summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/0a/a.h183
-rw-r--r--utils/0a/a.y588
-rw-r--r--utils/0a/l.s703
-rw-r--r--utils/0a/lex.c697
-rw-r--r--utils/0a/mkfile30
-rw-r--r--utils/0c/cgen.c1148
-rw-r--r--utils/0c/enam.c118
-rw-r--r--utils/0c/gc.h332
-rw-r--r--utils/0c/list.c244
-rw-r--r--utils/0c/mkenam15
-rw-r--r--utils/0c/mkfile30
-rw-r--r--utils/0c/mul.c608
-rw-r--r--utils/0c/peep.c694
-rw-r--r--utils/0c/reg.c1151
-rw-r--r--utils/0c/sgen.c569
-rw-r--r--utils/0c/swt.c727
-rw-r--r--utils/0c/txt.c1483
-rw-r--r--utils/0c/v.out.h201
-rw-r--r--utils/0l/Nt.c77
-rw-r--r--utils/0l/Plan9.c57
-rw-r--r--utils/0l/Posix.c80
-rw-r--r--utils/0l/asm.c1433
-rw-r--r--utils/0l/enam.c122
-rw-r--r--utils/0l/l.h329
-rw-r--r--utils/0l/list.c277
-rw-r--r--utils/0l/mkfile30
-rw-r--r--utils/0l/noop.c420
-rw-r--r--utils/0l/obj.c1384
-rw-r--r--utils/0l/optab.c221
-rw-r--r--utils/0l/pass.c498
-rw-r--r--utils/0l/sched.c709
-rw-r--r--utils/0l/span.c628
-rw-r--r--utils/1a/a.h198
-rw-r--r--utils/1a/a.y402
-rw-r--r--utils/1a/l.s479
-rw-r--r--utils/1a/lex.c925
-rw-r--r--utils/1a/mkfile30
-rw-r--r--utils/1c/cgen.c1396
-rw-r--r--utils/1c/enam.c425
-rw-r--r--utils/1c/gc.h339
-rw-r--r--utils/1c/list.c319
-rw-r--r--utils/1c/mkfile29
-rw-r--r--utils/1c/mul.c174
-rw-r--r--utils/1c/peep.c1060
-rw-r--r--utils/1c/reg.c1221
-rw-r--r--utils/1c/sgen.c694
-rw-r--r--utils/1c/swt.c964
-rw-r--r--utils/1c/txt.c903
-rw-r--r--utils/1l/Nt.c77
-rw-r--r--utils/1l/Plan9.c57
-rw-r--r--utils/1l/Posix.c80
-rw-r--r--utils/1l/asm.c1534
-rw-r--r--utils/1l/l.h268
-rw-r--r--utils/1l/list.c334
-rw-r--r--utils/1l/mkfile32
-rw-r--r--utils/1l/obj.c1380
-rw-r--r--utils/1l/optab.c444
-rw-r--r--utils/1l/pass.c673
-rw-r--r--utils/1l/span.c515
-rw-r--r--utils/2a/a.h200
-rw-r--r--utils/2a/a.y540
-rw-r--r--utils/2a/l.s479
-rw-r--r--utils/2a/lex.c935
-rw-r--r--utils/2a/mkfile30
-rw-r--r--utils/2c/2.out.h523
-rw-r--r--utils/2c/Update7
-rw-r--r--utils/2c/cgen.c1404
-rw-r--r--utils/2c/enam.c425
-rw-r--r--utils/2c/gc.h357
-rw-r--r--utils/2c/list.c384
-rw-r--r--utils/2c/mkfile30
-rw-r--r--utils/2c/mul.c174
-rw-r--r--utils/2c/peep.c1076
-rw-r--r--utils/2c/reg.c1275
-rw-r--r--utils/2c/sgen.c819
-rw-r--r--utils/2c/swt.c1046
-rw-r--r--utils/2c/txt.c940
-rw-r--r--utils/2l/Nt.c77
-rw-r--r--utils/2l/Plan9.c57
-rw-r--r--utils/2l/Posix.c80
-rw-r--r--utils/2l/asm.c1569
-rw-r--r--utils/2l/l.h263
-rw-r--r--utils/2l/list.c395
-rw-r--r--utils/2l/mkfile26
-rw-r--r--utils/2l/obj.c1402
-rw-r--r--utils/2l/optab.c444
-rw-r--r--utils/2l/pass.c538
-rw-r--r--utils/2l/span.c551
-rw-r--r--utils/5a/a.h182
-rw-r--r--utils/5a/a.y673
-rw-r--r--utils/5a/lex.c689
-rw-r--r--utils/5a/mkfile30
-rw-r--r--utils/5c/5.out.h197
-rw-r--r--utils/5c/cgen.c1156
-rw-r--r--utils/5c/enam.c98
-rw-r--r--utils/5c/gc.h349
-rw-r--r--utils/5c/list.c304
-rw-r--r--utils/5c/mkenam15
-rw-r--r--utils/5c/mkfile30
-rw-r--r--utils/5c/mul.c609
-rw-r--r--utils/5c/peep.c1440
-rw-r--r--utils/5c/reg.c1157
-rw-r--r--utils/5c/sgen.c613
-rw-r--r--utils/5c/swt.c757
-rw-r--r--utils/5c/txt.c1249
-rw-r--r--utils/5coff/5coff.c316
-rw-r--r--utils/5coff/NOTICE27
-rw-r--r--utils/5coff/auxi.c251
-rw-r--r--utils/5coff/auxi.h46
-rw-r--r--utils/5coff/coff.c642
-rw-r--r--utils/5coff/mkfile23
-rw-r--r--utils/5coff/readcoff.c298
-rw-r--r--utils/5cv/5cv.c353
-rw-r--r--utils/5cv/mkfile18
-rw-r--r--utils/5l/Nt.c77
-rw-r--r--utils/5l/Plan9.c57
-rw-r--r--utils/5l/Posix.c80
-rw-r--r--utils/5l/asm.c1793
-rw-r--r--utils/5l/l.h444
-rw-r--r--utils/5l/list.c360
-rw-r--r--utils/5l/mkfile32
-rw-r--r--utils/5l/noop.c894
-rw-r--r--utils/5l/obj.c1557
-rw-r--r--utils/5l/optab.c253
-rw-r--r--utils/5l/pass.c942
-rw-r--r--utils/5l/span.c1262
-rw-r--r--utils/5l/thumb.c1637
-rw-r--r--utils/6c/6.out.h820
-rw-r--r--utils/8a/a.h194
-rw-r--r--utils/8a/a.y520
-rw-r--r--utils/8a/l.s704
-rw-r--r--utils/8a/lex.c895
-rw-r--r--utils/8a/mkfile30
-rw-r--r--utils/8c/8.out.h445
-rw-r--r--utils/8c/cgen.c1821
-rw-r--r--utils/8c/cgen64.c2711
-rw-r--r--utils/8c/div.c206
-rw-r--r--utils/8c/enam.c337
-rw-r--r--utils/8c/gc.h374
-rw-r--r--utils/8c/list.c282
-rw-r--r--utils/8c/machcap.c86
-rw-r--r--utils/8c/mkenam15
-rw-r--r--utils/8c/mkfile35
-rw-r--r--utils/8c/mul.c428
-rw-r--r--utils/8c/peep.c757
-rw-r--r--utils/8c/reg.c1255
-rw-r--r--utils/8c/sgen.c842
-rw-r--r--utils/8c/swt.c647
-rw-r--r--utils/8c/txt.c1410
-rw-r--r--utils/8l/Nt.c77
-rw-r--r--utils/8l/Plan9.c57
-rw-r--r--utils/8l/Posix.c80
-rw-r--r--utils/8l/asm.c502
-rw-r--r--utils/8l/l.h349
-rw-r--r--utils/8l/list.c292
-rw-r--r--utils/8l/mkfile29
-rw-r--r--utils/8l/obj.c1492
-rw-r--r--utils/8l/optab.c654
-rw-r--r--utils/8l/pass.c763
-rw-r--r--utils/8l/span.c1387
-rw-r--r--utils/NOTICE34
-rw-r--r--utils/acid/386146
-rw-r--r--utils/acid/B.sh7
-rw-r--r--utils/acid/acid.h317
-rw-r--r--utils/acid/arm1
-rw-r--r--utils/acid/builtin.c1285
-rw-r--r--utils/acid/dbg.y402
-rw-r--r--utils/acid/dot.c152
-rw-r--r--utils/acid/exec.c490
-rw-r--r--utils/acid/expr.c1032
-rw-r--r--utils/acid/lex.c636
-rw-r--r--utils/acid/list.c276
-rw-r--r--utils/acid/main.c616
-rw-r--r--utils/acid/mips217
-rw-r--r--utils/acid/mkfile30
-rw-r--r--utils/acid/os-Nt.c198
-rw-r--r--utils/acid/os-Plan9.c157
-rw-r--r--utils/acid/os-Posix.c183
-rw-r--r--utils/acid/port547
-rw-r--r--utils/acid/print.c444
-rw-r--r--utils/acid/proc.c274
-rw-r--r--utils/acid/rdebug.c274
-rw-r--r--utils/acid/sparc218
-rw-r--r--utils/acid/util.c295
-rw-r--r--utils/awk/FIXES703
-rw-r--r--utils/awk/NOTICE7
-rw-r--r--utils/awk/README83
-rw-r--r--utils/awk/awk.1529
-rw-r--r--utils/awk/awk.h231
-rw-r--r--utils/awk/awkgram.y486
-rw-r--r--utils/awk/b.c855
-rw-r--r--utils/awk/buildwin.bat12
-rw-r--r--utils/awk/lex.c571
-rw-r--r--utils/awk/lib.c682
-rw-r--r--utils/awk/mac.code65
-rw-r--r--utils/awk/main.c197
-rw-r--r--utils/awk/makefile81
-rw-r--r--utils/awk/maketab.c168
-rw-r--r--utils/awk/missing95.c12
-rw-r--r--utils/awk/mkfile29
-rw-r--r--utils/awk/parse.c276
-rw-r--r--utils/awk/proctab.c205
-rw-r--r--utils/awk/proto.h194
-rw-r--r--utils/awk/run.c1891
-rw-r--r--utils/awk/tran.c437
-rw-r--r--utils/awk/ytab.c1623
-rw-r--r--utils/awk/ytab.h100
-rw-r--r--utils/awk/ytabc.bak1623
-rw-r--r--utils/awk/ytabh.bak100
-rw-r--r--utils/c2l/Nt.c131
-rw-r--r--utils/c2l/Plan9.c108
-rw-r--r--utils/c2l/Posix.c91
-rw-r--r--utils/c2l/acid.c13
-rw-r--r--utils/c2l/bits.c89
-rw-r--r--utils/c2l/c2l.c5118
-rw-r--r--utils/c2l/cc.h849
-rw-r--r--utils/c2l/cc.y1239
-rw-r--r--utils/c2l/com.c918
-rw-r--r--utils/c2l/com64.c52
-rw-r--r--utils/c2l/dcl.c1387
-rw-r--r--utils/c2l/dpchk.c392
-rw-r--r--utils/c2l/lex.c1675
-rw-r--r--utils/c2l/lexbody650
-rw-r--r--utils/c2l/mac.c3
-rw-r--r--utils/c2l/macbody773
-rw-r--r--utils/c2l/mkfile38
-rw-r--r--utils/c2l/mpatof.c337
-rw-r--r--utils/c2l/out.c825
-rw-r--r--utils/c2l/scon.c250
-rw-r--r--utils/c2l/sub.c1694
-rw-r--r--utils/cat/cat.c35
-rw-r--r--utils/cat/mkfile10
-rw-r--r--utils/cc/Nt.c135
-rw-r--r--utils/cc/Plan9.c114
-rw-r--r--utils/cc/Posix.c98
-rw-r--r--utils/cc/acid.c301
-rw-r--r--utils/cc/bits.c89
-rw-r--r--utils/cc/cc.h768
-rw-r--r--utils/cc/cc.y1167
-rw-r--r--utils/cc/com.c1164
-rw-r--r--utils/cc/com64.c611
-rw-r--r--utils/cc/dcl.c1630
-rw-r--r--utils/cc/dpchk.c463
-rw-r--r--utils/cc/funct.c400
-rw-r--r--utils/cc/lex.c1518
-rw-r--r--utils/cc/lexbody688
-rw-r--r--utils/cc/mac.c3
-rw-r--r--utils/cc/macbody822
-rw-r--r--utils/cc/machcap.c9
-rw-r--r--utils/cc/mkfile35
-rw-r--r--utils/cc/mpatof.c271
-rw-r--r--utils/cc/pickle.c268
-rw-r--r--utils/cc/scon.c606
-rw-r--r--utils/cc/sub.c2012
-rw-r--r--utils/cp/cp.c118
-rw-r--r--utils/cp/mkfile22
-rw-r--r--utils/data2c/data2c.c33
-rw-r--r--utils/data2c/mkfile13
-rw-r--r--utils/data2s/data2s.c32
-rw-r--r--utils/data2s/mkfile13
-rw-r--r--utils/echo/echo.c33
-rw-r--r--utils/echo/mkfile13
-rw-r--r--utils/format/Nt.c47
-rw-r--r--utils/format/Plan9.c19
-rw-r--r--utils/format/format.c574
-rw-r--r--utils/format/mkfile14
-rw-r--r--utils/ftl/ftl.c867
-rw-r--r--utils/ftl/mkfile13
-rw-r--r--utils/iar/Nt.c10
-rw-r--r--utils/iar/Plan9.c7
-rw-r--r--utils/iar/Posix.c10
-rw-r--r--utils/iar/ar.c1197
-rw-r--r--utils/iar/mkfile18
-rw-r--r--utils/idea/NOTICE27
-rw-r--r--utils/idea/idea.c254
-rw-r--r--utils/idea/mkfile13
-rw-r--r--utils/include/a.out.h45
-rw-r--r--utils/include/ar.h17
-rw-r--r--utils/include/mach.h295
-rw-r--r--utils/include/regexp.h66
-rw-r--r--utils/ka/a.h181
-rw-r--r--utils/ka/a.y734
-rw-r--r--utils/ka/l.s696
-rw-r--r--utils/ka/lex.c722
-rw-r--r--utils/ka/mkfile30
-rw-r--r--utils/ka/note274
-rw-r--r--utils/kc/cgen.c1087
-rw-r--r--utils/kc/enam.c175
-rw-r--r--utils/kc/gc.h338
-rw-r--r--utils/kc/k.out.h263
-rw-r--r--utils/kc/list.c229
-rw-r--r--utils/kc/mkenam17
-rw-r--r--utils/kc/mkfile32
-rw-r--r--utils/kc/mul.c609
-rw-r--r--utils/kc/peep.c691
-rw-r--r--utils/kc/reg.c1121
-rw-r--r--utils/kc/sgen.c590
-rw-r--r--utils/kc/swt.c715
-rw-r--r--utils/kc/txt.c1269
-rw-r--r--utils/kl/Nt.c88
-rw-r--r--utils/kl/Plan9.c57
-rw-r--r--utils/kl/Posix.c80
-rw-r--r--utils/kl/asm.c1237
-rw-r--r--utils/kl/foo.c15
-rw-r--r--utils/kl/l.h322
-rw-r--r--utils/kl/list.c258
-rw-r--r--utils/kl/mkfile31
-rw-r--r--utils/kl/noop.c650
-rw-r--r--utils/kl/obj.c1277
-rw-r--r--utils/kl/optab.c199
-rw-r--r--utils/kl/pass.c551
-rw-r--r--utils/kl/sched.c672
-rw-r--r--utils/kl/span.c522
-rw-r--r--utils/kprof/kprof.c155
-rw-r--r--utils/kprof/mkfile13
-rw-r--r--utils/ksize/ksize.c49
-rw-r--r--utils/ksize/mkfile13
-rw-r--r--utils/kstrip/kstrip.c166
-rw-r--r--utils/kstrip/mkfile13
-rw-r--r--utils/lib/rcmain29
-rw-r--r--utils/lib/yaccpar241
-rw-r--r--utils/libmach/2.c85
-rw-r--r--utils/libmach/2db.c2084
-rw-r--r--utils/libmach/2obj.c137
-rw-r--r--utils/libmach/4.c139
-rw-r--r--utils/libmach/4db.c57
-rw-r--r--utils/libmach/5.c64
-rw-r--r--utils/libmach/5db.c1063
-rw-r--r--utils/libmach/5obj.c133
-rw-r--r--utils/libmach/6.c117
-rw-r--r--utils/libmach/6obj.c142
-rw-r--r--utils/libmach/8.c78
-rw-r--r--utils/libmach/8db.c1850
-rw-r--r--utils/libmach/8obj.c133
-rw-r--r--utils/libmach/NOTICE31
-rw-r--r--utils/libmach/a.out.h45
-rw-r--r--utils/libmach/access.c215
-rw-r--r--utils/libmach/ar.h18
-rw-r--r--utils/libmach/bootexec.h172
-rw-r--r--utils/libmach/elf.h101
-rw-r--r--utils/libmach/executable.c570
-rw-r--r--utils/libmach/k.c117
-rw-r--r--utils/libmach/kdb.c1055
-rw-r--r--utils/libmach/kobj.c132
-rw-r--r--utils/libmach/mach.h294
-rw-r--r--utils/libmach/machdata.c450
-rw-r--r--utils/libmach/map.c203
-rw-r--r--utils/libmach/mkfile46
-rw-r--r--utils/libmach/obj.c326
-rw-r--r--utils/libmach/obj.h24
-rw-r--r--utils/libmach/q.c122
-rw-r--r--utils/libmach/qdb.c1270
-rw-r--r--utils/libmach/qobj.c134
-rw-r--r--utils/libmach/setmach.c143
-rw-r--r--utils/libmach/swap.c79
-rw-r--r--utils/libmach/sym.c1405
-rw-r--r--utils/libmach/t.c122
-rw-r--r--utils/libmach/tdb.c839
-rw-r--r--utils/libmach/tobj.c133
-rw-r--r--utils/libmach/ureg2.h28
-rw-r--r--utils/libmach/ureg4.h46
-rw-r--r--utils/libmach/ureg5.h21
-rw-r--r--utils/libmach/ureg6.h30
-rw-r--r--utils/libmach/ureg8.h25
-rw-r--r--utils/libmach/uregk.h45
-rw-r--r--utils/libmach/uregq.h43
-rw-r--r--utils/libmach/uregt.h21
-rw-r--r--utils/libmach/uregv.h44
-rw-r--r--utils/libmach/v.c116
-rw-r--r--utils/libmach/vcodas.c553
-rw-r--r--utils/libmach/vdb.c1094
-rw-r--r--utils/libmach/vobj.c129
-rw-r--r--utils/libregexp/NOTICE28
-rw-r--r--utils/libregexp/mkfile22
-rw-r--r--utils/libregexp/regaux.c98
-rw-r--r--utils/libregexp/regcomp.c557
-rw-r--r--utils/libregexp/regcomp.h70
-rw-r--r--utils/libregexp/regerror.c14
-rw-r--r--utils/libregexp/regexec.c219
-rw-r--r--utils/libregexp/regsub.c55
-rw-r--r--utils/libregexp/rregexec.c213
-rw-r--r--utils/libregexp/rregsub.c55
-rw-r--r--utils/libregexp/test.c46
-rw-r--r--utils/libregexp/test2.c20
-rw-r--r--utils/md5sum/md5sum.c61
-rw-r--r--utils/md5sum/mkfile19
-rw-r--r--utils/mk/Nt.c442
-rw-r--r--utils/mk/Plan9.c363
-rw-r--r--utils/mk/Posix.c331
-rw-r--r--utils/mk/README26
-rw-r--r--utils/mk/arc.c52
-rw-r--r--utils/mk/archive.c169
-rw-r--r--utils/mk/bufblock.c88
-rw-r--r--utils/mk/env.c149
-rw-r--r--utils/mk/file.c90
-rw-r--r--utils/mk/fns.h84
-rw-r--r--utils/mk/graph.c279
-rw-r--r--utils/mk/job.c33
-rw-r--r--utils/mk/lex.c147
-rw-r--r--utils/mk/main.c291
-rw-r--r--utils/mk/match.c49
-rw-r--r--utils/mk/mk.c226
-rw-r--r--utils/mk/mk.h171
-rw-r--r--utils/mk/mkfile40
-rw-r--r--utils/mk/mkfile-Nt12
-rw-r--r--utils/mk/mkfile-Plan93
-rw-r--r--utils/mk/mkfile-Posix7
-rw-r--r--utils/mk/parse.c309
-rw-r--r--utils/mk/rc.c175
-rw-r--r--utils/mk/recipe.c117
-rw-r--r--utils/mk/rule.c107
-rw-r--r--utils/mk/run.c297
-rw-r--r--utils/mk/sh.c189
-rw-r--r--utils/mk/shprint.c90
-rw-r--r--utils/mk/symtab.c97
-rw-r--r--utils/mk/var.c41
-rw-r--r--utils/mk/varsub.c256
-rw-r--r--utils/mk/word.c180
-rw-r--r--utils/mkdir/mkdir.c18
-rw-r--r--utils/mkdir/mkfile13
-rw-r--r--utils/mkext/mkext.c313
-rw-r--r--utils/mkext/mkfile13
-rw-r--r--utils/mkfile112
-rw-r--r--utils/mkppcimage/mkfile18
-rw-r--r--utils/mkppcimage/mkppcimage.c261
-rw-r--r--utils/ms2/mkfile16
-rw-r--r--utils/ms2/ms2.c186
-rw-r--r--utils/mv/mkfile13
-rw-r--r--utils/mv/mv.c210
-rw-r--r--utils/na/mkfile18
-rwxr-xr-xutils/na/na.h13
-rw-r--r--utils/na/na.man33
-rwxr-xr-xutils/na/na.y1231
-rw-r--r--utils/ndate/mkfile13
-rw-r--r--utils/ndate/ndate.c11
-rw-r--r--utils/nm/mkfile14
-rw-r--r--utils/nm/nm.c287
-rw-r--r--utils/ntsrv/domk2
-rwxr-xr-xutils/ntsrv/mkfile25
-rw-r--r--utils/ntsrv/ntsrv.c573
-rw-r--r--utils/qa/Ins203
-rw-r--r--utils/qa/a.h199
-rw-r--r--utils/qa/a.y974
-rw-r--r--utils/qa/branch37
-rw-r--r--utils/qa/lex.c856
-rw-r--r--utils/qa/mkfile29
-rw-r--r--utils/qc/cgen.c1091
-rw-r--r--utils/qc/enam.c327
-rw-r--r--utils/qc/gc.h343
-rw-r--r--utils/qc/list.c229
-rw-r--r--utils/qc/mkenam18
-rw-r--r--utils/qc/mkfile29
-rw-r--r--utils/qc/mul.c609
-rw-r--r--utils/qc/peep.c891
-rw-r--r--utils/qc/q.out.h426
-rw-r--r--utils/qc/reg.c1122
-rw-r--r--utils/qc/sgen.c640
-rw-r--r--utils/qc/swt.c722
-rw-r--r--utils/qc/txt.c1282
-rw-r--r--utils/ql/Ins203
-rw-r--r--utils/ql/Notes21
-rw-r--r--utils/ql/Nt.c88
-rw-r--r--utils/ql/Plan9.c57
-rw-r--r--utils/ql/Posix.c80
-rw-r--r--utils/ql/asm.c687
-rw-r--r--utils/ql/asmout.c1293
-rw-r--r--utils/ql/cnam.c37
-rw-r--r--utils/ql/l.h335
-rw-r--r--utils/ql/list.c311
-rw-r--r--utils/ql/mkcname17
-rw-r--r--utils/ql/mkfile33
-rw-r--r--utils/ql/noop.c513
-rw-r--r--utils/ql/obj.c1465
-rw-r--r--utils/ql/optab.c289
-rw-r--r--utils/ql/pass.c667
-rw-r--r--utils/ql/sched.c801
-rw-r--r--utils/ql/span.c928
-rw-r--r--utils/rcsh/Nt.c549
-rw-r--r--utils/rcsh/code.c486
-rw-r--r--utils/rcsh/exec.c802
-rw-r--r--utils/rcsh/glob.c286
-rw-r--r--utils/rcsh/here.c145
-rw-r--r--utils/rcsh/io.c238
-rw-r--r--utils/rcsh/lex.c398
-rw-r--r--utils/rcsh/main.c228
-rw-r--r--utils/rcsh/mkfile53
-rw-r--r--utils/rcsh/pcmd.c110
-rw-r--r--utils/rcsh/pfnc.c70
-rw-r--r--utils/rcsh/rc.h295
-rw-r--r--utils/rcsh/rcmain29
-rw-r--r--utils/rcsh/rcpath13
-rw-r--r--utils/rcsh/simple.c528
-rw-r--r--utils/rcsh/syn.y90
-rw-r--r--utils/rcsh/trap.c42
-rw-r--r--utils/rcsh/tree.c140
-rw-r--r--utils/rcsh/var.c240
-rw-r--r--utils/rcsh/word.c173
-rw-r--r--utils/rm/mkfile24
-rw-r--r--utils/rm/rm-Nt.c151
-rw-r--r--utils/sed/mkfile16
-rw-r--r--utils/sed/sed.c1428
-rw-r--r--utils/sqz/NOTICE27
-rw-r--r--utils/sqz/mkfile19
-rw-r--r--utils/sqz/squeeze.h34
-rw-r--r--utils/sqz/sqz.c528
-rw-r--r--utils/sqz/zqs.c243
-rw-r--r--utils/srclist/Nt.c8
-rw-r--r--utils/srclist/Plan9.c7
-rw-r--r--utils/srclist/Posix.c10
-rw-r--r--utils/srclist/mkfile19
-rw-r--r--utils/srclist/srclist.c144
-rw-r--r--utils/tc/5.out.h192
-rw-r--r--utils/tc/cgen.c1234
-rw-r--r--utils/tc/enam.c98
-rw-r--r--utils/tc/gc.h349
-rw-r--r--utils/tc/list.c276
-rw-r--r--utils/tc/mkenam15
-rw-r--r--utils/tc/mkfile28
-rw-r--r--utils/tc/mul.c609
-rw-r--r--utils/tc/peep.c759
-rw-r--r--utils/tc/reg.c1161
-rw-r--r--utils/tc/sgen.c667
-rw-r--r--utils/tc/swt.c717
-rw-r--r--utils/tc/txt.c1199
-rw-r--r--utils/test/mkfile21
-rw-r--r--utils/test/test-Nt.c278
-rw-r--r--utils/tr/mkfile13
-rw-r--r--utils/tr/tr.c355
-rw-r--r--utils/va/a.h181
-rw-r--r--utils/va/a.y588
-rw-r--r--utils/va/l.s703
-rw-r--r--utils/va/lex.c697
-rw-r--r--utils/va/mkfile30
-rw-r--r--utils/va/note51
-rw-r--r--utils/vc/cgen.c1184
-rw-r--r--utils/vc/enam.c118
-rw-r--r--utils/vc/gc.h331
-rw-r--r--utils/vc/list.c244
-rw-r--r--utils/vc/mkenam15
-rw-r--r--utils/vc/mkfile32
-rw-r--r--utils/vc/mul.c608
-rw-r--r--utils/vc/peep.c694
-rw-r--r--utils/vc/reg.c1148
-rw-r--r--utils/vc/sgen.c580
-rw-r--r--utils/vc/swt.c717
-rw-r--r--utils/vc/txt.c1440
-rw-r--r--utils/vc/v.out.h201
-rw-r--r--utils/vl/Nt.c77
-rw-r--r--utils/vl/Plan9.c57
-rw-r--r--utils/vl/Posix.c80
-rw-r--r--utils/vl/asm.c1403
-rw-r--r--utils/vl/compat.c50
-rw-r--r--utils/vl/l.h327
-rw-r--r--utils/vl/list.c277
-rw-r--r--utils/vl/mkfile31
-rw-r--r--utils/vl/noop.c416
-rw-r--r--utils/vl/obj.c1332
-rw-r--r--utils/vl/optab.c232
-rw-r--r--utils/vl/pass.c505
-rw-r--r--utils/vl/sched.c695
-rw-r--r--utils/vl/span.c662
-rw-r--r--utils/yacc/mkfile20
-rw-r--r--utils/yacc/yacc.c2933
-rw-r--r--utils/yacc/yaccpar241
564 files changed, 236010 insertions, 0 deletions
diff --git a/utils/0a/a.h b/utils/0a/a.h
new file mode 100644
index 00000000..664ac9b0
--- /dev/null
+++ b/utils/0a/a.h
@@ -0,0 +1,183 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../vc/v.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+
+#define MAXALIGN 7
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ long offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int nosched;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+int assemble(char*);
+void* alloc(long);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void maclin(void);
+void macprag(void);
+void macif(int);
+void macend(void);
+void outhist(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+
+/*
+ * Posix.c/Inferno.c/Nt.c
+ */
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/0a/a.y b/utils/0a/a.y
new file mode 100644
index 00000000..4f72a892
--- /dev/null
+++ b/utils/0a/a.y
@@ -0,0 +1,588 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
+%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token <lval> LCONST LSP LSB LFP LPC LHI LLO LMREG
+%token <lval> LTYPEX LREG LFREG LFCREG LR LM LF
+%token <lval> LFCR LSCHED
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset sreg
+%type <gen> gen vgen lgen vlgen rel reg freg mreg fcreg
+%type <gen> imm ximm ireg name oreg imr nireg fgen
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LSCHED ';'
+ {
+ nosched = $1;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * Immed-type
+ */
+ LTYPE1 imr ',' sreg ',' reg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPE1 imr ',' reg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * NOR
+ */
+| LTYPE2 imr ',' sreg ',' imr
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPE2 imr ',' imr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * LOAD/STORE, but not MOVW
+ */
+| LTYPE3 lgen ',' gen
+ {
+ if(!isreg(&$2) && !isreg(&$4))
+ print("one side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * SPECIAL
+ */
+| LTYPE4 comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * MOVW
+ */
+| LTYPE5 vlgen ',' vgen
+ {
+ if(!isreg(&$2) && !isreg(&$4))
+ print("one side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * MUL/DIV
+ */
+| LTYPE6 reg ',' sreg comma
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTYPE6 reg ',' sreg ',' reg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * JMP/JAL
+ */
+| LTYPE7 comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE7 comma nireg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 comma nireg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 sreg ',' nireg
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+/*
+ * BEQ/BNE
+ */
+| LTYPE9 gen ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPE9 gen ',' sreg ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * B-other
+ */
+| LTYPEA gen ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTYPEB name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEB name ',' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LTYPEC name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * floating-type
+ */
+| LTYPED freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEE freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEE freg ',' LFREG ',' freg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPEF freg ',' LFREG comma
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+/*
+ * coprocessor branch
+ */
+| LTYPEG comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * word
+ */
+| LTYPEH comma ximm
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * NOP
+ */
+| LTYPEI comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LTYPEI ',' vgen
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPEI vgen comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * BREAK -- overloaded with CACHE opcode
+ */
+| LTYPEJ comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LTYPEJ vgen ',' vgen
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+
+comma:
+| ','
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+vlgen:
+ lgen
+| fgen
+| mreg
+| fcreg
+| LHI
+ {
+ $$ = nullgen;
+ $$.type = D_HI;
+ }
+| LLO
+ {
+ $$ = nullgen;
+ $$.type = D_LO;
+ }
+
+vgen:
+ gen
+| fgen
+| mreg
+| fcreg
+| LHI
+ {
+ $$ = nullgen;
+ $$.type = D_HI;
+ }
+| LLO
+ {
+ $$ = nullgen;
+ $$.type = D_LO;
+ }
+
+lgen:
+ gen
+| ximm
+
+fgen:
+ freg
+
+mreg:
+ LMREG
+ {
+ $$ = nullgen;
+ $$.type = D_MREG;
+ $$.reg = $1;
+ }
+| LM '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_MREG;
+ $$.reg = $3;
+ }
+
+fcreg:
+ LFCREG
+ {
+ $$ = nullgen;
+ $$.type = D_FCREG;
+ $$.reg = $1;
+ }
+| LFCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCREG;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+ximm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' oreg
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' '*' '$' oreg
+ {
+ $$ = $4;
+ $$.type = D_OCONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+nireg:
+ ireg
+| con ireg
+ {
+ if($1 != 0)
+ yyerror("offset must be zero");
+ $$ = $2;
+ }
+| name
+ {
+ $$ = $1;
+ if($1.name != D_EXTERN && $1.name != D_STATIC) {
+ }
+ }
+
+ireg:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+
+gen:
+ reg
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.offset = $1;
+ }
+| oreg
+
+oreg:
+ name
+| name '(' sreg ')'
+ {
+ $$ = $1;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ }
+| '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+imr:
+ reg
+| imm
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+reg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+sreg:
+ LREG
+| LR '(' expr ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/0a/l.s b/utils/0a/l.s
new file mode 100644
index 00000000..2f8e6341
--- /dev/null
+++ b/utils/0a/l.s
@@ -0,0 +1,703 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+
+#define MAXMACH 4 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define MS2HZ 50 /* millisec per clock tick */
+#define TK2SEC(t) ((t)/20) /* ticks to seconds */
+#define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */
+
+/*
+ * CP0 registers
+ */
+
+#define INDEX 0
+#define RANDOM 1
+#define TLBPHYS 2
+#define CONTEXT 4
+#define BADVADDR 8
+#define TLBVIRT 10
+#define STATUS 12
+#define CAUSE 13
+#define EPC 14
+#define PRID 15
+
+/*
+ * M(STATUS) bits
+ */
+#define IEC 0x00000001
+#define KUC 0x00000002
+#define IEP 0x00000004
+#define KUP 0x00000008
+#define INTMASK 0x0000ff00
+#define SW0 0x00000100
+#define SW1 0x00000200
+#define INTR0 0x00000400
+#define INTR1 0x00000800
+#define INTR2 0x00001000
+#define INTR3 0x00002000
+#define INTR4 0x00004000
+#define INTR5 0x00008000
+#define ISC 0x00010000
+#define SWC 0x00020000
+#define CU1 0x20000000
+
+/*
+ * Traps
+ */
+
+#define UTLBMISS (KSEG0+0x00)
+#define EXCEPTION (KSEG0+0x80)
+
+/*
+ * Magic registers
+ */
+
+#define MACH 25 /* R25 is m-> */
+#define USER 24 /* R24 is u-> */
+#define MPID 0xBF000000 /* long; low 3 bits identify mp bus slot */
+#define WBFLUSH 0xBC000000 /* D-CACHE data; used for write buffer flush */
+
+/*
+ * Fundamental addresses
+ */
+
+#define MACHADDR 0x80014000
+#define USERADDR 0xC0000000
+#define UREGADDR (USERADDR+BY2PG-4-0xA0)
+/*
+ * MMU
+ */
+
+#define KUSEG 0x00000000
+#define KSEG0 0x80000000
+#define KSEG1 0xA0000000
+#define KSEG2 0xC0000000
+#define KSEGM 0xE0000000 /* mask to check which seg */
+
+#define PTEGLOBL (1<<8)
+#define PTEVALID (1<<9)
+#define PTEWRITE (1<<10)
+#define PTEPID(n) ((n)<<6)
+
+#define NTLBPID 64 /* number of pids */
+#define NTLB 64 /* number of entries */
+#define TLBROFF 8 /* offset of first randomly indexed entry */
+
+/*
+ * Address spaces
+ */
+
+#define UZERO KUSEG /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define USTKTOP KZERO /* byte just beyond user stack */
+#define TSTKTOP (USERADDR+100*BY2PG) /* top of temporary stack */
+#define KZERO KSEG0 /* base of kernel address space */
+#define KTZERO (KSEG0+0x20000) /* first address in kernel text */
+#define USTACKSIZE (4*1024*1024) /* size of user stack */
+/*
+ * Exception codes
+ */
+#define CINT 0 /* external interrupt */
+#define CTLBM 1 /* TLB modification */
+#define CTLBL 2 /* TLB miss (load or fetch) */
+#define CTLBS 3 /* TLB miss (store) */
+#define CADREL 4 /* address error (load or fetch) */
+#define CADRES 5 /* address error (store) */
+#define CBUSI 6 /* bus error (fetch) */
+#define CBUSD 7 /* bus error (data load or store) */
+#define CSYS 8 /* system call */
+#define CBRK 9 /* breakpoint */
+#define CRES 10 /* reserved instruction */
+#define CCPU 11 /* coprocessor unusable */
+#define COVF 12 /* arithmetic overflow */
+#define CUNK13 13 /* undefined 13 */
+#define CUNK14 14 /* undefined 14 */
+#define CUNK15 15 /* undefined 15 */
+
+#define NSEG 5
+
+#define SP R29
+
+#define PROM (KSEG1+0x1FC00000)
+#define NOOP NOR R0,R0
+#define WAIT NOOP; NOOP
+
+/*
+ * Boot first processor
+ * - why is the processor number loaded from R0 ?????
+ */
+TEXT start(SB), $-4
+
+ MOVW $setR30(SB), R30
+ MOVW $(CU1|INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1
+ MOVW R1, M(STATUS)
+ WAIT
+
+ MOVW $(0x1C<<7), R1
+ MOVW R1, FCR31 /* permit only inexact and underflow */
+ NOOP
+ MOVD $0.5, F26
+ SUBD F26, F26, F24
+ ADDD F26, F26, F28
+ ADDD F28, F28, F30
+
+ MOVD F24, F0
+ MOVD F24, F2
+ MOVD F24, F4
+ MOVD F24, F6
+ MOVD F24, F8
+ MOVD F24, F10
+ MOVD F24, F12
+ MOVD F24, F14
+ MOVD F24, F16
+ MOVD F24, F18
+ MOVD F24, F20
+ MOVD F24, F22
+
+ MOVW $MACHADDR, R(MACH)
+ ADDU $(BY2PG-4), R(MACH), SP
+ MOVW $0, R(USER)
+ MOVW R0, 0(R(MACH))
+
+ MOVW $edata(SB), R1
+ MOVW $end(SB), R2
+
+clrbss:
+ MOVB $0, (R1)
+ ADDU $1, R1
+ BNE R1, R2, clrbss
+
+ MOVW R4, _argc(SB)
+ MOVW R5, _argv(SB)
+ MOVW R6, _env(SB)
+ JAL main(SB)
+ JMP (R0)
+
+/*
+ * Take first processor into user mode
+ * - argument is stack pointer to user
+ */
+
+TEXT touser(SB), $-4
+
+ MOVW M(STATUS), R1
+ OR $(KUP|IEP), R1
+ MOVW R1, M(STATUS)
+ NOOP
+ MOVW 0(FP), SP
+ MOVW $(UTZERO+32), R26 /* header appears in text */
+ RFE (R26)
+
+/*
+ * Bring subsequent processors on line
+ */
+TEXT newstart(SB), $0
+
+ MOVW $setR30(SB), R30
+ MOVW $(INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1
+ MOVW R1, M(STATUS)
+ NOOP
+ MOVW $MACHADDR, R(MACH)
+ MOVB (MPID+3), R1
+ AND $7, R1
+ SLL $PGSHIFT, R1, R2
+ ADDU R2, R(MACH)
+ ADDU $(BY2PG-4), R(MACH), SP
+ MOVW $0, R(USER)
+ MOVW R1, 0(R(MACH))
+ JAL online(SB)
+ JMP (R0)
+
+TEXT firmware(SB), $0
+
+ MOVW $(PROM+0x18), R1 /**/
+/* MOVW $(PROM+0x00), R1 /**/
+ JMP (R1)
+
+TEXT splhi(SB), $0
+
+ MOVW M(STATUS), R1
+ AND $~IEC, R1, R2
+ MOVW R2, M(STATUS)
+ NOOP
+ RET
+
+TEXT spllo(SB), $0
+
+ MOVW M(STATUS), R1
+ OR $IEC, R1, R2
+ MOVW R2, M(STATUS)
+ NOOP
+ RET
+
+TEXT splx(SB), $0
+
+ MOVW 0(FP), R1
+ MOVW M(STATUS), R2
+ AND $IEC, R1
+ AND $~IEC, R2
+ OR R2, R1
+ MOVW R1, M(STATUS)
+ NOOP
+ RET
+
+TEXT wbflush(SB), $-4
+
+ MOVW $WBFLUSH, R1
+ MOVW 0(R1), R1
+ RET
+
+TEXT setlabel(SB), $0
+
+ MOVW 0(FP), R2
+ MOVW $0, R1
+ MOVW R31, 0(R2)
+ MOVW R29, 4(R2)
+ RET
+
+TEXT gotolabel(SB), $0
+
+ MOVW 0(FP), R2
+ MOVW $1, R1
+ MOVW 0(R2), R31
+ MOVW 4(R2), R29
+ RET
+
+TEXT gotopc(SB), $8
+
+ MOVW 0(FP), R7 /* save arguments for later */
+ MOVW _argc(SB), R4
+ MOVW _argv(SB), R5
+ MOVW _env(SB), R6
+ MOVW R0, 4(SP)
+ MOVW $(64*1024), R1
+ MOVW R1, 8(SP)
+ JAL icflush(SB)
+ JMP (R7)
+
+TEXT puttlb(SB), $4
+
+ JAL splhi(SB)
+ MOVW 0(FP), R2
+ MOVW 4(FP), R3
+ MOVW R1, 4(SP)
+ MOVW R2, M(TLBVIRT)
+ MOVW R3, M(TLBPHYS)
+ NOOP
+ TLBP
+ NOOP
+ MOVW M(INDEX), R4
+ BGEZ R4, index
+ TLBWR
+ NOOP
+ JAL splx(SB)
+ RET
+index:
+ TLBWI
+ NOOP
+ JAL splx(SB)
+ RET
+
+TEXT puttlbx(SB), $0
+
+ MOVW 0(FP), R4
+ MOVW 4(FP), R2
+ MOVW 8(FP), R3
+ SLL $8, R4
+ MOVW R2, M(TLBVIRT)
+ MOVW R3, M(TLBPHYS)
+ MOVW R4, M(INDEX)
+ NOOP
+ TLBWI
+ NOOP
+ RET
+
+TEXT tlbp(SB), $0
+ TLBP
+ NOOP
+ MOVW M(INDEX), R1
+ RET
+
+TEXT tlbvirt(SB), $0
+ TLBP
+ NOOP
+ MOVW M(TLBVIRT), R1
+ RET
+
+
+TEXT gettlb(SB), $0
+
+ MOVW 0(FP), R3
+ MOVW 4(FP), R4
+ SLL $8, R3
+ MOVW R3, M(INDEX)
+ NOOP
+ TLBR
+ NOOP
+ MOVW M(TLBVIRT), R1
+ MOVW M(TLBPHYS), R2
+ NOOP
+ MOVW R1, 0(R4)
+ MOVW R2, 4(R4)
+ RET
+
+TEXT gettlbvirt(SB), $0
+
+ MOVW 0(FP), R3
+ SLL $8, R3
+ MOVW R3, M(INDEX)
+ NOOP
+ TLBR
+ NOOP
+ MOVW M(TLBVIRT), R1
+ NOOP
+ RET
+
+TEXT vector80(SB), $-4
+
+ MOVW $exception(SB), R26
+ JMP (R26)
+
+TEXT exception(SB), $-4
+
+ MOVW M(STATUS), R26
+ AND $KUP, R26
+ BEQ R26, waskernel
+
+wasuser:
+ MOVW SP, R26
+ /*
+ * set kernel sp: ureg - ureg* - pc
+ * done in 2 steps because R30 is not set
+ * and the loader will make a literal
+ */
+ MOVW $((UREGADDR-2*BY2WD) & 0xffff0000), SP
+ OR $((UREGADDR-2*BY2WD) & 0xffff), SP
+ MOVW R26, 0x10(SP) /* user SP */
+ MOVW R31, 0x28(SP)
+ MOVW R30, 0x2C(SP)
+ MOVW M(CAUSE), R26
+ MOVW R(MACH), 0x3C(SP)
+ MOVW R(USER), 0x40(SP)
+ AND $(0xF<<2), R26
+ SUB $(CSYS<<2), R26
+
+ JAL saveregs(SB)
+
+ MOVW $setR30(SB), R30
+ SUBU $(UREGADDR-2*BY2WD-USERADDR), SP, R(USER)
+ MOVW $MPID, R1
+ MOVB 3(R1), R1
+ MOVW $MACHADDR, R(MACH) /* locn of mach 0 */
+ AND $7, R1
+ SLL $PGSHIFT, R1
+ ADDU R1, R(MACH) /* add offset for mach # */
+
+ BNE R26, notsys
+
+ JAL syscall(SB)
+
+ MOVW 0x28(SP), R31
+ MOVW 0x08(SP), R26
+ MOVW 0x2C(SP), R30
+ MOVW R26, M(STATUS)
+ NOOP
+ MOVW 0x0C(SP), R26 /* old pc */
+ MOVW 0x10(SP), SP
+ RFE (R26)
+
+notsys:
+ JAL trap(SB)
+
+restore:
+ JAL restregs(SB)
+ MOVW 0x28(SP), R31
+ MOVW 0x2C(SP), R30
+ MOVW 0x3C(SP), R(MACH)
+ MOVW 0x40(SP), R(USER)
+ MOVW 0x10(SP), SP
+ RFE (R26)
+
+waskernel:
+ MOVW $1, R26 /* not sys call */
+ MOVW SP, -0x90(SP) /* drop this if possible */
+ SUB $0xA0, SP
+ MOVW R31, 0x28(SP)
+ JAL saveregs(SB)
+ JAL trap(SB)
+ JAL restregs(SB)
+ MOVW 0x28(SP), R31
+ ADD $0xA0, SP
+ RFE (R26)
+
+TEXT saveregs(SB), $-4
+ MOVW R1, 0x9C(SP)
+ MOVW R2, 0x98(SP)
+ ADDU $8, SP, R1
+ MOVW R1, 0x04(SP) /* arg to base of regs */
+ MOVW M(STATUS), R1
+ MOVW M(EPC), R2
+ MOVW R1, 0x08(SP)
+ MOVW R2, 0x0C(SP)
+
+ BEQ R26, return /* sys call, don't save */
+
+ MOVW M(CAUSE), R1
+ MOVW M(BADVADDR), R2
+ MOVW R1, 0x14(SP)
+ MOVW M(TLBVIRT), R1
+ MOVW R2, 0x18(SP)
+ MOVW R1, 0x1C(SP)
+ MOVW HI, R1
+ MOVW LO, R2
+ MOVW R1, 0x20(SP)
+ MOVW R2, 0x24(SP)
+ /* LINK,SB,SP missing */
+ MOVW R28, 0x30(SP)
+ /* R27, R26 not saved */
+ /* R25, R24 missing */
+ MOVW R23, 0x44(SP)
+ MOVW R22, 0x48(SP)
+ MOVW R21, 0x4C(SP)
+ MOVW R20, 0x50(SP)
+ MOVW R19, 0x54(SP)
+ MOVW R18, 0x58(SP)
+ MOVW R17, 0x5C(SP)
+ MOVW R16, 0x60(SP)
+ MOVW R15, 0x64(SP)
+ MOVW R14, 0x68(SP)
+ MOVW R13, 0x6C(SP)
+ MOVW R12, 0x70(SP)
+ MOVW R11, 0x74(SP)
+ MOVW R10, 0x78(SP)
+ MOVW R9, 0x7C(SP)
+ MOVW R8, 0x80(SP)
+ MOVW R7, 0x84(SP)
+ MOVW R6, 0x88(SP)
+ MOVW R5, 0x8C(SP)
+ MOVW R4, 0x90(SP)
+ MOVW R3, 0x94(SP)
+return:
+ RET
+
+TEXT restregs(SB), $-4
+ /* LINK,SB,SP missing */
+ MOVW 0x30(SP), R28
+ /* R27, R26 not saved */
+ /* R25, R24 missing */
+ MOVW 0x44(SP), R23
+ MOVW 0x48(SP), R22
+ MOVW 0x4C(SP), R21
+ MOVW 0x50(SP), R20
+ MOVW 0x54(SP), R19
+ MOVW 0x58(SP), R18
+ MOVW 0x5C(SP), R17
+ MOVW 0x60(SP), R16
+ MOVW 0x64(SP), R15
+ MOVW 0x68(SP), R14
+ MOVW 0x6C(SP), R13
+ MOVW 0x70(SP), R12
+ MOVW 0x74(SP), R11
+ MOVW 0x78(SP), R10
+ MOVW 0x7C(SP), R9
+ MOVW 0x80(SP), R8
+ MOVW 0x84(SP), R7
+ MOVW 0x88(SP), R6
+ MOVW 0x8C(SP), R5
+ MOVW 0x90(SP), R4
+ MOVW 0x94(SP), R3
+ MOVW 0x24(SP), R2
+ MOVW 0x20(SP), R1
+ MOVW R2, LO
+ MOVW R1, HI
+ MOVW 0x08(SP), R1
+ MOVW 0x98(SP), R2
+ MOVW R1, M(STATUS)
+ NOOP
+ MOVW 0x9C(SP), R1
+ MOVW 0x0C(SP), R26 /* old pc */
+ RET
+
+TEXT rfnote(SB), $0
+ MOVW 0(FP), R26 /* 1st arg is &uregpointer */
+ SUBU $(BY2WD), R26, SP /* pc hole */
+ BNE R26, restore
+
+
+TEXT clrfpintr(SB), $0
+ MOVW FCR31, R1
+ MOVW R1, R2
+ AND $~(0x3F<<12), R2
+ MOVW R2, FCR31
+ RET
+
+TEXT savefpregs(SB), $0
+ MOVW M(STATUS), R3
+ MOVW 0(FP), R1
+ MOVW FCR31, R2
+
+ MOVD F0, 0x00(R1)
+ MOVD F2, 0x08(R1)
+ MOVD F4, 0x10(R1)
+ MOVD F6, 0x18(R1)
+ MOVD F8, 0x20(R1)
+ MOVD F10, 0x28(R1)
+ MOVD F12, 0x30(R1)
+ MOVD F14, 0x38(R1)
+ MOVD F16, 0x40(R1)
+ MOVD F18, 0x48(R1)
+ MOVD F20, 0x50(R1)
+ MOVD F22, 0x58(R1)
+ MOVD F24, 0x60(R1)
+ MOVD F26, 0x68(R1)
+ MOVD F28, 0x70(R1)
+ MOVD F30, 0x78(R1)
+
+ MOVW R2, 0x80(R1)
+ AND $~CU1, R3
+ MOVW R3, M(STATUS)
+ RET
+
+TEXT restfpregs(SB), $0
+
+ MOVW M(STATUS), R3
+ MOVW 0(FP), R1
+ OR $CU1, R3
+ MOVW R3, M(STATUS)
+ MOVW 0x80(R1), R2
+
+ MOVD 0x00(R1), F0
+ MOVD 0x08(R1), F2
+ MOVD 0x10(R1), F4
+ MOVD 0x18(R1), F6
+ MOVD 0x20(R1), F8
+ MOVD 0x28(R1), F10
+ MOVD 0x30(R1), F12
+ MOVD 0x38(R1), F14
+ MOVD 0x40(R1), F16
+ MOVD 0x48(R1), F18
+ MOVD 0x50(R1), F20
+ MOVD 0x58(R1), F22
+ MOVD 0x60(R1), F24
+ MOVD 0x68(R1), F26
+ MOVD 0x70(R1), F28
+ MOVD 0x78(R1), F30
+
+ MOVW R2, FCR31
+ AND $~CU1, R3
+ MOVW R3, M(STATUS)
+ RET
+
+/*
+ * we avoid using R4, R5, R6, and R7 so gotopc can call us without saving them
+ */
+TEXT icflush(SB), $-4 /* icflush(physaddr, nbytes) */
+
+ MOVW M(STATUS), R10
+ MOVW 0(FP), R8
+ MOVW 4(FP), R9
+ MOVW $KSEG0, R3
+ OR R3, R8
+ MOVW $0, M(STATUS)
+ MOVW $WBFLUSH, R1 /* wbflush */
+ MOVW 0(R1), R1
+ NOOP
+ MOVW $KSEG1, R3
+ MOVW $icflush0(SB), R2 /* make sure PC is in uncached address space */
+ MOVW $(SWC|ISC), R1
+ OR R3, R2
+ JMP (R2)
+
+TEXT icflush0(SB), $-4
+
+ MOVW R1, M(STATUS) /* swap and isolate cache, splhi */
+ MOVW $icflush1(SB), R2
+ JMP (R2)
+
+TEXT icflush1(SB), $-4
+
+_icflush1:
+ MOVBU R0, 0x00(R8)
+ MOVBU R0, 0x04(R8)
+ MOVBU R0, 0x08(R8)
+ MOVBU R0, 0x0C(R8)
+ MOVBU R0, 0x10(R8)
+ MOVBU R0, 0x14(R8)
+ MOVBU R0, 0x18(R8)
+ MOVBU R0, 0x1C(R8)
+ MOVBU R0, 0x20(R8)
+ MOVBU R0, 0x24(R8)
+ MOVBU R0, 0x28(R8)
+ MOVBU R0, 0x2C(R8)
+ MOVBU R0, 0x30(R8)
+ MOVBU R0, 0x34(R8)
+ MOVBU R0, 0x38(R8)
+ MOVBU R0, 0x3C(R8)
+ SUB $0x40, R9
+ ADD $0x40, R8
+ BGTZ R9, _icflush1
+ MOVW $icflush2(SB), R2 /* make sure PC is in uncached address space */
+ OR R3, R2
+ JMP (R2)
+
+TEXT icflush2(SB), $-4
+
+ MOVW $0, M(STATUS) /* swap back caches, de-isolate them, and stay splhi */
+ NOOP /* +++ */
+ MOVW R10, M(STATUS)
+ RET
+
+TEXT dcflush(SB), $-4 /* dcflush(physaddr, nbytes) */
+
+ MOVW M(STATUS), R6
+ MOVW 0(FP), R4
+ MOVW 4(FP), R5
+ MOVW $KSEG0, R3
+ OR R3, R4
+ MOVW $0, M(STATUS)
+ MOVW $WBFLUSH, R1
+ MOVW 0(R1), R1
+ NOOP
+ MOVW $ISC, R1
+ MOVW R1, M(STATUS)
+_dcflush0:
+ MOVBU R0, 0x00(R4)
+ MOVBU R0, 0x04(R4)
+ MOVBU R0, 0x08(R4)
+ MOVBU R0, 0x0C(R4)
+ MOVBU R0, 0x10(R4)
+ MOVBU R0, 0x14(R4)
+ MOVBU R0, 0x18(R4)
+ MOVBU R0, 0x1C(R4)
+ MOVBU R0, 0x20(R4)
+ MOVBU R0, 0x24(R4)
+ MOVBU R0, 0x28(R4)
+ MOVBU R0, 0x2C(R4)
+ MOVBU R0, 0x30(R4)
+ MOVBU R0, 0x34(R4)
+ MOVBU R0, 0x38(R4)
+ MOVBU R0, 0x3C(R4)
+ SUB $0x40, R5
+ ADD $0x40, R4
+ BGTZ R5, _dcflush0
+ MOVW $0, M(STATUS)
+ NOOP /* +++ */
+ MOVW R6, M(STATUS)
+ RET
diff --git a/utils/0a/lex.c b/utils/0a/lex.c
new file mode 100644
index 00000000..6d736d7c
--- /dev/null
+++ b/utils/0a/lex.c
@@ -0,0 +1,697 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = '0';
+ thestring = "spim";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)) {
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, '/');
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+ "HI", LHI, D_HI,
+ "LO", LLO, D_LO,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+ "R16", LREG, 16,
+ "R17", LREG, 17,
+ "R18", LREG, 18,
+ "R19", LREG, 19,
+ "R20", LREG, 20,
+ "R21", LREG, 21,
+ "R22", LREG, 22,
+ "R23", LREG, 23,
+ "R24", LREG, 24,
+ "R25", LREG, 25,
+ "R26", LREG, 26,
+ "R27", LREG, 27,
+ "R28", LREG, 28,
+ "R29", LREG, 29,
+ "R30", LREG, 30,
+ "R31", LREG, 31,
+
+ "M", LM, 0,
+ "M0", LMREG, 0,
+ "M1", LMREG, 1,
+ "M2", LMREG, 2,
+ "M3", LMREG, 3,
+ "M4", LMREG, 4,
+ "M5", LMREG, 5,
+ "M6", LMREG, 6,
+ "M7", LMREG, 7,
+ "M8", LMREG, 8,
+ "M9", LMREG, 9,
+ "M10", LMREG, 10,
+ "M11", LMREG, 11,
+ "M12", LMREG, 12,
+ "M13", LMREG, 13,
+ "M14", LMREG, 14,
+ "M15", LMREG, 15,
+ "M16", LMREG, 16,
+ "M17", LMREG, 17,
+ "M18", LMREG, 18,
+ "M19", LMREG, 19,
+ "M20", LMREG, 20,
+ "M21", LMREG, 21,
+ "M22", LMREG, 22,
+ "M23", LMREG, 23,
+ "M24", LMREG, 24,
+ "M25", LMREG, 25,
+ "M26", LMREG, 26,
+ "M27", LMREG, 27,
+ "M28", LMREG, 28,
+ "M29", LMREG, 29,
+ "M30", LMREG, 30,
+ "M31", LMREG, 31,
+
+ "F", LF, 0,
+
+ "F0", LFREG, 0,
+ "F1", LFREG, 1,
+ "F2", LFREG, 2,
+ "F3", LFREG, 3,
+ "F4", LFREG, 4,
+ "F5", LFREG, 5,
+ "F6", LFREG, 6,
+ "F7", LFREG, 7,
+ "F8", LFREG, 8,
+ "F9", LFREG, 9,
+ "F10", LFREG, 10,
+ "F11", LFREG, 11,
+ "F12", LFREG, 12,
+ "F13", LFREG, 13,
+ "F14", LFREG, 14,
+ "F15", LFREG, 15,
+ "F16", LFREG, 16,
+ "F17", LFREG, 17,
+ "F18", LFREG, 18,
+ "F19", LFREG, 19,
+ "F20", LFREG, 20,
+ "F21", LFREG, 21,
+ "F22", LFREG, 22,
+ "F23", LFREG, 23,
+ "F24", LFREG, 24,
+ "F25", LFREG, 25,
+ "F26", LFREG, 26,
+ "F27", LFREG, 27,
+ "F28", LFREG, 28,
+ "F29", LFREG, 29,
+ "F30", LFREG, 30,
+ "F31", LFREG, 31,
+
+ "FCR", LFCR, 0,
+ "FCR0", LFCREG, 0,
+ "FCR1", LFCREG, 1,
+ "FCR2", LFCREG, 2,
+ "FCR3", LFCREG, 3,
+ "FCR4", LFCREG, 4,
+ "FCR5", LFCREG, 5,
+ "FCR6", LFCREG, 6,
+ "FCR7", LFCREG, 7,
+ "FCR8", LFCREG, 8,
+ "FCR9", LFCREG, 9,
+ "FCR10", LFCREG, 10,
+ "FCR11", LFCREG, 11,
+ "FCR12", LFCREG, 12,
+ "FCR13", LFCREG, 13,
+ "FCR14", LFCREG, 14,
+ "FCR15", LFCREG, 15,
+ "FCR16", LFCREG, 16,
+ "FCR17", LFCREG, 17,
+ "FCR18", LFCREG, 18,
+ "FCR19", LFCREG, 19,
+ "FCR20", LFCREG, 20,
+ "FCR21", LFCREG, 21,
+ "FCR22", LFCREG, 22,
+ "FCR23", LFCREG, 23,
+ "FCR24", LFCREG, 24,
+ "FCR25", LFCREG, 25,
+ "FCR26", LFCREG, 26,
+ "FCR27", LFCREG, 27,
+ "FCR28", LFCREG, 28,
+ "FCR29", LFCREG, 29,
+ "FCR30", LFCREG, 30,
+ "FCR31", LFCREG, 31,
+
+ "ADD", LTYPE1, AADD,
+ "ADDU", LTYPE1, AADDU,
+ "SUB", LTYPE1, ASUB, /* converted to ADD(-) in loader */
+ "SUBU", LTYPE1, ASUBU,
+ "SGT", LTYPE1, ASGT,
+ "SGTU", LTYPE1, ASGTU,
+ "AND", LTYPE1, AAND,
+ "OR", LTYPE1, AOR,
+ "XOR", LTYPE1, AXOR,
+ "SLL", LTYPE1, ASLL,
+ "SRL", LTYPE1, ASRL,
+ "SRA", LTYPE1, ASRA,
+
+ "ADDV", LTYPE1, AADDV,
+ "ADDVU", LTYPE1, AADDVU,
+ "SUBV", LTYPE1, ASUBV, /* converted to ADD(-) in loader */
+ "SUBVU", LTYPE1, ASUBVU,
+ "SLLV", LTYPE1, ASLLV,
+ "SRLV", LTYPE1, ASRLV,
+ "SRAV", LTYPE1, ASRAV,
+
+ "NOR", LTYPE2, ANOR,
+
+ "MOVB", LTYPE3, AMOVB,
+ "MOVBU", LTYPE3, AMOVBU,
+ "MOVH", LTYPE3, AMOVH,
+ "MOVHU", LTYPE3, AMOVHU,
+ "MOVWL", LTYPE3, AMOVWL,
+ "MOVWR", LTYPE3, AMOVWR,
+ "MOVVL", LTYPE3, AMOVVL,
+ "MOVVR", LTYPE3, AMOVVR,
+
+ "BREAK", LTYPEJ, ABREAK, /* overloaded CACHE opcode */
+ "END", LTYPE4, AEND,
+ "REM", LTYPE6, AREM,
+ "REMU", LTYPE6, AREMU,
+ "RET", LTYPE4, ARET,
+ "SYSCALL", LTYPE4, ASYSCALL,
+ "TLBP", LTYPE4, ATLBP,
+ "TLBR", LTYPE4, ATLBR,
+ "TLBWI", LTYPE4, ATLBWI,
+ "TLBWR", LTYPE4, ATLBWR,
+
+ "MOVW", LTYPE5, AMOVW,
+ "MOVV", LTYPE5, AMOVV,
+ "MOVD", LTYPE5, AMOVD,
+ "MOVF", LTYPE5, AMOVF,
+
+ "DIV", LTYPE6, ADIV,
+ "DIVU", LTYPE6, ADIVU,
+ "MUL", LTYPE6, AMUL,
+ "MULU", LTYPE6, AMULU,
+ "DIVV", LTYPE6, ADIVV,
+ "DIVVU", LTYPE6, ADIVVU,
+ "MULV", LTYPE6, AMULV,
+ "MULVU", LTYPE6, AMULVU,
+
+ "RFE", LTYPE7, ARFE,
+ "JMP", LTYPE7, AJMP,
+
+ "JAL", LTYPE8, AJAL,
+
+ "BEQ", LTYPE9, ABEQ,
+ "BNE", LTYPE9, ABNE,
+
+ "BGEZ", LTYPEA, ABGEZ,
+ "BGEZAL", LTYPEA, ABGEZAL,
+ "BGTZ", LTYPEA, ABGTZ,
+ "BLEZ", LTYPEA, ABLEZ,
+ "BLTZ", LTYPEA, ABLTZ,
+ "BLTZAL", LTYPEA, ABLTZAL,
+
+ "TEXT", LTYPEB, ATEXT,
+ "GLOBL", LTYPEB, AGLOBL,
+
+ "DATA", LTYPEC, ADATA,
+
+ "MOVDF", LTYPE5, AMOVDF,
+ "MOVDW", LTYPE5, AMOVDW,
+ "MOVFD", LTYPE5, AMOVFD,
+ "MOVFW", LTYPE5, AMOVFW,
+ "MOVWD", LTYPE5, AMOVWD,
+ "MOVWF", LTYPE5, AMOVWF,
+
+ "ABSD", LTYPED, AABSD,
+ "ABSF", LTYPED, AABSF,
+ "ABSW", LTYPED, AABSW,
+ "NEGD", LTYPED, ANEGD,
+ "NEGF", LTYPED, ANEGF,
+ "NEGW", LTYPED, ANEGW,
+
+ "CMPEQD", LTYPEF, ACMPEQD,
+ "CMPEQF", LTYPEF, ACMPEQF,
+ "CMPGED", LTYPEF, ACMPGED,
+ "CMPGEF", LTYPEF, ACMPGEF,
+ "CMPGTD", LTYPEF, ACMPGTD,
+ "CMPGTF", LTYPEF, ACMPGTF,
+
+ "ADDD", LTYPEE, AADDD,
+ "ADDF", LTYPEE, AADDF,
+ "ADDW", LTYPEE, AADDW,
+ "DIVD", LTYPEE, ADIVD,
+ "DIVF", LTYPEE, ADIVF,
+ "DIVW", LTYPEE, ADIVW,
+ "MULD", LTYPEE, AMULD,
+ "MULF", LTYPEE, AMULF,
+ "MULW", LTYPEE, AMULW,
+ "SUBD", LTYPEE, ASUBD,
+ "SUBF", LTYPEE, ASUBF,
+ "SUBW", LTYPEE, ASUBW,
+
+ "BFPT", LTYPEG, ABFPT,
+ "BFPF", LTYPEG, ABFPF,
+
+ "WORD", LTYPEH, AWORD,
+ "NOP", LTYPEI, ANOP,
+ "SCHED", LSCHED, 0,
+ "NOSCHED", LSCHED, 0x80,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = alloc(100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+int
+isreg(Gen *g)
+{
+
+ USED(g);
+ return 1;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_MREG:
+ case D_FCREG:
+ case D_LO:
+ case D_HI:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+ }
+}
+
+void
+outcode(int a, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+jackpot:
+ sf = 0;
+ s = g1->sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g1->name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, reg|nosched);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/0a/mkfile b/utils/0a/mkfile
new file mode 100644
index 00000000..1c1a88c7
--- /dev/null
+++ b/utils/0a/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=0a
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../vc/v.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES= a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/0c/cgen.c b/utils/0c/cgen.c
new file mode 100644
index 00000000..e77c2114
--- /dev/null
+++ b/utils/0c/cgen.c
@@ -0,0 +1,1148 @@
+#include "gc.h"
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o;
+ long v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesu[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ if(n->addable > INDEXED) {
+ if(nn != Z)
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ o = n->op;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED && l->complex < FNX) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, n, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ } else {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+
+ regalloc(&nod, n, nn);
+ gmove(&nod2, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(o, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type)) {
+ if(nocast(n->type, nn->type)) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+ return;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ if(nn == Z || typefd[n->type->etype]) {
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ nodreg(&nod1, n, NREG+FREGZERO);
+ gopcode(o, &nod, &nod1, Z);
+ } else
+ gopcode(o, &nod, Z, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(true)
+ gopcode(OCOND, &nod, nodconst(0), &nod);
+ else
+ gopcode(OCOND, nodconst(1), &nod, &nod);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(nn != Z && !typefd[l->type->etype]) {
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ switch(o) {
+ case OEQ:
+ gopcode(OSUB, &nod1, &nod, &nod);
+ gopcode(OCOND, &nod, nodconst(0), &nod);
+ break;
+ case ONE:
+ gopcode(OSUB, &nod1, &nod, &nod);
+ gopcode(OCOND, nodconst(1), &nod, &nod);
+ break;
+ case OLE:
+ gopcode(OCOMMA, &nod1, &nod, &nod);
+ break;
+ case OGT:
+ gopcode(OCOMMA, &nod1, &nod, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OLT:
+ gopcode(OCOMMA, &nod, &nod1, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OGE:
+ gopcode(OCOMMA, &nod, &nod1, &nod);
+ break;
+ case OLS:
+ gopcode(OCOND, &nod1, &nod, &nod);
+ break;
+ case OHI:
+ gopcode(OCOND, &nod1, &nod, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OLO:
+ gopcode(OCOND, &nod, &nod1, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OHS:
+ gopcode(OCOND, &nod, &nod1, &nod);
+ break;
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+ }
+ if(sconst(l)) {
+ switch(o) {
+ default:
+ if(l->vconst != 0)
+ break;
+
+ case OGT:
+ case OHI:
+ case OLE:
+ case OLS:
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ }
+ if(sconst(r)) {
+ switch(o) {
+ default:
+ if(r->vconst != 0)
+ break;
+
+ case OGE:
+ case OHS:
+ case OLT:
+ case OLO:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, r, Z);
+ regfree(&nod);
+ goto com;
+ }
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod1, &nod, Z);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && nn->complex >= FNX) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TVLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TVLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TVLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TVLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ }
+
+ w /= SZ_VLONG;
+ if(w <= 5) {
+ layout(&nod1, &nod2, w, 0, Z);
+ goto out;
+ }
+
+ /*
+ * minimize space for unrolling loop
+ * 3,4,5 times. (6 or more is never minimum)
+ * if small structure, try 2 also.
+ */
+ c = 0; /* set */
+ m = 100;
+ i = 3;
+ if(w <= 15)
+ i = 2;
+ for(; i<=5; i++)
+ if(i + w%i <= m) {
+ c = i;
+ m = c + w%c;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ layout(&nod1, &nod2, w%c, w/c, &nod3);
+
+ pc1 = pc;
+ layout(&nod1, &nod2, c, 0, Z);
+
+ gopcode(OSUB, nodconst(1), Z, &nod3);
+ nod1.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_VLONG), Z, &nod1);
+ nod2.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_VLONG), Z, &nod2);
+
+ gopcode(OEQ, &nod3, Z, Z);
+ p->as = ABGTZ;
+ patch(p, pc1);
+
+ regfree(&nod3);
+out:
+ regfree(&nod1);
+ regfree(&nod2);
+}
+
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, &regnode, Z);
+ regalloc(&t2, &regnode, Z);
+ t1.type = types[TVLONG];
+ t2.type = types[TVLONG];
+ if(c > 0) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_VLONG;
+ }
+ if(cn != Z)
+ gopcode(OAS, nodconst(cv), Z, cn);
+ if(c > 1) {
+ gopcode(OAS, f, Z, &t2);
+ f->xoffset += SZ_VLONG;
+ }
+ if(c > 0) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_VLONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_VLONG;
+ }
+ if(c > 1) {
+ gopcode(OAS, &t2, Z, t);
+ t->xoffset += SZ_VLONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_VLONG;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
diff --git a/utils/0c/enam.c b/utils/0c/enam.c
new file mode 100644
index 00000000..f9c94f7f
--- /dev/null
+++ b/utils/0c/enam.c
@@ -0,0 +1,118 @@
+char* anames[] =
+{
+ "XXX",
+ "ABSD",
+ "ABSF",
+ "ABSW",
+ "ADD",
+ "ADDD",
+ "ADDF",
+ "ADDU",
+ "ADDW",
+ "AND",
+ "BEQ",
+ "BFPF",
+ "BFPT",
+ "BGEZ",
+ "BGEZAL",
+ "BGTZ",
+ "BLEZ",
+ "BLTZ",
+ "BLTZAL",
+ "BNE",
+ "BREAK",
+ "CMPEQD",
+ "CMPEQF",
+ "CMPGED",
+ "CMPGEF",
+ "CMPGTD",
+ "CMPGTF",
+ "DATA",
+ "DIV",
+ "DIVD",
+ "DIVF",
+ "DIVU",
+ "DIVW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "JAL",
+ "JMP",
+ "MOVB",
+ "MOVBU",
+ "MOVD",
+ "MOVDF",
+ "MOVDW",
+ "MOVF",
+ "MOVFD",
+ "MOVFW",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MOVWD",
+ "MOVWF",
+ "MOVWL",
+ "MOVWR",
+ "MUL",
+ "MULD",
+ "MULF",
+ "MULU",
+ "MULW",
+ "NAME",
+ "NEGD",
+ "NEGF",
+ "NEGW",
+ "NOP",
+ "NOR",
+ "OR",
+ "REM",
+ "REMU",
+ "RET",
+ "RFE",
+ "SGT",
+ "SGTU",
+ "SLL",
+ "SRA",
+ "SRL",
+ "SUB",
+ "SUBD",
+ "SUBF",
+ "SUBU",
+ "SUBW",
+ "SYSCALL",
+ "TEXT",
+ "TLBP",
+ "TLBR",
+ "TLBWI",
+ "TLBWR",
+ "WORD",
+ "XOR",
+ "END",
+ "MOVV",
+ "MOVVL",
+ "MOVVR",
+ "SLLV",
+ "SRAV",
+ "SRLV",
+ "DIVV",
+ "DIVVU",
+ "REMV",
+ "REMVU",
+ "MULV",
+ "MULVU",
+ "ADDV",
+ "ADDVU",
+ "SUBV",
+ "SUBVU",
+ "DYNT",
+ "INIT",
+ "BCASE",
+ "CASE",
+ "TRUNCFV",
+ "TRUNCDV",
+ "TRUNCFW",
+ "TRUNCDW",
+ "MOVWU",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/0c/gc.h b/utils/0c/gc.h
new file mode 100644
index 00000000..88196aec
--- /dev/null
+++ b/utils/0c/gc.h
@@ -0,0 +1,332 @@
+#include "../cc/cc.h"
+#include "../vc/v.out.h"
+
+/*
+ * 0c/spim
+ * Mips 4000 little endian
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Adr
+{
+ long offset;
+ double dval;
+ vlong vval;
+ char sval[NSNAME];
+ Ieee ieee;
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ char as;
+ char reg;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN Multab multab[20];
+EXTERN int retok;
+EXTERN int hintabsize;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[NREG+NREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 4
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void xcom(Node*);
+void bcomplex(Node*);
+void usedset(Node*, int);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+int llconst(Node*);
+int sval(long);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/utils/0c/list.c b/utils/0c/list.c
new file mode 100644
index 00000000..f89b17ca
--- /dev/null
+++ b/utils/0c/list.c
@@ -0,0 +1,244 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('D', Dconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCREG:
+ sprint(str, "FCR%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_LO:
+ sprint(str, "LO");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(LO)(REG)", a);
+ break;
+
+ case D_HI:
+ sprint(str, "HI");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(HI)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/0c/mkenam b/utils/0c/mkenam
new file mode 100644
index 00000000..f09ef75d
--- /dev/null
+++ b/utils/0c/mkenam
@@ -0,0 +1,15 @@
+ed - ../vc/v.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/0c/mkfile b/utils/0c/mkfile
new file mode 100644
index 00000000..6b722243
--- /dev/null
+++ b/utils/0c/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=0c
+
+OFILES= cgen.$O\
+ enam.$O\
+ list.$O\
+ peep.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ mul.$O\
+
+HFILES= gc.h\
+ v.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/0c/mul.c b/utils/0c/mul.c
new file mode 100644
index 00000000..3ef56cd5
--- /dev/null
+++ b/utils/0c/mul.c
@@ -0,0 +1,608 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=6; g++) {
+ if(g >= 6 && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/utils/0c/peep.c b/utils/0c/peep.c
new file mode 100644
index 00000000..a9a43da4
--- /dev/null
+++ b/utils/0c/peep.c
@@ -0,0 +1,694 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
+ if(regtyp(&p->to)) {
+ if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(regzer(&p->from))
+ if(p->to.type == D_REG) {
+ p->from.type = D_REG;
+ p->from.reg = 0;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regzer(Adr *a)
+{
+
+ if(a->type == D_CONST)
+ if(a->sym == S)
+ if(a->offset == 0)
+ return 1;
+ if(a->type == D_REG)
+ if(a->reg == 0)
+ return 1;
+ return 0;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG) {
+ if(a->reg != 0)
+ return 1;
+ return 0;
+ }
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case AJAL:
+ return 0;
+
+ case ASGT:
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDD:
+ case AADDF:
+ case ASUBD:
+ case ASUBF:
+ case AMULD:
+ case AMULF:
+ case ADIVD:
+ case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFD:
+ case AMOVDF:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ASGT: /* read, read, write */
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case ANOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABGTZ:
+ case ABGEZ:
+ case ABLTZ:
+ case ABLEZ:
+
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+ case ABFPF:
+ case ABFPT:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AJMP: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case AJAL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(REGARG && v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+ case ABEQ:
+ case ABNE:
+ case ABGTZ:
+ case ABGEZ:
+ case ABLTZ:
+ case ABLEZ:
+
+ case ASGT:
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+ return D_REG;
+
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v))
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG)
+ if(a->type == D_OREG)
+ if(v->reg == a->reg)
+ return 1;
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v))
+ if(p->from.type == v->type || p->to.type == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v))
+ a->reg = s->reg;
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
diff --git a/utils/0c/reg.c b/utils/0c/reg.c
new file mode 100644
index 00000000..0ed8d696
--- /dev/null
+++ b/utils/0c/reg.c
@@ -0,0 +1,1151 @@
+#include "gc.h"
+
+void addsplits(void);
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVV:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case AJAL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] && debug['v']) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%B", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%B", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%B", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%B", r->calbehind);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == AJAL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TVLONG || v->etype == TUVLONG)
+ p1->as = AMOVV;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !(typechlpfd[et]/* || typev[et]*/)) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case AJAL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R3
+ * 1 R4
+ * ... ...
+ * 19 R22
+ * 20 R23
+ */
+long
+RtoB(int r)
+{
+
+ if(r < 3 || r > 23)
+ return 0;
+ return 1L << (r-3);
+}
+
+BtoR(long b)
+{
+
+ b &= 0x001fffffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + 3;
+}
+
+/*
+ * bit reg
+ * 22 F4
+ * 23 F6
+ * ... ...
+ * 31 F22
+ */
+long
+FtoB(int f)
+{
+
+ if(f < 4 || f > 22 || (f&1))
+ return 0;
+ return 1L << (f/2 + 20);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0xffc00000L;
+ if(b == 0)
+ return 0;
+ return bitno(b)*2 - 40;
+}
diff --git a/utils/0c/sgen.c b/utils/0c/sgen.c
new file mode 100644
index 00000000..eb562e8f
--- /dev/null
+++ b/utils/0c/sgen.c
@@ -0,0 +1,569 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typesu[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ }
+ }
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ sp->to.offset += maxargsafe;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesu[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ bcomplex(l);
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ t = vlog(l);
+ if(t >= 0) {
+ n->op = OASHL;
+ n->left = r;
+ n->right = l;
+ r = l;
+ l = n->left;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ switch(n->op) {
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ case OEQ:
+ case ONE:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
+
+void
+bcomplex(Node *n)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T)
+ boolgen(n, 1, Z);
+ else
+ gbranch(OGOTO);
+}
diff --git a/utils/0c/swt.c b/utils/0c/swt.c
new file mode 100644
index 00000000..38cd3d43
--- /dev/null
+++ b/utils/0c/swt.c
@@ -0,0 +1,727 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+ Node tn;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8lux\n", i, iq[i].val);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ regalloc(&tn, &regnode, Z);
+ swit1(iq, nc, def, n, &tn);
+ regfree(&tn);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n, Node *tn)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8lux\n", q->val);
+ gmove(nodconst(q->val), tn);
+ gopcode(OEQ, n, tn, Z);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8lux\n", r->val);
+ gmove(nodconst(r->val), tn);
+ gopcode(OLT, tn, n, Z);
+ sp = p;
+ gopcode(OEQ, n, tn, Z);
+ patch(p, r->label);
+ swit1(q, i, def, n, tn);
+
+ if(debug['W'])
+ print("case < %.8lux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n, tn);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ if(debug['M'] && debug['v'])
+ print("%L multiply: %ld\n", n->lineno, v);
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ if(v < 0)
+ gopcode(OSUB, &nod1, nodconst(0), &nod1);
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, nodconst(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ gpseudo(ADATA, s, nodconst(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+
+ bf[0] = p->as;
+ bf[1] = p->reg;
+ bf[2] = p->lineno;
+ bf[3] = p->lineno>>8;
+ bf[4] = p->lineno>>16;
+ bf[5] = p->lineno>>24;
+ bp = zaddr(bf+6, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ ulong sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ vlong v;
+ long l;
+ Ieee e;
+
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_MREG:
+ case D_FCREG:
+ case D_LO:
+ case D_HI:
+ break;
+
+ case D_CONST:
+ case D_OREG:
+ case D_BRANCH:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ case D_VCONST:
+ v = a->vval;
+ bp[0] = v;
+ bp[1] = v>>8;
+ bp[2] = v>>16;
+ bp[3] = v>>24;
+ bp[4] = v>>32;
+ bp[5] = v>>40;
+ bp[6] = v>>48;
+ bp[7] = v>>56;
+ bp += 8;
+ break;
+ }
+ return bp;
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_VLONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_VLONG)
+ w = SZ_VLONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesu[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_VLONG) {
+ w = SZ_VLONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_VLONG-1;
+ if(v > max)
+ max = round(v, SZ_VLONG);
+ return max;
+}
diff --git a/utils/0c/txt.c b/utils/0c/txt.c
new file mode 100644
index 00000000..964db985
--- /dev/null
+++ b/utils/0c/txt.c
@@ -0,0 +1,1483 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '0';
+ thestring = "spim";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 0;
+ if(i == REGZERO ||
+ (i >= NREG && ((i-NREG)&1)))
+ reg[i] = 1;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(i != REGZERO)
+ if(reg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NREG; i+=2)
+ if(reg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gopcode(OAS, n, Z, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+int
+tmpreg(void)
+{
+ int i;
+
+ for(i=REGRET+1; i<NREG; i++)
+ if(reg[i] == 0)
+ return i;
+ diag(Z, "out of fixed registers");
+ return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TUVLONG:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i > 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<NREG; i++) {
+ if(j >= NREG)
+ j = REGRET+1;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NREG)
+ goto out;
+ }
+ j = 0*2 + NREG;
+ for(i=NREG; i<NREG+NREG; i+=2) {
+ if(j >= NREG+NREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j += 2;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ lasti++;
+ if(lasti >= 5)
+ lasti = 0;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_VLONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else
+ if(llconst(n)) {
+ a->type = D_VCONST;
+ a->vval = n->vconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod;
+ Prog *p1;
+ double d;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0.0) {
+ a = FREGZERO;
+ goto ffreg;
+ }
+ if(d == 0.5) {
+ a = FREGHALF;
+ goto ffreg;
+ }
+ if(d == 1.0) {
+ a = FREGONE;
+ goto ffreg;
+ }
+ if(d == 2.0) {
+ a = FREGTWO;
+ goto ffreg;
+ }
+ if(d == -.5) {
+ fop(OSUB, FREGHALF, FREGZERO, t);
+ return;
+ }
+ if(d == -1.0) {
+ fop(OSUB, FREGONE, FREGZERO, t);
+ return;
+ }
+ if(d == -2.0) {
+ fop(OSUB, FREGTWO, FREGZERO, t);
+ return;
+ }
+ if(d == 1.5) {
+ fop(OADD, FREGONE, FREGHALF, t);
+ return;
+ }
+ if(d == 2.5) {
+ fop(OADD, FREGTWO, FREGHALF, t);
+ return;
+ }
+ if(d == 3.0) {
+ fop(OADD, FREGTWO, FREGONE, t);
+ return;
+ }
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0) {
+ a = FREGZERO;
+ ffreg:
+ nodreg(&nod, f, NREG+a);
+ gmove(&nod, t);
+ return;
+ }
+ }
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ if(typefd[tt]) {
+ /* special case can load mem to Freg */
+ regalloc(&nod, t, t);
+ gins(AMOVW, f, &nod);
+ a = AMOVWD;
+ if(tt == TFLOAT)
+ a = AMOVWF;
+ gins(a, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVW;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TUVLONG:
+ case TVLONG:
+ a = AMOVV;
+ break;
+ }
+ if(typechlp[ft] && typeilp[tt])
+ regalloc(&nod, t, t);
+ else
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TUVLONG:
+ case TVLONG:
+ a = AMOVV;
+ break;
+ }
+ if(!typefd[ft] && vconst(f) == 0) {
+ gins(a, f, t);
+ return;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TUVLONG:
+ case TVLONG:
+ switch(tt) {
+ case TUVLONG:
+ case TVLONG:
+ a = AMOVV;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ case TDOUBLE:
+ gins(AMOVW, f, t);
+ gins(AMOVWD, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGED, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVD, nodfconst(4294967296.), &nod);
+ gins(AADDD, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TFLOAT:
+ gins(AMOVW, f, t);
+ gins(AMOVWF, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGEF, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVF, nodfconst(4294967296.), &nod);
+ gins(AADDF, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ }
+ break;
+ case TDOUBLE:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ a = AMOVD;
+ if(ft == TFLOAT)
+ a = AMOVFD;
+ break;
+ case TFLOAT:
+ a = AMOVDF;
+ if(ft == TFLOAT)
+ a = AMOVF;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ regalloc(&nod, f, Z);
+ gins(ATRUNCDW, f, &nod);
+ if(ft == TFLOAT)
+ p->as = ATRUNCFW;
+ gins(AMOVW, &nod, t);
+ regfree(&nod);
+ return;
+ case TUVLONG:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(ATRUNCDV, f, &nod);
+ if(ft == TFLOAT)
+ p->as = ATRUNCFV;
+ gins(AMOVV, &nod, t);
+ regfree(&nod);
+ return;
+ }
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ switch(tt) {
+ case TDOUBLE:
+ gins(AMOVW, f, t);
+ gins(AMOVWD, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGED, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVD, nodfconst(4294967296.), &nod);
+ gins(AADDD, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TFLOAT:
+ gins(AMOVW, f, t);
+ gins(AMOVWF, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGEF, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVF, nodfconst(4294967296.), &nod);
+ gins(AADDF, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TUVLONG:
+ case TVLONG:
+ if(ft == TULONG || ft == TUINT) {
+ a = AMOVWU;
+ break;
+ }
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AMOVF || a == AMOVD || a == AMOVV)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et, ett;
+ Adr ta;
+ Node nod;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ ett = TLONG;
+ if(t != Z && t->type != T)
+ ett = t->type->etype;
+ if(llconst(f1) && o != OAS) {
+ regalloc(&nod, f1, Z);
+ gmove(f1, &nod);
+ gopcode(o, &nod, f2, t);
+ regfree(&nod);
+ return;
+ }
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADDU;
+ if(et == TVLONG || et == TUVLONG)
+ a = AADDVU;
+ else
+ if(et == TFLOAT)
+ a = AADDF;
+ else
+ if(et == TDOUBLE)
+ a = AADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBU;
+ if(et == TVLONG || et == TUVLONG)
+ a = ASUBVU;
+ else
+ if(et == TFLOAT)
+ a = ASUBF;
+ else
+ if(et == TDOUBLE)
+ a = ASUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AOR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ if(ett == TVLONG || ett == TUVLONG)
+ a = ASRLV;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ if(ett == TVLONG || ett == TUVLONG)
+ a = ASRAV;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ if(ett == TVLONG || ett == TUVLONG)
+ a = ASLLV;
+ break;
+
+ case OFUNC:
+ a = AJAL;
+ break;
+
+ case OCOND:
+ a = ASGTU;
+ break;
+
+ case OCOMMA:
+ a = ASGT;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT) {
+ a = AMULF;
+ break;
+ } else
+ if(et == TDOUBLE) {
+ a = AMULD;
+ break;
+ }
+ a = AMUL;
+ if(et == TVLONG || et == TUVLONG)
+ a = AMULV;
+ goto muldiv;
+
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = ADIVF;
+ break;
+ } else
+ if(et == TDOUBLE) {
+ a = ADIVD;
+ break;
+ }
+ a = ADIV;
+ if(et == TVLONG || et == TUVLONG)
+ a = ADIVV;
+ goto muldiv;
+
+ case OASMOD:
+ case OMOD:
+ a = ADIV;
+ o = OMOD;
+ if(et == TVLONG || et == TUVLONG)
+ a = ADIVV;
+ goto muldiv;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULU;
+ if(et == TVLONG || et == TUVLONG)
+ a = AMULVU;
+ goto muldiv;
+
+ case OASLMOD:
+ case OLMOD:
+ o = OMOD;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVU;
+ if(et == TVLONG || et == TUVLONG)
+ a = ADIVVU;
+ goto muldiv;
+
+ muldiv:
+ nextpc();
+ naddr(f1, &p->from);
+ if(f2 == Z)
+ raddr(t, p);
+ else
+ raddr(f2, p);
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ nextpc();
+ p->as = AMOVW;
+ if(et == TVLONG || et == TUVLONG)
+ p->as = AMOVV;
+ a = D_LO;
+ if(o == OMOD)
+ a = D_HI;
+ p->from.type = a;
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+
+ case OEQ:
+ if(!typefd[et]) {
+ a = ABEQ;
+ break;
+ }
+
+ case ONE:
+ if(!typefd[et]) {
+ a = ABNE;
+ break;
+ }
+
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ if(typefd[et]) {
+ nextpc();
+ if(et == TFLOAT) {
+ a = ACMPGTF;
+ if(o == OEQ || o == ONE)
+ a = ACMPEQF;
+ else
+ if(o == OLT || o == OGE)
+ a = ACMPGEF;
+ } else {
+ a = ACMPGTD;
+ if(o == OEQ || o == ONE)
+ a = ACMPEQD;
+ else
+ if(o == OLT || o == OGE)
+ a = ACMPGED;
+ }
+ p->as = a;
+ naddr(f1, &p->from);
+ raddr(f2, p);
+ if(debug['g'])
+ print("%P\n", p);
+ nextpc();
+ a = ABFPF;
+ if(o == OEQ || o == OGE || o == OGT)
+ a = ABFPT;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+ }
+ if(vconst(f1) == 0 || vconst(f2) == 0) {
+ if(vconst(f1) == 0) {
+ o = invrel[relindex(o)];
+ f1 = f2;
+ }
+ switch(o) {
+ case OLT:
+ a = ABLTZ;
+ break;
+ case OLE:
+ a = ABLEZ;
+ break;
+ case OGE:
+ a = ABGEZ;
+ break;
+ case OGT:
+ a = ABGTZ;
+ break;
+ }
+ f2 = Z;
+ break;
+ }
+
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ nextpc();
+ if(o == OLE || o == OGT || o == OLS || o == OHI) {
+ naddr(f1, &p->from);
+ raddr(f2, p);
+ } else {
+ naddr(f2, &p->from);
+ raddr(f1, p);
+ }
+ naddr(&regnode, &p->to);
+ p->to.reg = tmpreg();
+ a = ASGT;
+ if(o == OLO || o == OLS || o == OHS || o == OHI)
+ a = ASGTU;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+
+ nextpc();
+ naddr(&regnode, &p->from);
+ p->from.reg = tmpreg();
+ a = ABEQ;
+ if(o == OLT || o == OGT || o == OLO || o == OHI)
+ a = ABNE;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0)
+ p->reg = REGZERO;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= (vlong)-32766 && vv < (vlong)32766)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+llconst(Node *n)
+{
+ vlong vv;
+
+ if(n != Z && n->op == OCONST) {
+ if(typev[n->type->etype]) {
+ vv = n->vconst >> 32;
+ if(vv != 0 && vv != -1)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+sval(long v)
+{
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= 16)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 16)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /*[TXXX]*/
+ SZ_CHAR, /*[TCHAR]*/
+ SZ_CHAR, /*[TUCHAR]*/
+ SZ_SHORT, /*[TSHORT]*/
+ SZ_SHORT, /*[TUSHORT]*/
+ SZ_INT, /*[TINT]*/
+ SZ_INT, /*[TUINT]*/
+ SZ_LONG, /*[TLONG]*/
+ SZ_LONG, /*[TULONG]*/
+ SZ_VLONG, /*[TVLONG]*/
+ SZ_VLONG, /*[TUVLONG]*/
+ SZ_FLOAT, /*[TFLOAT]*/
+ SZ_DOUBLE, /*[TDOUBLE]*/
+ SZ_IND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ -1, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ -1, /*[TSTRUCT]*/
+ -1, /*[TUNION]*/
+ SZ_INT, /*[TENUM]*/
+};
+long ncast[NTYPE] =
+{
+ 0, /*[TXXX]*/
+ BCHAR|BUCHAR, /*[TCHAR]*/
+ BCHAR|BUCHAR, /*[TUCHAR]*/
+ BSHORT|BUSHORT, /*[TSHORT]*/
+ BSHORT|BUSHORT, /*[TUSHORT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
+ BVLONG|BUVLONG, /*[TVLONG]*/
+ BVLONG|BUVLONG, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BLONG|BULONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};
diff --git a/utils/0c/v.out.h b/utils/0c/v.out.h
new file mode 100644
index 00000000..2fec2893
--- /dev/null
+++ b/utils/0c/v.out.h
@@ -0,0 +1,201 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 32
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+#define REGZERO 0
+#define REGRET 1
+#define REGARG 1
+/* compiler allocates R1 up as temps */
+/* compiler allocates register variables R3-R23 */
+#define REGEXT 25
+/* compiler allocates external registers R25 down */
+/* dont use R26 R27 */
+#define REGTMP 28
+#define REGSP 29
+#define REGSB 30
+#define REGLINK 31
+
+#define FREGRET 0
+/* compiler allocates register variables F4-F22 */
+/* compiler allocates external registers F22 down */
+#define FREGEXT 22
+#define FREGZERO 24 /* both float and double */
+#define FREGHALF 26 /* double */
+#define FREGONE 28 /* double */
+#define FREGTWO 30 /* double */
+
+enum as
+{
+ AXXX,
+
+ AABSD,
+ AABSF,
+ AABSW,
+ AADD,
+ AADDD,
+ AADDF,
+ AADDU,
+ AADDW,
+ AAND,
+ ABEQ,
+ ABFPF,
+ ABFPT,
+ ABGEZ,
+ ABGEZAL,
+ ABGTZ,
+ ABLEZ,
+ ABLTZ,
+ ABLTZAL,
+ ABNE,
+ ABREAK,
+ ACMPEQD,
+ ACMPEQF,
+ ACMPGED,
+ ACMPGEF,
+ ACMPGTD,
+ ACMPGTF,
+ ADATA,
+ ADIV,
+ ADIVD,
+ ADIVF,
+ ADIVU,
+ ADIVW,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AJAL,
+ AJMP,
+ AMOVB,
+ AMOVBU,
+ AMOVD,
+ AMOVDF,
+ AMOVDW,
+ AMOVF,
+ AMOVFD,
+ AMOVFW,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMOVWD,
+ AMOVWF,
+ AMOVWL,
+ AMOVWR,
+ AMUL,
+ AMULD,
+ AMULF,
+ AMULU,
+ AMULW,
+ ANAME,
+ ANEGD,
+ ANEGF,
+ ANEGW,
+ ANOP,
+ ANOR,
+ AOR,
+ AREM,
+ AREMU,
+ ARET,
+ ARFE,
+ ASGT,
+ ASGTU,
+ ASLL,
+ ASRA,
+ ASRL,
+ ASUB,
+ ASUBD,
+ ASUBF,
+ ASUBU,
+ ASUBW,
+ ASYSCALL,
+ ATEXT,
+ ATLBP,
+ ATLBR,
+ ATLBWI,
+ ATLBWR,
+ AWORD,
+ AXOR,
+
+ AEND,
+
+ AMOVV,
+ AMOVVL,
+ AMOVVR,
+ ASLLV,
+ ASRAV,
+ ASRLV,
+ ADIVV,
+ ADIVVU,
+ AREMV,
+ AREMVU,
+ AMULV,
+ AMULVU,
+ AADDV,
+ AADDVU,
+ ASUBV,
+ ASUBVU,
+
+ ADYNT,
+ AINIT,
+
+ ABCASE,
+ ACASE,
+
+ ATRUNCFV,
+ ATRUNCDV,
+ ATRUNCFW,
+ ATRUNCDW,
+ AMOVWU,
+ AMOVFV,
+ AMOVDV,
+ AMOVVF,
+ AMOVVD,
+
+ ASIGNAME,
+
+ ALAST,
+};
+
+/* type/name */
+#define D_GOK 0
+#define D_NONE 1
+
+/* type */
+#define D_BRANCH (D_NONE+1)
+#define D_OREG (D_NONE+2)
+#define D_EXTERN (D_NONE+3) /* name */
+#define D_STATIC (D_NONE+4) /* name */
+#define D_AUTO (D_NONE+5) /* name */
+#define D_PARAM (D_NONE+6) /* name */
+#define D_CONST (D_NONE+7)
+#define D_FCONST (D_NONE+8)
+#define D_SCONST (D_NONE+9)
+#define D_HI (D_NONE+10)
+#define D_LO (D_NONE+11)
+#define D_REG (D_NONE+12)
+#define D_FREG (D_NONE+13)
+#define D_FCREG (D_NONE+14)
+#define D_MREG (D_NONE+15)
+#define D_FILE (D_NONE+16)
+#define D_OCONST (D_NONE+17)
+#define D_FILE1 (D_NONE+18)
+#define D_VCONST (D_NONE+19)
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/0l/Nt.c b/utils/0l/Nt.c
new file mode 100644
index 00000000..2efff499
--- /dev/null
+++ b/utils/0l/Nt.c
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/0l/Plan9.c b/utils/0l/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/0l/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/0l/Posix.c b/utils/0l/Posix.c
new file mode 100644
index 00000000..aa5d9551
--- /dev/null
+++ b/utils/0l/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fials if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
diff --git a/utils/0l/asm.c b/utils/0l/asm.c
new file mode 100644
index 00000000..f0ee58bf
--- /dev/null
+++ b/utils/0l/asm.c
@@ -0,0 +1,1433 @@
+#include "l.h"
+
+long OFFSET;
+/*
+long BADOFFSET = -1;
+
+ if(OFFSET <= BADOFFSET && OFFSET+4 > BADOFFSET)\
+ abort();\
+ OFFSET += 4;\
+
+ if(OFFSET == BADOFFSET)\
+ abort();\
+ OFFSET++;\
+*/
+
+void
+cput(int c)
+{
+ cbp[0] = c;
+ cbp++;
+ cbc--;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+bput(long l)
+{
+ cbp[0] = l>>24;
+ cbp[1] = l>>16;
+ cbp[2] = l>>8;
+ cbp[3] = l;
+ cbp += 4;
+ cbc -= 4;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+lput(long l)
+{
+
+ cbp[0] = l;
+ cbp[1] = l>>8;
+ cbp[2] = l>>16;
+ cbp[3] = l>>24;
+ cbp += 4;
+ cbc -= 4;
+ if(cbc <= 0)
+ cflush();
+}
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT && s->type != SLEAF)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long t;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asm\n", cputime());
+ Bflush(&bso);
+ OFFSET = HEADR;
+ seek(cout, OFFSET, 0);
+ pc = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 8;
+ }
+ if(p->pc != pc) {
+ diag("phase error %lux sb %lux\n",
+ p->pc, pc);
+ if(!debug['a'])
+ prasm(curp);
+ pc = p->pc;
+ }
+ curp = p;
+ o = oplook(p); /* could probably avoid this call */
+ if(asmout(p, o, 0)) {
+ p = p->link;
+ pc += 4;
+ }
+ pc += o->size;
+ }
+ if(debug['a'])
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ cflush();
+
+ curtext = P;
+ switch(HEADTYPE) {
+ case 0:
+ case 4:
+ OFFSET = rnd(HEADR+textsize, 4096);
+ seek(cout, OFFSET, 0);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ OFFSET = HEADR+textsize;
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ for(t = 0; t < datsize; t += sizeof(buf)-100) {
+ if(datsize-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100);
+ else
+ datblk(t, datsize-t);
+ }
+
+ symsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ case 0:
+ case 4:
+ OFFSET = rnd(HEADR+textsize, 4096)+datsize;
+ seek(cout, OFFSET, 0);
+ break;
+ case 3:
+ case 2:
+ case 1:
+ case 5:
+ case 6:
+ OFFSET = HEADR+textsize+datsize;
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ cflush();
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f header\n", cputime());
+ Bflush(&bso);
+ OFFSET = 0;
+ seek(cout, OFFSET, 0);
+ switch(HEADTYPE) {
+ case 0:
+ bput(0x160L<<16); /* magic and sections */
+ bput(0L); /* time and date */
+ bput(rnd(HEADR+textsize, 4096)+datsize);
+ bput(symsize); /* nsyms */
+ bput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ bput((0413<<16)|0437L); /* magic and version */
+ bput(rnd(HEADR+textsize, 4096)); /* sizes */
+ bput(datsize);
+ bput(bsssize);
+ bput(entryvalue()); /* va of entry */
+ bput(INITTEXT-HEADR); /* va of base of text */
+ bput(INITDAT); /* va of base of data */
+ bput(INITDAT+datsize); /* va of base of bss */
+ bput(~0L); /* gp reg mask */
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(~0L); /* gp value ?? */
+ break;
+ case 1:
+ bput(0x160L<<16); /* magic and sections */
+ bput(0L); /* time and date */
+ bput(HEADR+textsize+datsize);
+ bput(symsize); /* nsyms */
+ bput((0x38L<<16)|7L); /* size of optional hdr and flags */
+
+ bput((0407<<16)|0437L); /* magic and version */
+ bput(textsize); /* sizes */
+ bput(datsize);
+ bput(bsssize);
+ bput(entryvalue()); /* va of entry */
+ bput(INITTEXT); /* va of base of text */
+ bput(INITDAT); /* va of base of data */
+ bput(INITDAT+datsize); /* va of base of bss */
+ bput(~0L); /* gp reg mask */
+ bput(lcsize);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(~0L); /* gp value ?? */
+ bput(0L); /* complete mystery */
+ break;
+ case 2:
+ t = 22;
+ bput(((((4*t)+0)*t)+7)); /* magic */
+ bput(textsize); /* sizes */
+ bput(datsize);
+ bput(bsssize);
+ bput(symsize); /* nsyms */
+ bput(entryvalue()); /* va of entry */
+ bput(0L);
+ bput(lcsize);
+ break;
+ case 3:
+ bput((0x160L<<16)|3L); /* magic and sections */
+ bput(time(0)); /* time and date */
+ bput(HEADR+textsize+datsize);
+ bput(symsize); /* nsyms */
+ bput((0x38L<<16)|7L); /* size of optional hdr and flags */
+
+ bput((0407<<16)|0437L); /* magic and version */
+ bput(textsize); /* sizes */
+ bput(datsize);
+ bput(bsssize);
+ bput(entryvalue()); /* va of entry */
+ bput(INITTEXT); /* va of base of text */
+ bput(INITDAT); /* va of base of data */
+ bput(INITDAT+datsize); /* va of base of bss */
+ bput(~0L); /* gp reg mask */
+ bput(lcsize);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(~0L); /* gp value ?? */
+
+ strnput(".text", 8); /* text segment */
+ bput(INITTEXT); /* address */
+ bput(INITTEXT);
+ bput(textsize);
+ bput(HEADR);
+ bput(0L);
+ bput(HEADR+textsize+datsize+symsize);
+ bput(lcsize); /* line number size */
+ bput(0x20L); /* flags */
+
+ strnput(".data", 8); /* data segment */
+ bput(INITDAT); /* address */
+ bput(INITDAT);
+ bput(datsize);
+ bput(HEADR+textsize);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0x40L); /* flags */
+
+ strnput(".bss", 8); /* bss segment */
+ bput(INITDAT+datsize); /* address */
+ bput(INITDAT+datsize);
+ bput(bsssize);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0x80L); /* flags */
+ break;
+ case 4:
+
+ bput((0x160L<<16)|3L); /* magic and sections */
+ bput(time(0)); /* time and date */
+ bput(rnd(HEADR+textsize, 4096)+datsize);
+ bput(symsize); /* nsyms */
+ bput((0x38L<<16)|7L); /* size of optional hdr and flags */
+
+ bput((0413<<16)|01012L); /* magic and version */
+ bput(textsize); /* sizes */
+ bput(datsize);
+ bput(bsssize);
+ bput(entryvalue()); /* va of entry */
+ bput(INITTEXT); /* va of base of text */
+ bput(INITDAT); /* va of base of data */
+ bput(INITDAT+datsize); /* va of base of bss */
+ bput(~0L); /* gp reg mask */
+ bput(lcsize);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(~0L); /* gp value ?? */
+
+ strnput(".text", 8); /* text segment */
+ bput(INITTEXT); /* address */
+ bput(INITTEXT);
+ bput(textsize);
+ bput(HEADR);
+ bput(0L);
+ bput(HEADR+textsize+datsize+symsize);
+ bput(lcsize); /* line number size */
+ bput(0x20L); /* flags */
+
+ strnput(".data", 8); /* data segment */
+ bput(INITDAT); /* address */
+ bput(INITDAT);
+ bput(datsize);
+ bput(rnd(HEADR+textsize, 4096)); /* sizes */
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0x40L); /* flags */
+
+ strnput(".bss", 8); /* bss segment */
+ bput(INITDAT+datsize); /* address */
+ bput(INITDAT+datsize);
+ bput(bsssize);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0L);
+ bput(0x80L); /* flags */
+ break;
+ case 5:
+ strnput("\177ELF", 4); /* e_ident */
+ cput(1); /* class = 32 bit */
+ cput(2); /* data = MSB */
+ cput(1); /* version = CURRENT */
+ strnput("", 9);
+ bput((2L<<16)|8L); /* type = EXEC; machine = MIPS */
+ bput(1L); /* version = CURRENT */
+ bput(entryvalue()); /* entry vaddr */
+ bput(52L); /* offset to first phdr */
+ bput(0L); /* offset to first shdr */
+ bput(0L); /* flags = MIPS */
+ bput((52L<<16)|32L); /* Ehdr & Phdr sizes*/
+ bput((3L<<16)|0L); /* # Phdrs & Shdr size */
+ bput((0L<<16)|0L); /* # Shdrs & shdr string size */
+
+ bput(1L); /* text - type = PT_LOAD */
+ bput(0L); /* file offset */
+ bput(INITTEXT-HEADR); /* vaddr */
+ bput(INITTEXT-HEADR); /* paddr */
+ bput(HEADR+textsize); /* file size */
+ bput(HEADR+textsize); /* memory size */
+ bput(0x05L); /* protections = RX */
+ bput(0x10000L); /* alignment code?? */
+
+ bput(1L); /* data - type = PT_LOAD */
+ bput(HEADR+textsize); /* file offset */
+ bput(INITDAT); /* vaddr */
+ bput(INITDAT); /* paddr */
+ bput(datsize); /* file size */
+ bput(datsize+bsssize); /* memory size */
+ bput(0x06L); /* protections = RW */
+ bput(0x10000L); /* alignment code?? */
+
+ bput(0L); /* data - type = PT_NULL */
+ bput(HEADR+textsize+datsize); /* file offset */
+ bput(0L);
+ bput(0L);
+ bput(symsize); /* symbol table size */
+ bput(lcsize); /* line number size */
+ bput(0x04L); /* protections = R */
+ bput(0x04L); /* alignment code?? */
+ break;
+ case 6:
+ t = 22;
+ bput(((((4*t)+0)*t)+7)); /* magic */
+ bput(textsize); /* sizes */
+ bput(datsize);
+ bput(bsssize);
+ bput(symsize); /* nsyms */
+ bput(entryvalue()); /* va of entry */
+ bput(0L);
+ bput(lcsize);
+ break;
+ }
+ cflush();
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s; s++){
+ cput(*s);
+ n--;
+ }
+ for(; n > 0; n--)
+ cput(0);
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = (uchar*)buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+nopstat(char *f, Count *c)
+{
+ if(c->outof)
+ Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
+ c->outof - c->count, c->outof,
+ (double)(c->outof - c->count)/c->outof);
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->cond) {
+ s = p->from.sym;
+ if(s->type != STEXT && s->type != SLEAF)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+ else
+ putsymb(s->name, 'L', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+8, 0);
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+putsymb(char *s, int t, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ bput(v);
+ if(ver)
+ t += 'a' - 'A';
+ cput(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ cput(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ cput(s[i]);
+ cput(s[i+1]);
+ }
+ cput(0);
+ cput(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ cput(s[i]);
+ cput(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, s);
+ }
+}
+
+#define MINLC 4
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ cput(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ cput(0); /* 0 vv +lc */
+ cput(s>>24);
+ cput(s>>16);
+ cput(s>>8);
+ cput(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ cput(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ cput(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ cput(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j, d;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->reg;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization\n");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ default:
+ diag("unknown mode in initialization\n%P\n", p);
+ break;
+
+ case D_VCONST:
+ cast = (char*)p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(p->to.ieee);
+ cast = (char*)&fl;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.sval[i];
+ l++;
+ }
+ break;
+
+ case D_CONST:
+ d = p->to.offset;
+ if(p->to.sym) {
+ if(p->to.sym->type == STEXT ||
+ p->to.sym->type == SLEAF)
+ d += p->to.sym->value;
+ if(p->to.sym->type == SDATA)
+ d += p->to.sym->value + INITDAT;
+ if(p->to.sym->type == SBSS)
+ d += p->to.sym->value + INITDAT;
+ }
+ cast = (char*)&d;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P\n", c, i, curp);
+ break;
+ case 1:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+#define OP_RRR(op,r1,r2,r3)\
+ (op|(((r1)&31L)<<16)|(((r2)&31L)<<21)|(((r3)&31L)<<11))
+#define OP_IRR(op,i,r2,r3)\
+ (op|((i)&0xffffL)|(((r2)&31L)<<21)|(((r3)&31L)<<16))
+#define OP_SRR(op,s,r2,r3)\
+ (op|(((s)&31L)<<6)|(((r2)&31L)<<16)|(((r3)&31L)<<11))
+#define OP_FRRR(op,r1,r2,r3)\
+ (op|(((r1)&31L)<<16)|(((r2)&31L)<<11)|(((r3)&31L)<<6))
+#define OP_JMP(op,i)\
+ ((op)|((i)&0x3ffffffL))
+
+#define OP(x,y)\
+ (((x)<<3)|((y)<<0))
+#define SP(x,y)\
+ (((x)<<29)|((y)<<26))
+#define BCOND(x,y)\
+ (((x)<<19)|((y)<<16))
+#define MMU(x,y)\
+ (SP(2,0)|(16<<21)|((x)<<3)|((y)<<0))
+#define FPF(x,y)\
+ (SP(2,1)|(16<<21)|((x)<<3)|((y)<<0))
+#define FPD(x,y)\
+ (SP(2,1)|(17<<21)|((x)<<3)|((y)<<0))
+#define FPW(x,y)\
+ (SP(2,1)|(20<<21)|((x)<<3)|((y)<<0))
+#define FPV(x,y)\
+ (SP(2,1)|(21<<21)|((x)<<3)|((y)<<0))
+
+int
+asmout(Prog *p, Optab *o, int aflag)
+{
+ long o1, o2, o3, o4, o5, o6, o7, v;
+ Prog *ct;
+ int r, a;
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ o6 = 0;
+ o7 = 0;
+ switch(o->type) {
+ default:
+ diag("unknown type %d\n", o->type);
+ if(!debug['a'])
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ if(aflag) {
+ if(p->link) {
+ if(p->as == ATEXT) {
+ ct = curtext;
+ o2 = autosize;
+ curtext = p;
+ autosize = p->to.offset + 8;
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ curtext = ct;
+ autosize = o2;
+ } else
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ }
+ return o1;
+ }
+ break;
+
+ case 1: /* mov[v] r1,r2 ==> OR r1,r0,r2 */
+ o1 = OP_RRR(oprrr(AOR), p->from.reg, REGZERO, p->to.reg);
+ break;
+
+ case 2: /* add/sub r1,[r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 3: /* mov $soreg, r ==> or/add $i,o,r */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ a = AADDU;
+ if(o->a1 == C_ANDCON)
+ a = AOR;
+ o1 = OP_IRR(opirr(a), v, r, p->to.reg);
+ break;
+
+ case 4: /* add $scon,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(opirr(p->as), v, r, p->to.reg);
+ break;
+
+ case 5: /* syscall */
+ if(aflag)
+ return 0;
+ o1 = oprrr(p->as);
+ break;
+
+ case 6: /* beq r1,[r2],sbra */
+ if(aflag)
+ return 0;
+ if(!debug['Y'] && p->link && p->cond && isnop(p->link)) {
+ nop.branch.count--;
+ nop.branch.outof--;
+ nop.jump.outof++;
+ o2 = asmout(p->cond, oplook(p->cond), 1);
+ if(o2) {
+ if(p->cond == P)
+ v = -4 >> 2;
+ else
+ v = (p->cond->pc+4 - pc-4) >> 2;
+ if(((v << 16) >> 16) != v)
+ diag("short branch too far: %d\n%P\n", v, p);
+ o1 = OP_IRR(opirr(p->as+ALAST), v, p->from.reg, p->reg);
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n",
+ p->pc, o1, o2, p);
+ lput(o1);
+ lput(o2);
+ return 1;
+ }
+ }
+ if(p->cond == P)
+ v = -4 >> 2;
+ else
+ v = (p->cond->pc - pc-4) >> 2;
+ if(((v << 16) >> 16) != v)
+ diag("short branch too far: %d\n%P\n", v, p);
+ o1 = OP_IRR(opirr(p->as), v, p->from.reg, p->reg);
+ break;
+
+ case 7: /* mov r, soreg ==> sw o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = OP_IRR(opirr(p->as), v, r, p->from.reg);
+ break;
+
+ case 8: /* mov soreg, r ==> lw o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(p->as+ALAST), v, r, p->to.reg);
+ break;
+
+ case 9: /* asl r1,[r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg);
+ break;
+
+ case 10: /* add $con,[r1],r2 ==> mov $con,t; add t,[r1],r2 */
+ v = regoff(&p->from);
+ r = AOR;
+ if(v < 0)
+ r = AADDU;
+ o1 = OP_IRR(opirr(r), v, 0, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 11: /* jmp lbra */
+ if(aflag)
+ return 0;
+ if(p->cond == P)
+ v = p->pc >> 2;
+ else
+ v = p->cond->pc >> 2;
+ o1 = OP_JMP(opirr(p->as), v);
+ if(!debug['Y'] && p->link && p->cond && isnop(p->link)) {
+ nop.branch.count--;
+ nop.branch.outof--;
+ nop.jump.outof++;
+ o2 = asmout(p->cond, oplook(p->cond), 1);
+ if(o2) {
+ o1 += 1;
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n",
+ p->pc, o1, o2, p);
+ lput(o1);
+ lput(o2);
+ return 1;
+ }
+ }
+ break;
+
+ case 12: /* movbs r,r */
+ v = 16;
+ if(p->as == AMOVB)
+ v = 24;
+ o1 = OP_SRR(opirr(ASLL), v, p->from.reg, p->to.reg);
+ o2 = OP_SRR(opirr(ASRA), v, p->to.reg, p->to.reg);
+ break;
+
+ case 13: /* movbu r,r */
+ if(p->as == AMOVBU)
+ o1 = OP_IRR(opirr(AAND), 0xffL, p->from.reg, p->to.reg);
+ else
+ o1 = OP_IRR(opirr(AAND), 0xffffL, p->from.reg, p->to.reg);
+ break;
+
+ case 14: /* movwu r,r */
+ v = 32-32;
+ o1 = OP_SRR(opirr(ASLLV+ALAST), v, p->from.reg, p->to.reg);
+ o2 = OP_SRR(opirr(ASRLV+ALAST), v, p->to.reg, p->to.reg);
+ break;
+
+ case 16: /* sll $c,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ if(v >= 32)
+ o1 = OP_SRR(opirr(p->as+ALAST), v-32, r, p->to.reg);
+ else
+ o1 = OP_SRR(opirr(p->as), v, r, p->to.reg);
+ break;
+
+ case 18: /* jmp [r1],0(r2) */
+ if(aflag)
+ return 0;
+ r = p->reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = OP_RRR(oprrr(p->as), 0, p->to.reg, r);
+ break;
+
+ case 19: /* mov $lcon,r ==> lu+or */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg);
+ o2 = OP_IRR(opirr(AOR), v, p->to.reg, p->to.reg);
+ break;
+
+ case 20: /* mov lohi,r */
+ r = OP(2,0); /* mfhi */
+ if(p->from.type == D_LO)
+ r = OP(2,2); /* mflo */
+ o1 = OP_RRR(r, REGZERO, REGZERO, p->to.reg);
+ break;
+
+ case 21: /* mov r,lohi */
+ r = OP(2,1); /* mthi */
+ if(p->to.type == D_LO)
+ r = OP(2,3); /* mtlo */
+ o1 = OP_RRR(r, REGZERO, p->from.reg, REGZERO);
+ break;
+
+ case 22: /* mul r1,r2 */
+ o1 = OP_RRR(oprrr(p->as), p->from.reg, p->reg, REGZERO);
+ break;
+
+ case 23: /* add $lcon,r1,r2 ==> lu+or+add */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ diag("cant synthesize large constant\n%P\n", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 24: /* mov $ucon,,r ==> lu r */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg);
+ break;
+
+ case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 26: /* mov $lsext/auto/oreg,,r2 ==> lu+or+add */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP)
+ diag("cant synthesize large constant\n%P\n", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o3 = OP_RRR(oprrr(AADDU), REGTMP, r, p->to.reg);
+ break;
+
+ case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ if(p->as == AMOVD)
+ o4 = opirr(AMOVD+ALAST);
+ else
+ o4 = opirr(AMOVF+ALAST);
+ switch(o->size) {
+ case 16:
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(o4, 0, REGTMP, p->to.reg);
+ break;
+ case 4:
+ o1 = OP_IRR(o4, v, r, p->to.reg);
+ break;
+ }
+ break;
+
+ case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ if(p->as == AMOVD)
+ o4 = opirr(AMOVD);
+ else
+ o4 = opirr(AMOVF);
+ switch(o->size) {
+ case 16:
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P\n", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(o4, 0, REGTMP, p->from.reg);
+ break;
+ case 4:
+ o1 = OP_IRR(o4, v, r, p->from.reg);
+ break;
+ }
+ break;
+
+ case 30: /* movw r,fr */
+ r = SP(2,1)|(4<<21); /* mtc1 */
+ o1 = OP_RRR(r, p->from.reg, 0, p->to.reg);
+ break;
+
+ case 31: /* movw fr,r */
+ r = SP(2,1)|(0<<21); /* mfc1 */
+ o1 = OP_RRR(r, p->to.reg, 0, p->from.reg);
+ break;
+
+ case 32: /* fadd fr1,[fr2],fr3 */
+ r = p->reg;
+ if(r == NREG)
+ o1 = OP_FRRR(oprrr(p->as), p->from.reg, p->to.reg, p->to.reg);
+ else
+ o1 = OP_FRRR(oprrr(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 33: /* fabs fr1,fr3 */
+ o1 = OP_FRRR(oprrr(p->as), 0, p->from.reg, p->to.reg);
+ break;
+
+ case 34: /* mov $con,fr ==> or/add $i,r,r2 */
+ v = regoff(&p->from);
+ r = AADDU;
+ if(o->a1 == C_ANDCON)
+ r = AOR;
+ o1 = OP_IRR(opirr(r), v, 0, REGTMP);
+ o2 = OP_RRR(SP(2,1)|(4<<21), REGTMP, 0, p->to.reg); /* mtc1 */
+ break;
+
+ case 35: /* mov r,lext/luto/oreg ==> sw o(r) */
+ /*
+ * the lowbits of the constant cannot
+ * be moved into the offset of the load
+ * because the mips 4000 in 64-bit mode
+ * does a 64-bit add and it will screw up.
+ */
+ v = regoff(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P\n", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(p->as), 0, REGTMP, p->from.reg);
+ break;
+
+ case 36: /* mov lext/lauto/lreg,r ==> lw o(r30) */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P\n", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(p->as+ALAST), 0, REGTMP, p->to.reg);
+ break;
+
+ case 37: /* movw r,mr */
+ r = SP(2,0)|(4<<21); /* mtc0 */
+ if(p->as == AMOVV)
+ r = SP(2,0)|(5<<21); /* dmtc0 */
+ o1 = OP_RRR(r, p->from.reg, 0, p->to.reg);
+ break;
+
+ case 38: /* movw mr,r */
+ r = SP(2,0)|(0<<21); /* mfc0 */
+ if(p->as == AMOVV)
+ r = SP(2,0)|(1<<21); /* dmfc0 */
+ o1 = OP_RRR(r, p->to.reg, 0, p->from.reg);
+ break;
+
+ case 39: /* rfe ==> jmp+rfe */
+ if(aflag)
+ return 0;
+ o1 = OP_RRR(oprrr(AJMP), 0, p->to.reg, REGZERO);
+ o2 = oprrr(p->as);
+ break;
+
+ case 40: /* word */
+ if(aflag)
+ return 0;
+ o1 = regoff(&p->to);
+ break;
+
+ case 41: /* movw r,fcr */
+ o1 = OP_RRR(SP(2,1)|(2<<21), REGZERO, 0, p->to.reg); /* mfcc1 */
+ o2 = OP_RRR(SP(2,1)|(6<<21), p->from.reg, 0, p->to.reg);/* mtcc1 */
+ break;
+
+ case 42: /* movw fcr,r */
+ o1 = OP_RRR(SP(2,1)|(2<<21), p->to.reg, 0, p->from.reg);/* mfcc1 */
+ break;
+
+ case 47: /* movv r,fr */
+ r = SP(2,1)|(5<<21); /* dmtc1 */
+ o1 = OP_RRR(r, p->from.reg, 0, p->to.reg);
+ break;
+
+ case 48: /* movv fr,r */
+ r = SP(2,1)|(1<<21); /* dmfc1 */
+ o1 = OP_RRR(r, p->to.reg, 0, p->from.reg);
+ break;
+ }
+ if(aflag)
+ return o1;
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ lput(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ lput(o1);
+ lput(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ lput(o5);
+ break;
+
+ case 28:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, o6, o7, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ lput(o5);
+ lput(o6);
+ lput(o7);
+ break;
+ }
+ return 0;
+}
+
+int
+isnop(Prog *p)
+{
+ if(p->as != ANOR)
+ return 0;
+ if(p->reg != REGZERO && p->reg != NREG)
+ return 0;
+ if(p->from.type != D_REG || p->from.reg != REGZERO)
+ return 0;
+ if(p->to.type != D_REG || p->to.reg != REGZERO)
+ return 0;
+ return 1;
+}
+
+long
+oprrr(int a)
+{
+ switch(a) {
+ case AADD: return OP(4,0);
+ case AADDU: return OP(4,1);
+ case ASGT: return OP(5,2);
+ case ASGTU: return OP(5,3);
+ case AAND: return OP(4,4);
+ case AOR: return OP(4,5);
+ case AXOR: return OP(4,6);
+ case ASUB: return OP(4,2);
+ case ASUBU: return OP(4,3);
+ case ANOR: return OP(4,7);
+ case ASLL: return OP(0,4);
+ case ASRL: return OP(0,6);
+ case ASRA: return OP(0,7);
+
+ case ASLLV: return OP(2,4);
+ case ASRLV: return OP(2,6);
+ case ASRAV: return OP(2,7);
+
+ case AADDV: return OP(5,4);
+ case AADDVU: return OP(5,5);
+ case ASUBV: return OP(5,6);
+ case ASUBVU: return OP(5,7);
+ case AREM:
+ case ADIV: return OP(3,2);
+ case AREMU:
+ case ADIVU: return OP(3,3);
+ case AMUL: return OP(3,0);
+ case AMULU: return OP(3,1);
+
+ case AREMV:
+ case ADIVV: return OP(3,6);
+ case AREMVU:
+ case ADIVVU: return OP(3,7);
+ case AMULV: return OP(3,4);
+ case AMULVU: return OP(3,5);
+
+ case AJMP: return OP(1,0);
+ case AJAL: return OP(1,1);
+
+ case ABREAK: return OP(1,5);
+ case ASYSCALL: return OP(1,4);
+ case ATLBP: return MMU(1,0);
+ case ATLBR: return MMU(0,1);
+ case ATLBWI: return MMU(0,2);
+ case ATLBWR: return MMU(0,6);
+ case ARFE: return MMU(2,0);
+
+ case ADIVF: return FPF(0,3);
+ case ADIVD: return FPD(0,3);
+ case AMULF: return FPF(0,2);
+ case AMULD: return FPD(0,2);
+ case ASUBF: return FPF(0,1);
+ case ASUBD: return FPD(0,1);
+ case AADDF: return FPF(0,0);
+ case AADDD: return FPD(0,0);
+
+ case ATRUNCFV: return FPF(1,1);
+ case ATRUNCDV: return FPD(1,1);
+ case ATRUNCFW: return FPF(1,5);
+ case ATRUNCDW: return FPD(1,5);
+ case AMOVFV: return FPF(4,5);
+ case AMOVDV: return FPD(4,5);
+ case AMOVVF: return FPV(4,0);
+ case AMOVVD: return FPV(4,1);
+
+ case AMOVFW: return FPF(4,4);
+ case AMOVDW: return FPD(4,4);
+ case AMOVWF: return FPW(4,0);
+ case AMOVDF: return FPD(4,0);
+ case AMOVWD: return FPW(4,1);
+ case AMOVFD: return FPF(4,1);
+ case AABSF: return FPF(0,5);
+ case AABSD: return FPD(0,5);
+ case AMOVF: return FPF(0,6);
+ case AMOVD: return FPD(0,6);
+ case ANEGF: return FPF(0,7);
+ case ANEGD: return FPD(0,7);
+
+ case ACMPEQF: return FPF(6,2);
+ case ACMPEQD: return FPD(6,2);
+ case ACMPGTF: return FPF(7,4);
+ case ACMPGTD: return FPD(7,4);
+ case ACMPGEF: return FPF(7,6);
+ case ACMPGED: return FPD(7,6);
+ }
+ if(a >= ALAST)
+ diag("bad rrr %A+ALAST", a-ALAST);
+ else
+ diag("bad rrr %A", a);
+ return 0;
+}
+
+long
+opirr(int a)
+{
+ switch(a) {
+ case AADD: return SP(1,0);
+ case AADDU: return SP(1,1);
+ case ASGT: return SP(1,2);
+ case ASGTU: return SP(1,3);
+ case AAND: return SP(1,4);
+ case AOR: return SP(1,5);
+ case AXOR: return SP(1,6);
+ case ALAST: return SP(1,7); /* lui */
+ case ASLL: return OP(0,0);
+ case ASRL: return OP(0,2);
+ case ASRA: return OP(0,3);
+
+ case AADDV: return SP(3,0);
+ case AADDVU: return SP(3,1);
+
+ case AJMP: return SP(0,2);
+ case AJAL: return SP(0,3);
+ case ABEQ: return SP(0,4);
+ case ABEQ+ALAST: return SP(2,4); /* likely */
+ case ABNE: return SP(0,5);
+ case ABNE+ALAST: return SP(2,5); /* likely */
+
+ case ABGEZ: return SP(0,1)|BCOND(0,1);
+ case ABGEZ+ALAST: return SP(0,1)|BCOND(0,3); /* likely */
+ case ABGEZAL: return SP(0,1)|BCOND(2,1);
+ case ABGEZAL+ALAST: return SP(0,1)|BCOND(2,3); /* likely */
+ case ABGTZ: return SP(0,7);
+ case ABGTZ+ALAST: return SP(2,7); /* likely */
+ case ABLEZ: return SP(0,6);
+ case ABLEZ+ALAST: return SP(2,6); /* likely */
+ case ABLTZ: return SP(0,1)|BCOND(0,0);
+ case ABLTZ+ALAST: return SP(0,1)|BCOND(0,2); /* likely */
+ case ABLTZAL: return SP(0,1)|BCOND(2,0);
+ case ABLTZAL+ALAST: return SP(0,1)|BCOND(2,2); /* likely */
+
+ case ABFPT: return SP(2,1)|(257<<16);
+ case ABFPT+ALAST: return SP(2,1)|(259<<16); /* likely */
+ case ABFPF: return SP(2,1)|(256<<16);
+ case ABFPF+ALAST: return SP(2,1)|(258<<16); /* likely */
+
+ case AMOVB:
+ case AMOVBU: return SP(5,0);
+ case AMOVH:
+ case AMOVHU: return SP(5,1);
+ case AMOVW: return SP(5,3);
+ case AMOVV: return SP(7,7);
+ case AMOVF: return SP(7,1);
+ case AMOVD: return SP(7,5);
+ case AMOVWL: return SP(5,2);
+ case AMOVWR: return SP(5,6);
+ case AMOVVL: return SP(5,4);
+ case AMOVVR: return SP(5,5);
+
+ case ABREAK: return SP(5,7);
+
+ case AMOVWL+ALAST: return SP(4,2);
+ case AMOVWR+ALAST: return SP(4,6);
+ case AMOVVL+ALAST: return SP(3,2);
+ case AMOVVR+ALAST: return SP(3,3);
+ case AMOVB+ALAST: return SP(4,0);
+ case AMOVBU+ALAST: return SP(4,4);
+ case AMOVH+ALAST: return SP(4,1);
+ case AMOVHU+ALAST: return SP(4,5);
+ case AMOVW+ALAST: return SP(4,3);
+ case AMOVV+ALAST: return SP(6,7);
+ case AMOVF+ALAST: return SP(6,1);
+ case AMOVD+ALAST: return SP(6,5);
+
+ case ASLLV: return OP(7,0);
+ case ASRLV: return OP(7,2);
+ case ASRAV: return OP(7,3);
+ case ASLLV+ALAST: return OP(7,4);
+ case ASRLV+ALAST: return OP(7,6);
+ case ASRAV+ALAST: return OP(7,7);
+ }
+ if(a >= ALAST)
+ diag("bad irr %A+ALAST", a-ALAST);
+ else
+ diag("bad irr %A", a);
+ return 0;
+}
diff --git a/utils/0l/enam.c b/utils/0l/enam.c
new file mode 100644
index 00000000..5fd1a351
--- /dev/null
+++ b/utils/0l/enam.c
@@ -0,0 +1,122 @@
+char* anames[] =
+{
+ "XXX",
+ "ABSD",
+ "ABSF",
+ "ABSW",
+ "ADD",
+ "ADDD",
+ "ADDF",
+ "ADDU",
+ "ADDW",
+ "AND",
+ "BEQ",
+ "BFPF",
+ "BFPT",
+ "BGEZ",
+ "BGEZAL",
+ "BGTZ",
+ "BLEZ",
+ "BLTZ",
+ "BLTZAL",
+ "BNE",
+ "BREAK",
+ "CMPEQD",
+ "CMPEQF",
+ "CMPGED",
+ "CMPGEF",
+ "CMPGTD",
+ "CMPGTF",
+ "DATA",
+ "DIV",
+ "DIVD",
+ "DIVF",
+ "DIVU",
+ "DIVW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "JAL",
+ "JMP",
+ "MOVB",
+ "MOVBU",
+ "MOVD",
+ "MOVDF",
+ "MOVDW",
+ "MOVF",
+ "MOVFD",
+ "MOVFW",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MOVWD",
+ "MOVWF",
+ "MOVWL",
+ "MOVWR",
+ "MUL",
+ "MULD",
+ "MULF",
+ "MULU",
+ "MULW",
+ "NAME",
+ "NEGD",
+ "NEGF",
+ "NEGW",
+ "NOP",
+ "NOR",
+ "OR",
+ "REM",
+ "REMU",
+ "RET",
+ "RFE",
+ "SGT",
+ "SGTU",
+ "SLL",
+ "SRA",
+ "SRL",
+ "SUB",
+ "SUBD",
+ "SUBF",
+ "SUBU",
+ "SUBW",
+ "SYSCALL",
+ "TEXT",
+ "TLBP",
+ "TLBR",
+ "TLBWI",
+ "TLBWR",
+ "WORD",
+ "XOR",
+ "END",
+ "MOVV",
+ "MOVVL",
+ "MOVVR",
+ "SLLV",
+ "SRAV",
+ "SRLV",
+ "DIVV",
+ "DIVVU",
+ "REMV",
+ "REMVU",
+ "MULV",
+ "MULVU",
+ "ADDV",
+ "ADDVU",
+ "SUBV",
+ "SUBVU",
+ "DYNT",
+ "INIT",
+ "BCASE",
+ "CASE",
+ "TRUNCFV",
+ "TRUNCDV",
+ "TRUNCFW",
+ "TRUNCDW",
+ "MOVWU",
+ "MOVFV",
+ "MOVDV",
+ "MOVVF",
+ "MOVVD",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/0l/l.h b/utils/0l/l.h
new file mode 100644
index 00000000..6b027814
--- /dev/null
+++ b/utils/0l/l.h
@@ -0,0 +1,329 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../vc/v.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Adr Adr;
+typedef struct Sym Sym;
+typedef struct Autom Auto;
+typedef struct Prog Prog;
+typedef struct Optab Optab;
+typedef struct Oprang Oprang;
+typedef uchar Opcross[32][2][32];
+typedef struct Count Count;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ long u0offset;
+ char* u0sval;
+ Ieee* u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ char type;
+ char reg;
+ char name;
+ char class;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0regused;
+ Prog* u0forwd;
+ } u0;
+ Prog* cond;
+ Prog* link;
+ long pc;
+ long line;
+ uchar mark;
+ uchar optab;
+ char as;
+ char reg;
+};
+
+#define regused u0.u0regused
+#define forwd u0.u0forwd
+
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ long value;
+ Sym* link;
+};
+struct Autom
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Optab
+{
+ char as;
+ char a1;
+ char a2;
+ char a3;
+ char type;
+ char size;
+ char param;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+struct Count
+{
+ long count;
+ long outof;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SLEAF,
+ SFILE,
+ SCONST,
+
+ C_NONE = 0,
+ C_REG,
+ C_FREG,
+ C_FCREG,
+ C_MREG,
+ C_HI,
+ C_LO,
+ C_ZCON,
+ C_SCON,
+ C_ADD0CON,
+ C_AND0CON,
+ C_ADDCON,
+ C_ANDCON,
+ C_UCON,
+ C_LCON,
+ C_SACON,
+ C_SECON,
+ C_LACON,
+ C_LECON,
+ C_SBRA,
+ C_LBRA,
+ C_SAUTO,
+ C_SEXT,
+ C_LAUTO,
+ C_LEXT,
+ C_ZOREG,
+ C_SOREG,
+ C_LOREG,
+ C_GOK,
+
+ NSCHED = 20,
+
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+ SYNC = 1<<3,
+ BRANCH = 1<<4,
+ LOAD = 1<<5,
+ FCMP = 1<<6,
+ NOSCHED = 1<<7,
+
+ BIG = 32766,
+ STRINGSZ = 200,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+};
+
+EXTERN union
+{
+ struct
+ {
+ char obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+EXTERN long HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN long INITDAT; /* data location */
+EXTERN long INITRND; /* data round above text location */
+EXTERN long INITTEXT; /* text location */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN long autosize;
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN uchar* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi4[4];
+EXTERN char fnuxi8[8];
+EXTERN char* noname;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long instoffset;
+EXTERN Opcross opcross[10];
+EXTERN Oprang oprange[ALAST];
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN uchar repop[ALAST];
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN char xcmp[32][32];
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+EXTERN struct
+{
+ Count branch;
+ Count fcmp;
+ Count load;
+ Count mfrom;
+ Count page;
+ Count jump;
+} nop;
+
+extern char* anames[];
+extern Optab optab[];
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Nconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int aclass(Adr*);
+void addhist(long, int);
+void addnop(Prog*);
+void append(Prog*, Prog*);
+void asmb(void);
+void asmlc(void);
+int asmout(Prog*, Optab*, int);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void buildrep(int, int);
+void cflush(void);
+int cmp(int, int);
+int compound(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+long entryvalue(void);
+void errorexit(void);
+void exchange(Prog*);
+int find1(long, int);
+void follow(void);
+void gethunk(void);
+void histtoauto(void);
+vlong ieeedtov(Ieee*);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+int isnop(Prog*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void mkfwd(void);
+void* mysbrk(ulong);
+void names(void);
+void nocache(Prog*);
+void noops(void);
+void nuxiinit(void);
+void objfile(char*);
+int ocmp(const void*, const void*);
+long opirr(int);
+Optab* oplook(Prog*);
+long oprrr(int);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+void putsymb(char*, int, long, int);
+long regoff(Adr*);
+int relinv(int);
+long rnd(long, long);
+void sched(Prog*, Prog*);
+void span(void);
+void strnput(char*, int);
+void undef(void);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+void xfol(Prog*);
+void nopstat(char*, Count*);
diff --git a/utils/0l/list.c b/utils/0l/list.c
new file mode 100644
index 00000000..9261bc8e
--- /dev/null
+++ b/utils/0l/list.c
@@ -0,0 +1,277 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ if(a == ADATA || a == ADYNT || a == AINIT)
+ sprint(str, "(%ld) %A %D/%d,%D",
+ p->line, a, &p->from, p->reg, &p->to);
+ else{
+ s = str;
+ s += sprint(s, "(%ld)", p->line);
+ if(p->mark & NOSCHED)
+ s += sprint(s, "*");
+ if(p->reg == NREG)
+ sprint(s, " %A %D,%D",
+ a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(s, " %A %D,R%d,%D",
+ a, &p->from, p->reg, &p->to);
+ else
+ sprint(s, " %A %D,F%d,%D",
+ a, &p->from, p->reg, &p->to);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ long v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OCONST:
+ sprint(str, "$*$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_MREG:
+ sprint(str, "M%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCREG:
+ sprint(str, "FC%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_LO:
+ sprint(str, "LO");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(LO)(REG)", a);
+ break;
+
+ case D_HI:
+ sprint(str, "HI");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(HI)(REG)", a);
+ break;
+
+ case D_BRANCH: /* botch */
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(v >= INITTEXT)
+ v -= INITTEXT-HEADR;
+ if(a->sym != S)
+ sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5lux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%ld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%e", ieeedtod(a->ieee));
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(s == S)
+ sprint(str, "%ld(SB)", a->offset);
+ else
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ if(s == S)
+ sprint(str, "<>+%ld(SB)", a->offset);
+ else
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ if(s == S)
+ sprint(str, "%ld(SP)", a->offset);
+ else
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ if(s == S)
+ sprint(str, "%ld(FP)", a->offset);
+ else
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(long); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/0l/mkfile b/utils/0l/mkfile
new file mode 100644
index 00000000..3001002b
--- /dev/null
+++ b/utils/0l/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=0l
+OFILES=\
+ asm.$O\
+ list.$O\
+ noop.$O\
+ sched.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../vc/v.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I ../include
+
+enam.$O: ../0c/enam.c
+ $CC $CFLAGS ../0c/enam.c
diff --git a/utils/0l/noop.c b/utils/0l/noop.c
new file mode 100644
index 00000000..21998947
--- /dev/null
+++ b/utils/0l/noop.c
@@ -0,0 +1,420 @@
+#include "l.h"
+
+void
+noops(void)
+{
+ Prog *p, *p1, *q, *q1;
+ int o, curframe, curbecome, maxbecome;
+
+ /*
+ * find leaf subroutines
+ * become sizes
+ * frame sizes
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+
+ q = P;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == D_OREG && p->to.reg == REGSP)
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ curtext = p;
+ break;
+
+ /* too hard, just leave alone */
+ case AMOVW:
+ case AMOVV:
+ if(p->to.type == D_FCREG ||
+ p->to.type == D_MREG) {
+ p->mark |= LABEL|SYNC;
+ break;
+ }
+ if(p->from.type == D_FCREG ||
+ p->from.type == D_MREG) {
+ p->mark |= LABEL|SYNC;
+ addnop(p);
+ addnop(p);
+ nop.mfrom.count += 2;
+ nop.mfrom.outof += 2;
+ break;
+ }
+ break;
+
+ /* too hard, just leave alone */
+ case ACASE:
+ case ASYSCALL:
+ case AWORD:
+ case ATLBWR:
+ case ATLBWI:
+ case ATLBP:
+ case ATLBR:
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ANOR:
+ if(p->to.type == D_REG && p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ARET:
+ /* special form of RET is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+
+ if(p->link != P)
+ p->link->mark |= LABEL;
+ break;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ case ABCASE:
+ p->mark |= LABEL|SYNC;
+ goto dstlab;
+
+ case ABGEZAL:
+ case ABLTZAL:
+ case AJAL:
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+
+ case AJMP:
+ case ABEQ:
+ case ABGEZ:
+ case ABGTZ:
+ case ABLEZ:
+ case ABLTZ:
+ case ABNE:
+ case ABFPT:
+ case ABFPF:
+ p->mark |= BRANCH;
+
+ dstlab:
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != P)
+ q1->mark |= LABEL;
+ break;
+ }
+ q = p;
+ }
+
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+ case AJAL:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ o = maxbecome - curtext->from.sym->frame;
+ if(o <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += o;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, o);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ curtext = p;
+ autosize = p->to.offset + 8;
+ if(autosize <= 8)
+ if(curtext->mark & LEAF) {
+ p->to.offset = -8;
+ autosize = 0;
+ }
+
+ q = p;
+ if(autosize) {
+ if(autosize & 7)
+ Bprint(&bso, "odd stack in: %s\n",
+ curtext->from.sym->name);
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = -autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ } else
+ if(!(curtext->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ curtext->from.sym->name);
+ Bflush(&bso);
+ curtext->mark |= LEAF;
+ }
+
+ if(curtext->mark & LEAF) {
+ if(curtext->from.sym)
+ curtext->from.sym->type = SLEAF;
+ break;
+ }
+
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGLINK;
+ q1->to.type = D_OREG;
+ q1->from.offset = 0;
+ q1->to.reg = REGSP;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case ARET:
+ nocache(p);
+ if(p->from.type == D_CONST)
+ goto become;
+ if(curtext->mark & LEAF) {
+ if(!autosize) {
+ p->as = AJMP;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ p->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_OREG;
+ q->to.offset = 0;
+ q->to.reg = REGLINK;
+ q->mark |= BRANCH;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ q = p;
+ if(autosize) {
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = prg();
+ q1->as = AJMP;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 0;
+ q1->to.reg = 2;
+ q1->mark |= BRANCH;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ become:
+ if(curtext->mark & LEAF) {
+
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ p->as = AADD;
+ p->from = zprg.from;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ break;
+ }
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ q = prg();
+ q->line = p->line;
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+
+ p->as = AMOVW;
+ p->from = zprg.from;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGLINK;
+
+ break;
+ }
+ }
+
+ curtext = P;
+ q = P; /* p - 1 */
+ q1 = firstp; /* top of block */
+ o = 0; /* count of instructions */
+ for(p = firstp; p != P; p = p1) {
+ p1 = p->link;
+ o++;
+ if(p->mark & NOSCHED){
+ if(q1 != p){
+ sched(q1, q);
+ }
+ for(; p != P; p = p->link){
+ if(!(p->mark & NOSCHED))
+ break;
+ q = p;
+ }
+ p1 = p;
+ q1 = p;
+ o = 0;
+ continue;
+ }
+ if(p->mark & (LABEL|SYNC)) {
+ if(q1 != p)
+ sched(q1, q);
+ q1 = p;
+ o = 1;
+ }
+ if(p->mark & (BRANCH|SYNC)) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ if(o >= NSCHED) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ q = p;
+ }
+}
+
+void
+addnop(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = ANOR;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGZERO;
+ q->to.type = D_REG;
+ q->to.reg = REGZERO;
+
+ q->link = p->link;
+ p->link = q;
+}
+
+void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
diff --git a/utils/0l/obj.c b/utils/0l/obj.c
new file mode 100644
index 00000000..644925ac
--- /dev/null
+++ b/utils/0l/obj.c
@@ -0,0 +1,1384 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = '0';
+char *thestring = "spim";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is abbrev unix
+ * -H1 -T0x80020000 -R4 is bootp() format for 3k
+ * -H2 -T4128 -R4096 is plan9 spim format
+ * -H3 -T0x80020000 -R8 is bootp() format for 4k
+ * -H4 -T0x400000 -R4 is sgi unix coff executable
+ * -H5 -T0x4000A0 -R4 is sgi unix elf executable
+ * -H6 -T0x4000A0 -R4 is plan9 spim format
+ */
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ outfile = 0;
+ nerrors = 0;
+ curtext = P;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ /* do something about setting INITTEXT */
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0) {
+ diag("usage: vl [-options] objects\n");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 0;
+ if(debug['B'])
+ HEADTYPE = 1;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case 0: /* unix simple */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* boot for 3k */
+ HEADR = 20L+60L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x80020000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 2: /* plan 9 spim */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* boot for 4k */
+ HEADR = 20L+56L+3*40L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x80020000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 8;
+ break;
+ case 4: /* sgi unix coff executable */
+ HEADR = 20L+56L+3*40L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x00400000L+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 5: /* sgi unix elf executable */
+ HEADR = rnd(52L+3*32L, 16);
+ if(INITTEXT == -1)
+ INITTEXT = 0x00400000L+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 6: /* plan 9 spim */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.to = zprg.from;
+ buildop();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ dtype = 4;
+ if(outfile == 0)
+ outfile = "0.out";
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("%s: cannot create\n", outfile);
+ errorexit();
+ }
+ nuxiinit();
+
+ version = 0;
+ cbp = (uchar*)buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ goto out;
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ dodata();
+ follow();
+ if(firstp == P)
+ goto out;
+ noops();
+ span();
+ asmb();
+ undef();
+
+out:
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ Bflush(&bso);
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s\n", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header\n", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header\n", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s\n", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive\n", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int i, c;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ c = p[2];
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ p[0] = ALAST+1;
+ return 0;
+ }
+ a->type = p[0];
+ a->reg = p[1];
+ a->sym = h[c];
+ a->name = p[3];
+ c = 4;
+
+ if(a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_MREG:
+ case D_FCREG:
+ case D_LO:
+ case D_HI:
+ break;
+
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ a->offset = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ c += 4;
+ break;
+
+ case D_SCONST:
+ a->sval = malloc(NSNAME);
+ memmove(a->sval, p+4, NSNAME);
+ c += NSNAME;
+ break;
+
+ case D_VCONST:
+ case D_FCONST:
+ a->ieee = malloc(sizeof(Ieee));
+ a->ieee->l = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ a->ieee->h = p[8] | (p[9]<<8) |
+ (p[10]<<16) | (p[11]<<24);
+ c += 8;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ return c;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ long ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ Sym *h[NSYM], *s, *di;
+ int v, o, r, skip;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0]; /* as */
+ if(o <= AXXX || o >= ALAST) {
+ diag("%s: line %ld: opcode out of range %d\n", pn, pc-ipc, o);
+ print(" probably not a .v file\n");
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[1]; /* type */
+ o = bloc[2]; /* sym */
+ bloc += 3;
+ c -= 3;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ if(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->reg = bloc[1] & 0x7f;
+ if(bloc[1] & 0x80)
+ p->mark = NOSCHED;
+ p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(p->reg < 0 || p->reg > NREG)
+ diag("register out of range %d\n", p->reg);
+
+ p->link = P;
+ p->cond = P;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P\n", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P\n", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset && s->value && p->to.offset != s->value)
+ print("warning: resize of a global: %s\n%P\n", s->name, p);
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ break;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P\n", p);
+ break;
+ }
+ di = p->to.sym;
+ p->reg = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P\n", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_CONST;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P\n", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P\n", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case ADATA:
+ if(p->from.sym == S) {
+ diag("DATA without a sym\n%P\n", p);
+ break;
+ }
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P\n", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ curtext = p;
+ s = p->from.sym;
+ if(s == S) {
+ diag("TEXT must have a name\n%P\n", p);
+ errorexit();
+ }
+ autosize = p->to.offset;
+ if(autosize & 7) {
+ diag("stack frame not 8 multiple: %s\n%P\n", s->name, p);
+ autosize = autosize + 7 & ~7;
+ p->to.offset = autosize;
+ }
+ autosize += 8;
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->reg & DUPOK) {
+ skip = 1;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P\n", s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->cond = p;
+ etextp = p;
+ break;
+
+ case ASUB:
+ case ASUBU:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE) {
+ p->from.offset = -p->from.offset;
+ if(p->as == ASUB)
+ p->as = AADD;
+ else
+ p->as = AADDU;
+ }
+ goto casedef;
+
+ case AMOVF:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 4;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVD:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee->h, p->from.ieee->l);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVV:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_VCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee->h, p->from.ieee->l);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s\n", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory\n");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDU;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined\n");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->reg = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->reg = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->reg & NOPROF) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * JAL profin, R2
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AJAL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = AJAL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ fnuxi4[i] = c;
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", fnuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+vlong
+ieeedtov(Ieee *ieeep)
+{
+ vlong v;
+
+ v = (vlong)ieeep->l & (vlong)0xffffffff;
+ v |= (vlong)ieeep->h << 32;
+ return v;
+}
+
+long
+ieeedtof(Ieee *ieeep)
+{
+ int exp;
+ long v;
+
+ if(ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (ieeep->h & 0xfffffL) << 3;
+ v |= (ieeep->l >> 29) & 0x7L;
+ if((ieeep->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow\n");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= ieeep->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
diff --git a/utils/0l/optab.c b/utils/0l/optab.c
new file mode 100644
index 00000000..d788c013
--- /dev/null
+++ b/utils/0l/optab.c
@@ -0,0 +1,221 @@
+#include "l.h"
+
+#define X 99
+
+Optab optab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0 },
+ { AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0 },
+
+ { ASUB, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AAND, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { ASUB, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AAND, C_REG, C_NONE, C_REG, 2, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0 },
+ { ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0 },
+ { AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+ { AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVV, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVB, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVWL, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVV, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWL, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVV, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVB, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVV, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVV, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+
+ { AMOVW, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVV, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVB, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVBU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVV, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVBU, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVV, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVBU, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+
+ { AMOVW, C_SECON,C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVW, C_SACON,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_REG, 26, 12, REGSB },
+ { AMOVW, C_LACON,C_NONE, C_REG, 26, 12, REGSP },
+ { AMOVW, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVV, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVW, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVV, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO },
+
+ { AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0 },
+ { AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0 },
+
+ { AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0 },
+
+ { AMUL, C_REG, C_REG, C_NONE, 22, 4, 0 },
+
+ { AADD, C_ADD0CON,C_REG,C_REG, 4, 4, 0 },
+ { AADD, C_ADD0CON,C_NONE,C_REG, 4, 4, 0 },
+ { AADD, C_ANDCON,C_REG, C_REG, 10, 8, 0 },
+ { AADD, C_ANDCON,C_NONE,C_REG, 10, 8, 0 },
+
+ { AAND, C_AND0CON,C_REG,C_REG, 4, 4, 0 },
+ { AAND, C_AND0CON,C_NONE,C_REG, 4, 4, 0 },
+ { AAND, C_ADDCON,C_REG, C_REG, 10, 8, 0 },
+ { AAND, C_ADDCON,C_NONE,C_REG, 10, 8, 0 },
+
+ { AADD, C_UCON, C_REG, C_REG, 25, 8, 0 },
+ { AADD, C_UCON, C_NONE, C_REG, 25, 8, 0 },
+ { AAND, C_UCON, C_REG, C_REG, 25, 8, 0 },
+ { AAND, C_UCON, C_NONE, C_REG, 25, 8, 0 },
+
+ { AADD, C_LCON, C_NONE, C_REG, 23, 12, 0 },
+ { AAND, C_LCON, C_NONE, C_REG, 23, 12, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 23, 12, 0 },
+ { AAND, C_LCON, C_REG, C_REG, 23, 12, 0 },
+
+ { ASLL, C_SCON, C_REG, C_REG, 16, 4, 0 },
+ { ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0 },
+
+ { ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0 },
+ { ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0 },
+ { ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0 },
+ { ABFPT, C_NONE, C_NONE, C_SBRA, 6, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+ { AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO },
+ { AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK },
+
+ { AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVF, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVD, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+ { AMOVF, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+ { AMOVD, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+
+ { AMOVW, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVF, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVD, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVD, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+ { AMOVD, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+
+ { AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+ { AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+ { AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+
+ { AMOVW, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+ { AMOVD, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0 },
+ { AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0 },
+
+ { AMOVW, C_ADDCON,C_NONE,C_FREG, 34, 8, 0 },
+ { AMOVW, C_ANDCON,C_NONE,C_FREG, 34, 8, 0 },
+ { AMOVW, C_UCON, C_NONE, C_FREG, 35, 8, 0 },
+ { AMOVW, C_LCON, C_NONE, C_FREG, 36, 12, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0 },
+ { AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0 },
+ { AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0 },
+
+ { ARFE, C_NONE, C_NONE, C_ZOREG, 39, 8, 0 },
+ { AWORD, C_NONE, C_NONE, C_LCON, 40, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0 },
+ { AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0 },
+ { AMOVW, C_FCREG,C_NONE, C_REG, 42, 4, 0 },
+ { AMOVV, C_FCREG,C_NONE, C_REG, 42, 4, 0 },
+
+ { ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, /* really CACHE instruction */
+ { ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
diff --git a/utils/0l/pass.c b/utils/0l/pass.c
new file mode 100644
index 00000000..95c4a754
--- /dev/null
+++ b/utils/0l/pass.c
@@ -0,0 +1,498 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i, t;
+ Sym *s;
+ Prog *p, *p1;
+ long orig, orig1, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P\n",
+ s->type, s->name, p);
+ v = p->from.offset + p->reg;
+ if(v > s->value)
+ diag("initialize bounds (%ld): %s\n%P\n",
+ s->value, s->name, p);
+ }
+
+ /*
+ * pass 1
+ * assign 'small' variables to data segment
+ * (rational is that data segment is more easily
+ * addressed through offset on R30)
+ */
+ orig = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA && t != SBSS)
+ continue;
+ v = s->value;
+ if(v == 0) {
+ diag("%s: no size\n", s->name);
+ v = 1;
+ }
+ while(v & 7)
+ v++;
+ s->value = v;
+ if(v > MINSIZ)
+ continue;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+ orig1 = orig;
+
+ /*
+ * pass 2
+ * assign 'data' variables to data segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA) {
+ if(t == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ v = s->value;
+ while(v & 7)
+ v++;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+
+ while(orig & 7)
+ orig++;
+ datsize = orig;
+
+ /*
+ * pass 3
+ * everything else to bss segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ v = s->value;
+ while(v & 7)
+ v++;
+ s->value = orig;
+ orig += v;
+ }
+ while(orig & 7)
+ orig++;
+ bsssize = orig-datsize;
+
+ /*
+ * pass 4
+ * add literals to all large values.
+ * at this time:
+ * small data is allocated DATA
+ * large data is allocated DATA1
+ * large bss is allocated BSS
+ * the new literals are loaded between
+ * small data and large data.
+ */
+ orig = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as != AMOVW)
+ continue;
+ if(p->from.type != D_CONST)
+ continue;
+ if(s = p->from.sym) {
+ t = s->type;
+ if(t != SDATA && t != SDATA1 && t != SBSS)
+ continue;
+ t = p->from.name;
+ if(t != D_EXTERN && t != D_STATIC)
+ continue;
+ v = s->value + p->from.offset;
+ if(v >= 0 && v <= 0xffff)
+ continue;
+ if(!strcmp(s->name, "setR30"))
+ continue;
+ /* size should be 19 max */
+ if(strlen(s->name) >= 10) /* has loader address */
+ sprint(literal, "$%lux.%lux", (long)s, p->from.offset);
+ else
+ sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset);
+ } else {
+ if(p->from.name != D_NONE)
+ continue;
+ if(p->from.reg != NREG)
+ continue;
+ v = p->from.offset;
+ if(v >= -0x7fff && v <= 0xffff)
+ continue;
+ if(!(v & 0xffff))
+ continue;
+ /* size should be 9 max */
+ sprint(literal, "$%lux", v);
+ }
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ s->value = orig1+orig;
+ orig += 8;
+ p1 = prg();
+ p1->line = p->line;
+ p1->as = ADATA;
+ p1->from.type = D_OREG;
+ p1->from.sym = s;
+ p1->from.name = D_EXTERN;
+ p1->reg = 4;
+ p1->to = p->from;
+ p1->link = datap;
+ datap = p1;
+ }
+ if(s->type != SDATA)
+ diag("literal not data: %s", s->name);
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ nocache(p);
+ continue;
+ }
+ while(orig & 7)
+ orig++;
+ /*
+ * pass 5
+ * re-adjust offsets
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t == SBSS) {
+ s->value += orig;
+ continue;
+ }
+ if(t == SDATA1) {
+ s->type = SDATA;
+ s->value += orig;
+ continue;
+ }
+ }
+ datsize += orig;
+ xdefine("setR30", SDATA, 0L+BIG);
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+ xdefine("etext", STEXT, 0L);
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined\n", s->name);
+}
+
+void
+follow(void)
+{
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+
+ firstp = firstp->link;
+ lastp->link = P;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == P)
+ return;
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(a == AJMP) {
+ q = p->cond;
+ if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ p = p->link;
+ xfol(p);
+ p = q;
+ if(p && !(p->mark & FOLL))
+ goto loop;
+ return;
+ }
+ if(q != P) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == lastp || (q->mark&NOSCHED))
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AJMP || a == ARET || a == ARFE)
+ goto copy;
+ if(!q->cond || (q->cond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ lastp->link = r;
+ lastp = r;
+ continue;
+ }
+ lastp->link = r;
+ lastp = r;
+ if(a == AJMP || a == ARET || a == ARFE)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+ a = AJMP;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ if(a == AJMP || a == ARET || a == ARFE){
+ if(p->mark & NOSCHED){
+ p = p->link;
+ goto loop;
+ }
+ return;
+ }
+ if(p->cond != P)
+ if(a != AJAL && p->link != P) {
+ xfol(p->link);
+ p = p->cond;
+ if(p == P || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ long c, vexit;
+ Prog *p, *q;
+ Sym *s;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if((a == AJAL || a == AJMP || a == ARET) &&
+ p->to.type != D_BRANCH && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s\n%P\n", s->name, p);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range %ld\n%P\n", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->cond != P) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ long dwn[LOG], cnt[LOG], i;
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != AJMP || (p->mark&NOSCHED))
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/utils/0l/sched.c b/utils/0l/sched.c
new file mode 100644
index 00000000..28e78f28
--- /dev/null
+++ b/utils/0l/sched.c
@@ -0,0 +1,709 @@
+#include "l.h"
+
+enum
+{
+ E_HILO = 1<<0,
+ E_FCR = 1<<1,
+ E_MCR = 1<<2,
+ E_MEM = 1<<3,
+ E_MEMSP = 1<<4, /* uses offset and size */
+ E_MEMSB = 1<<5, /* uses offset and size */
+ ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
+ DELAY = BRANCH|LOAD|FCMP,
+};
+
+typedef struct Sch Sch;
+typedef struct Dep Dep;
+
+struct Dep
+{
+ ulong ireg;
+ ulong freg;
+ ulong cc;
+};
+struct Sch
+{
+ Prog p;
+ Dep set;
+ Dep used;
+ long soffset;
+ char size;
+ char nop;
+ char comp;
+};
+
+void markregused(Sch*, Prog*);
+int depend(Sch*, Sch*);
+int conflict(Sch*, Sch*);
+int offoverlap(Sch*, Sch*);
+void dumpbits(Sch*, Dep*);
+
+void
+sched(Prog *p0, Prog *pe)
+{
+ Prog *p, *q;
+ Sch sch[NSCHED], *s, *t, *u, *se, stmp;
+
+ /*
+ * build side structure
+ */
+ s = sch;
+ for(p=p0;; p=p->link) {
+ memset(s, 0, sizeof(*s));
+ s->p = *p;
+ markregused(s, p);
+ if(debug['X']) {
+ Bprint(&bso, "%P%|set", &s->p, 40);
+ dumpbits(s, &s->set);
+ Bprint(&bso, "; used");
+ dumpbits(s, &s->used);
+ if(s->comp)
+ Bprint(&bso, "; compound");
+ if(s->p.mark & LOAD)
+ Bprint(&bso, "; load");
+ if(s->p.mark & BRANCH)
+ Bprint(&bso, "; branch");
+ if(s->p.mark & FCMP)
+ Bprint(&bso, "; fcmp");
+ Bprint(&bso, "\n");
+ }
+ if(p == pe)
+ break;
+ s++;
+ }
+ se = s;
+
+ /*
+ * prepass to move things around
+ * does nothing, but tries to make
+ * the actual scheduler work better
+ */
+ for(s=sch; s<=se; s++) {
+ if(!(s->p.mark & LOAD))
+ continue;
+ /* always good to put nonconflict loads together */
+ for(t=s+1; t<=se; t++) {
+ if(!(t->p.mark & LOAD))
+ continue;
+ if(t->p.mark & BRANCH)
+ break;
+ if(conflict(s, t))
+ break;
+ for(u=t-1; u>s; u--)
+ if(depend(u, t))
+ goto no11;
+ u = s+1;
+ stmp = *t;
+ memmove(s+2, u, (uchar*)t - (uchar*)u);
+ *u = stmp;
+ break;
+ }
+ no11:
+
+ /* put schedule fodder above load */
+ for(t=s+1; t<=se; t++) {
+ if(t->p.mark & BRANCH)
+ break;
+ if(s > sch && conflict(s-1, t))
+ continue;
+ for(u=t-1; u>=s; u--)
+ if(depend(t, u))
+ goto no1;
+ stmp = *t;
+ memmove(s+1, s, (uchar*)t - (uchar*)s);
+ *s = stmp;
+ if(!(s->p.mark & LOAD))
+ break;
+ no1:;
+ }
+ }
+
+ for(s=se; s>=sch; s--) {
+ if(!(s->p.mark & DELAY))
+ continue;
+ if(s < se)
+ if(!conflict(s, s+1))
+ goto out3;
+ /*
+ * s is load, s+1 is immediate use of result or end of block
+ * t is the trial instruction to insert between s and s+1
+ */
+ if(!debug['Y'])
+ for(t=s-1; t>=sch; t--) {
+ if(t->comp)
+ if(s->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & DELAY)
+ if(s >= se || conflict(t, s+1))
+ goto no2;
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no2;
+ goto out2;
+ no2:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?l%P\n", &s->p);
+ if(s->p.mark & BRANCH)
+ s->nop = 1;
+ if(debug['v']) {
+ if(s->p.mark & LOAD) {
+ nop.load.count++;
+ nop.load.outof++;
+ }
+ if(s->p.mark & BRANCH) {
+ nop.branch.count++;
+ nop.branch.outof++;
+ }
+ if(s->p.mark & FCMP) {
+ nop.fcmp.count++;
+ nop.fcmp.outof++;
+ }
+ }
+ continue;
+
+ out2:
+ if(debug['X']) {
+ Bprint(&bso, "!l%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+
+ out3:
+ if(debug['v']) {
+ if(s->p.mark & LOAD)
+ nop.load.outof++;
+ if(s->p.mark & BRANCH)
+ nop.branch.outof++;
+ if(s->p.mark & FCMP)
+ nop.fcmp.outof++;
+ }
+ }
+
+ /* Avoid HI/LO use->set */
+ t = sch+1;
+ for(s=sch; s<se-1; s++, t++) {
+ if((s->used.cc & E_HILO) == 0)
+ continue;
+ if(t->set.cc & E_HILO)
+ s->nop = 2;
+ }
+
+ /*
+ * put it all back
+ */
+ for(s=sch, p=p0; s<=se; s++, p=q) {
+ q = p->link;
+ if(q != s->p.link) {
+ *p = s->p;
+ p->link = q;
+ }
+ while(s->nop--)
+ addnop(p);
+ }
+ if(debug['X']) {
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ }
+}
+
+void
+markregused(Sch *s, Prog *realp)
+{
+ int c, ar, ad, ld, sz;
+ ulong m;
+ Prog *p;
+
+ p = &s->p;
+ s->comp = compound(p);
+ s->nop = 0;
+ if(s->comp) {
+ s->set.ireg |= 1<<REGTMP;
+ s->used.ireg |= 1<<REGTMP;
+ }
+
+ ar = 0; /* dest is really reference */
+ ad = 0; /* source/dest is really address */
+ ld = 0; /* opcode is load instruction */
+ sz = 20; /* size of load/store for overlap computation */
+
+/*
+ * flags based on opcode
+ */
+ switch(p->as) {
+ case ATEXT:
+ curtext = realp;
+ autosize = p->to.offset + 8;
+ ad = 1;
+ break;
+ case AJAL:
+ c = p->reg;
+ if(c == NREG)
+ c = REGLINK;
+ s->set.ireg |= 1<<c;
+ ar = 1;
+ ad = 1;
+ break;
+ case ABGEZAL:
+ case ABLTZAL:
+ s->set.ireg |= 1<<REGLINK;
+ case ABEQ:
+ case ABGEZ:
+ case ABGTZ:
+ case ABLEZ:
+ case ABLTZ:
+ case ABNE:
+ ar = 1;
+ ad = 1;
+ break;
+ case ABFPT:
+ case ABFPF:
+ ad = 1;
+ s->used.cc |= E_FCR;
+ break;
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+ ar = 1;
+ s->set.cc |= E_FCR;
+ p->mark |= FCMP;
+ break;
+ case AJMP:
+ ar = 1;
+ ad = 1;
+ break;
+ case AMOVB:
+ case AMOVBU:
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVH:
+ case AMOVHU:
+ sz = 2;
+ ld = 1;
+ break;
+ case AMOVF:
+ case AMOVW:
+ case AMOVWL:
+ case AMOVWR:
+ sz = 4;
+ ld = 1;
+ break;
+ case AMOVD:
+ case AMOVV:
+ case AMOVVL:
+ case AMOVVR:
+ sz = 8;
+ ld = 1;
+ break;
+ case ADIV:
+ case ADIVU:
+ case AMUL:
+ case AMULU:
+ case AREM:
+ case AREMU:
+ case ADIVV:
+ case ADIVVU:
+ case AMULV:
+ case AMULVU:
+ case AREMV:
+ case AREMVU:
+ s->set.cc = E_HILO;
+ case AADD:
+ case AADDU:
+ case AADDV:
+ case AADDVU:
+ case AAND:
+ case ANOR:
+ case AOR:
+ case ASGT:
+ case ASGTU:
+ case ASLL:
+ case ASRA:
+ case ASRL:
+ case ASLLV:
+ case ASRAV:
+ case ASRLV:
+ case ASUB:
+ case ASUBU:
+ case ASUBV:
+ case ASUBVU:
+ case AXOR:
+
+ case AADDD:
+ case AADDF:
+ case AADDW:
+ case ASUBD:
+ case ASUBF:
+ case ASUBW:
+ case AMULF:
+ case AMULD:
+ case AMULW:
+ case ADIVF:
+ case ADIVD:
+ case ADIVW:
+ if(p->reg == NREG) {
+ if(p->to.type == D_REG || p->to.type == D_FREG)
+ p->reg = p->to.reg;
+ if(p->reg == NREG)
+ print("botch %P\n", p);
+ }
+ break;
+ }
+
+/*
+ * flags based on 'to' field
+ */
+ c = p->to.class;
+ if(c == 0) {
+ c = aclass(&p->to) + 1;
+ p->to.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->to);
+
+ case C_ZCON:
+ case C_SCON:
+ case C_ADD0CON:
+ case C_AND0CON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_UCON:
+ case C_LCON:
+ case C_NONE:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+
+ case C_HI:
+ case C_LO:
+ s->set.cc |= E_HILO;
+ break;
+ case C_FCREG:
+ s->set.cc |= E_FCR;
+ break;
+ case C_MREG:
+ s->set.cc |= E_MCR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->to.reg;
+ s->used.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ if(ar)
+ s->used.cc |= m;
+ else
+ s->set.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ if(ar)
+ s->used.ireg |= 1<<p->to.reg;
+ else
+ s->set.ireg |= 1<<p->to.reg;
+ break;
+ case C_FREG:
+ /* do better -- determine double prec */
+ if(ar) {
+ s->used.freg |= 1<<p->to.reg;
+ s->used.freg |= 1<<(p->to.reg|1);
+ } else {
+ s->set.freg |= 1<<p->to.reg;
+ s->set.freg |= 1<<(p->to.reg|1);
+ }
+ if(ld && p->from.type == D_REG)
+ p->mark |= LOAD;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSP;
+ else
+ s->set.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSB;
+ else
+ s->set.cc |= E_MEMSB;
+ break;
+ }
+
+/*
+ * flags based on 'from' field
+ */
+ c = p->from.class;
+ if(c == 0) {
+ c = aclass(&p->from) + 1;
+ p->from.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->from);
+
+ case C_ZCON:
+ case C_SCON:
+ case C_ADD0CON:
+ case C_AND0CON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_UCON:
+ case C_LCON:
+ case C_NONE:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+ case C_HI:
+ case C_LO:
+ s->used.cc |= E_HILO;
+ break;
+ case C_FCREG:
+ s->used.cc |= E_FCR;
+ break;
+ case C_MREG:
+ s->used.cc |= E_MCR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->from.reg;
+ s->used.ireg |= 1<<c;
+ if(ld)
+ p->mark |= LOAD;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ s->used.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ s->used.ireg |= 1<<p->from.reg;
+ break;
+ case C_FREG:
+ /* do better -- determine double prec */
+ s->used.freg |= 1<<p->from.reg;
+ s->used.freg |= 1<<(p->from.reg|1);
+ if(ld && p->to.type == D_REG)
+ p->mark |= LOAD;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSB;
+ break;
+ }
+
+ c = p->reg;
+ if(c != NREG) {
+ if(p->from.type == D_FREG || p->to.type == D_FREG) {
+ s->used.freg |= 1<<c;
+ s->used.freg |= 1<<(c|1);
+ } else
+ s->used.ireg |= 1<<c;
+ }
+ s->set.ireg &= ~(1<<REGZERO); /* R0 cant be set */
+}
+
+/*
+ * test to see if 2 instrictions can be
+ * interchanged without changing semantics
+ */
+int
+depend(Sch *sa, Sch *sb)
+{
+ ulong x;
+
+ if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
+ return 1;
+ if(sb->set.ireg & sa->used.ireg)
+ return 1;
+
+ if(sa->set.freg & (sb->set.freg|sb->used.freg))
+ return 1;
+ if(sb->set.freg & sa->used.freg)
+ return 1;
+
+ /*
+ * special case.
+ * loads from same address cannot pass.
+ * this is for hardware fifo's and the like
+ */
+ if(sa->used.cc & sb->used.cc & E_MEM)
+ if(sa->p.reg == sb->p.reg)
+ if(regoff(&sa->p.from) == regoff(&sb->p.from))
+ return 1;
+
+ x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
+ (sb->set.cc & sa->used.cc);
+ if(x) {
+ /*
+ * allow SB and SP to pass each other.
+ * allow SB to pass SB iff doffsets are ok
+ * anything else conflicts
+ */
+ if(x != E_MEMSP && x != E_MEMSB)
+ return 1;
+ x = sa->set.cc | sb->set.cc |
+ sa->used.cc | sb->used.cc;
+ if(x & E_MEM)
+ return 1;
+ if(offoverlap(sa, sb))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+offoverlap(Sch *sa, Sch *sb)
+{
+
+ if(sa->soffset < sb->soffset) {
+ if(sa->soffset+sa->size > sb->soffset)
+ return 1;
+ return 0;
+ }
+ if(sb->soffset+sb->size > sa->soffset)
+ return 1;
+ return 0;
+}
+
+/*
+ * test 2 adjacent instructions
+ * and find out if inserted instructions
+ * are desired to prevent stalls.
+ */
+int
+conflict(Sch *sa, Sch *sb)
+{
+
+ if(sa->set.ireg & sb->used.ireg)
+ return 1;
+ if(sa->set.freg & sb->used.freg)
+ return 1;
+ if(sa->set.cc & sb->used.cc)
+ return 1;
+
+ return 0;
+}
+
+int
+compound(Prog *p)
+{
+ Optab *o;
+
+ o = oplook(p);
+ if(o->size != 4)
+ return 1;
+ if(p->to.type == D_REG && p->to.reg == REGSB)
+ return 1;
+ return 0;
+}
+
+void
+dumpbits(Sch *s, Dep *d)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(d->ireg & (1<<i))
+ Bprint(&bso, " R%d", i);
+ for(i=0; i<32; i++)
+ if(d->freg & (1<<i))
+ Bprint(&bso, " F%d", i);
+ for(i=0; i<32; i++)
+ switch(d->cc & (1<<i)) {
+ default:
+ break;
+ case E_HILO:
+ Bprint(&bso, " HILO");
+ break;
+ case E_FCR:
+ Bprint(&bso, " FCR");
+ break;
+ case E_MCR:
+ Bprint(&bso, " MCR");
+ break;
+ case E_MEM:
+ Bprint(&bso, " MEM%d", s->size);
+ break;
+ case E_MEMSB:
+ Bprint(&bso, " SB%d", s->size);
+ break;
+ case E_MEMSP:
+ Bprint(&bso, " SP%d", s->size);
+ break;
+ }
+}
diff --git a/utils/0l/span.c b/utils/0l/span.c
new file mode 100644
index 00000000..3c9d2d50
--- /dev/null
+++ b/utils/0l/span.c
@@ -0,0 +1,628 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ Sym *setext;
+ Optab *o;
+ int m, bflag;
+ long c, otxt;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+
+ bflag = 0;
+ c = INITTEXT;
+ otxt = c;
+ for(p = firstp; p != P; p = p->link) {
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 8;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P\n", p);
+ continue;
+ }
+ c += m;
+ }
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ while(bflag) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ p->pc = c;
+ o = oplook(p);
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AJMP;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AJMP;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ addnop(p->link);
+ addnop(p);
+ bflag = 1;
+ }
+ }
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 8;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P\n", p);
+ continue;
+ }
+ c += m;
+ }
+ }
+ c = rnd(c, 8);
+
+ setext = lookup("etext", 0);
+ if(setext != S) {
+ setext->value = c;
+ textsize = c - INITTEXT;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "tsize = %lux\n", textsize);
+ Bflush(&bso);
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+}
+
+long
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+int
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FCREG:
+ return C_FCREG;
+
+ case D_MREG:
+ return C_MREG;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s\n",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ instoffset = a->sym->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SEXT;
+ return C_LEXT;
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 8L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ if(instoffset == 0)
+ return C_ZOREG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_HI:
+ return C_LO;
+ case D_LO:
+ return C_HI;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s\n",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ if(s->type == STEXT || s->type == SLEAF)
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+
+ case D_NONE:
+ instoffset = a->offset;
+ consize:
+ if(instoffset > 0) {
+ if(instoffset <= 0x7fff)
+ return C_SCON;
+ if(instoffset <= 0xffff)
+ return C_ANDCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+ }
+ if(instoffset == 0)
+ return C_ZCON;
+ if(instoffset >= -0x8000)
+ return C_ADDCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ switch(t) {
+ case 0:
+ case SXREF:
+ diag("undefined external: %s in %s\n",
+ s->name, TNAME);
+ s->type = SDATA;
+ break;
+ case SCONST:
+ instoffset = s->value + a->offset;
+ goto consize;
+ case STEXT:
+ case SLEAF:
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ instoffset = s->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
+ return C_SECON;
+ instoffset = s->value + a->offset + INITDAT;
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 8L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, r, t;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(&p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0) {
+ t = opcross[repop[r]][a1][a2][a3];
+ if(t) {
+ p->optab = t+1;
+ return optab+t;
+ }
+ o = oprange[r].stop; /* just generate an error */
+ }
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ diag("illegal combination %A %d %d %d",
+ p->as, a1, a2, a3);
+ if(!debug['a'])
+ prasm(p);
+ o = optab;
+ p->optab = (o-optab)+1;
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON ||
+ b == C_ADDCON || b == C_ANDCON)
+ return 1;
+ break;
+ case C_ADD0CON:
+ if(b == C_ADDCON)
+ return 1;
+ case C_ADDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_AND0CON:
+ if(b == C_ANDCON)
+ return 1;
+ case C_ANDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ for(i=0; i<32; i++)
+ for(n=0; n<32; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A\n", r);
+ errorexit();
+ case AABSF:
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ oprange[AMOVWF] = oprange[r];
+ oprange[AMOVFW] = oprange[r];
+ oprange[AMOVWD] = oprange[r];
+ oprange[AMOVDW] = oprange[r];
+ oprange[ANEGF] = oprange[r];
+ oprange[ANEGD] = oprange[r];
+ oprange[AABSD] = oprange[r];
+ oprange[ATRUNCDW] = oprange[r];
+ oprange[ATRUNCFW] = oprange[r];
+ oprange[ATRUNCDV] = oprange[r];
+ oprange[ATRUNCFV] = oprange[r];
+ oprange[AMOVDV] = oprange[r];
+ oprange[AMOVFV] = oprange[r];
+ oprange[AMOVVD] = oprange[r];
+ oprange[AMOVVF] = oprange[r];
+ break;
+ case AADD:
+ buildrep(1, AADD);
+ oprange[ASGT] = oprange[r];
+ repop[ASGT] = 1;
+ oprange[ASGTU] = oprange[r];
+ repop[ASGTU] = 1;
+ oprange[AADDU] = oprange[r];
+ repop[AADDU] = 1;
+ oprange[AADDVU] = oprange[r];
+ repop[AADDVU] = 1;
+ oprange[AADDV] = oprange[r];
+ repop[AADDV] = 1;
+ break;
+ case AADDF:
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AADDD] = oprange[r];
+ break;
+ case AAND:
+ buildrep(2, AAND);
+ oprange[AXOR] = oprange[r];
+ repop[AXOR] = 2;
+ oprange[AOR] = oprange[r];
+ repop[AOR] = 2;
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ break;
+ case ABLEZ:
+ oprange[ABGEZ] = oprange[r];
+ oprange[ABGEZAL] = oprange[r];
+ oprange[ABLTZ] = oprange[r];
+ oprange[ABLTZAL] = oprange[r];
+ oprange[ABGTZ] = oprange[r];
+ break;
+ case AMOVB:
+ buildrep(3, AMOVB);
+ oprange[AMOVH] = oprange[r];
+ repop[AMOVH] = 3;
+ break;
+ case AMOVBU:
+ buildrep(4, AMOVBU);
+ oprange[AMOVHU] = oprange[r];
+ repop[AMOVHU] = 4;
+ break;
+ case AMUL:
+ oprange[AREM] = oprange[r];
+ oprange[AREMU] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ oprange[AMULU] = oprange[r];
+ oprange[ADIV] = oprange[r];
+ oprange[ADIVV] = oprange[r];
+ oprange[ADIVVU] = oprange[r];
+ oprange[AMULV] = oprange[r];
+ oprange[AMULVU] = oprange[r];
+ oprange[AREMV] = oprange[r];
+ oprange[AREMVU] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ oprange[ASLLV] = oprange[r];
+ oprange[ASRAV] = oprange[r];
+ oprange[ASRLV] = oprange[r];
+ break;
+ case ASUB:
+ oprange[ASUBU] = oprange[r];
+ oprange[ASUBV] = oprange[r];
+ oprange[ASUBVU] = oprange[r];
+ oprange[ANOR] = oprange[r];
+ break;
+ case ASYSCALL:
+ oprange[ATLBP] = oprange[r];
+ oprange[ATLBR] = oprange[r];
+ oprange[ATLBWI] = oprange[r];
+ oprange[ATLBWR] = oprange[r];
+ break;
+ case ACMPEQF:
+ oprange[ACMPGTF] = oprange[r];
+ oprange[ACMPGTD] = oprange[r];
+ oprange[ACMPGEF] = oprange[r];
+ oprange[ACMPGED] = oprange[r];
+ oprange[ACMPEQD] = oprange[r];
+ break;
+ case ABFPT:
+ oprange[ABFPF] = oprange[r];
+ break;
+ case AMOVWL:
+ oprange[AMOVWR] = oprange[r];
+ oprange[AMOVVR] = oprange[r];
+ oprange[AMOVVL] = oprange[r];
+ break;
+ case AMOVW:
+ buildrep(5, AMOVW);
+ break;
+ case AMOVD:
+ buildrep(6, AMOVD);
+ break;
+ case AMOVF:
+ buildrep(7, AMOVF);
+ break;
+ case AMOVV:
+ buildrep(8, AMOVV);
+ break;
+ case ABREAK:
+ case AWORD:
+ case ARFE:
+ case AJAL:
+ case AJMP:
+ case ATEXT:
+ case ACASE:
+ case ABCASE:
+ case AMOVWU:
+ break;
+ }
+ }
+}
+
+void
+buildrep(int x, int as)
+{
+ Opcross *p;
+ Optab *e, *s, *o;
+ int a1, a2, a3, n;
+
+ if(C_NONE != 0 ||
+ C_REG != 1 ||
+ C_GOK >= 32 ||
+ x >= nelem(opcross)) {
+ diag("assumptions fail in buildrep");
+ errorexit();
+ }
+ repop[as] = x;
+ p = (opcross + x);
+ s = oprange[as].start;
+ e = oprange[as].stop;
+ for(o=e-1; o>=s; o--) {
+ n = o-optab;
+ for(a2=0; a2<2; a2++) {
+ if(a2) {
+ if(o->a2 == C_NONE)
+ continue;
+ } else
+ if(o->a2 != C_NONE)
+ continue;
+ for(a1=0; a1<32; a1++) {
+ if(!xcmp[a1][o->a1])
+ continue;
+ for(a3=0; a3<32; a3++)
+ if(xcmp[a3][o->a3])
+ (*p)[a1][a2][a3] = n;
+ }
+ }
+ }
+ oprange[as].start = 0;
+}
diff --git a/utils/1a/a.h b/utils/1a/a.h
new file mode 100644
index 00000000..7c064db1
--- /dev/null
+++ b/utils/1a/a.h
@@ -0,0 +1,198 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../2c/2.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Ref Ref;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Addr Addr;
+typedef struct Gen2 Gen2;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ Ref* ref;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct Ref
+{
+ int class;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Addr
+{
+ Sym* sym;
+ long offset;
+ short type;
+};
+struct Gen
+{
+ Addr s0;
+ double dval;
+ char sval[8];
+ long displace;
+ short type;
+ short field;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+int assemble(char*);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen2*);
+void outhist(void);
+void zaddr(Gen*, int);
+void zname(char*, int, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * compat
+ */
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/1a/a.y b/utils/1a/a.y
new file mode 100644
index 00000000..626154d5
--- /dev/null
+++ b/utils/1a/a.y
@@ -0,0 +1,402 @@
+%{
+#include "a.h"
+%}
+%union {
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Addr addr;
+ Gen gen;
+ Gen2 gen2;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA LTYPEB
+%token <lval> LCONST LSP LSB LFP LPC LTOS LAREG LDREG LFREG
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr type pointer reg offset
+%type <addr> name areg
+%type <gen> gen rel
+%type <gen2> noaddr gengen dstgen spec1 spec2 spec3 srcgen dstrel genrel
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+ LNAME '=' expr
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LTYPE1 gengen { outcode($1, &$2); }
+| LTYPE2 noaddr { outcode($1, &$2); }
+| LTYPE3 dstgen { outcode($1, &$2); }
+| LTYPE4 spec1 { outcode($1, &$2); }
+| LTYPE5 srcgen { outcode($1, &$2); }
+| LTYPE6 dstrel { outcode($1, &$2); }
+| LTYPE7 genrel { outcode($1, &$2); }
+| LTYPE8 dstgen { outcode($1, &$2); }
+| LTYPE8 gengen { outcode($1, &$2); }
+| LTYPE9 noaddr { outcode($1, &$2); }
+| LTYPE9 dstgen { outcode($1, &$2); }
+| LTYPEA spec2 { outcode($1, &$2); }
+| LTYPEB spec3 { outcode($1, &$2); }
+
+noaddr:
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| ','
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+
+srcgen:
+ gen
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| gen ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+dstgen:
+ gen
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+| ',' gen
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+
+gengen:
+ gen ',' gen
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+dstrel:
+ rel
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+| ',' rel
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+
+genrel:
+ gen ',' rel
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec1: /* DATA opcode */
+ gen '/' con ',' gen
+ {
+ $1.displace = $3;
+ $$.from = $1;
+ $$.to = $5;
+ }
+
+spec2: /* bit field opcodes */
+ gen ',' gen ',' con ',' con
+ {
+ $1.field = $7;
+ $3.field = $5;
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec3: /* TEXT opcode */
+ gengen
+| gen ',' con ',' gen
+ {
+ $1.displace = $3;
+ $$.from = $1;
+ $$.to = $5;
+ }
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.s0.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.s0.sym = $1;
+ $$.s0.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.s0.sym = $1;
+ $$.s0.offset = $1->value + $2;
+ }
+
+gen:
+ type
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.s0.offset = $2;
+ }
+| '$' name
+ {
+ $$ = nullgen;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $2;
+ }
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ $$.type = $2.type | I_ADDR;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+| LTOS '+' con
+ {
+ $$ = nullgen;
+ $$.type = D_STACK;
+ $$.s0.offset = $3;
+ }
+| LTOS '-' con
+ {
+ $$ = nullgen;
+ $$.type = D_STACK;
+ $$.s0.offset = -$3;
+ }
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST | I_INDIR;
+ $$.s0.offset = $1;
+ }
+| '-' '(' LAREG ')'
+ {
+ $$ = nullgen;
+ $$.type = $3 | I_INDDEC;
+ }
+| '(' LAREG ')' '+'
+ {
+ $$ = nullgen;
+ $$.type = $2 | I_INDINC;
+ }
+| areg
+ {
+ $$ = nullgen;
+ $$.type = $1.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $1;
+ }
+ }
+
+type:
+ reg
+| LFREG
+
+reg:
+ LAREG
+| LDREG
+| LTOS
+
+areg:
+ '(' LAREG ')'
+ {
+ $$.type = $2 | I_INDIR;
+ $$.sym = S;
+ $$.offset = 0;
+ }
+| con '(' LAREG ')'
+ {
+ $$.type = $3 | I_INDIR;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| '(' ')'
+ {
+ $$.type = D_NONE | I_INDIR;
+ $$.sym = S;
+ $$.offset = 0;
+ }
+| con '(' ')'
+ {
+ $$.type = D_NONE | I_INDIR;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| name
+
+name:
+ LNAME offset '(' pointer ')'
+ {
+ $$.type = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$.type = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/1a/l.s b/utils/1a/l.s
new file mode 100644
index 00000000..6f3cca3a
--- /dev/null
+++ b/utils/1a/l.s
@@ -0,0 +1,479 @@
+
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 8192 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 13 /* log(BY2PG) */
+#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
+#define ICACHESIZE 0
+#define MB4 (4*1024*1024) /* Lots of things are 4Mb in size */
+
+#define MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ (60) /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+
+/*
+ * SR bits
+ */
+#define SUPER 0x2000
+#define SPL(n) (n<<8)
+
+/*
+ * CACR
+ */
+#define CCLEAR 0x08
+#define CENABLE 0x01
+
+/*
+ * Magic registers (unused in current system)
+ */
+
+#define MACH A5 /* A5 is m-> */
+#define USER A4 /* A4 is u-> */
+
+/*
+ * Fundamental addresses
+ */
+
+#define USERADDR 0x80000000
+/* assuming we're in a syscall, this is the address of the Ureg structure */
+#define UREGVARSZ (23*BY2WD) /* size of variable part of Ureg */
+#define UREGADDR (USERADDR+BY2PG-(UREGVARSZ+2+4+2+(8+8+1+1)*BY2WD))
+
+/*
+ * Devices poked during bootstrap
+ */
+#define TACADDR 0x40600000
+#define MOUSE 0x40200000
+
+/*
+ * MMU
+ */
+
+#define VAMASK 0xCFFFFFFF /* clear balu bits in address */
+#define KUSEG 0x00000000
+#define KSEG 0x80000000
+
+/*
+ * MMU entries
+ */
+#define PTEVALID (1<<13)
+#define PTEWRITE 0
+#define PTERONLY (1<<14)
+#define PTEKERNEL (1<<15)
+#define PTEUNCACHED 0
+#define INVALIDPTE 0
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 16
+
+#define PPN(pa) ((pa>>13)&0x1FFF)
+
+#define KMAP ((unsigned long *)0xD0000000)
+#define UMAP ((unsigned long *)0x50000000)
+
+/*
+ * Virtual addresses
+ */
+#define VTAG(va) ((va>>22)&0x03F)
+#define VPN(va) ((va>>13)&0x1FF)
+
+#define PARAM ((char*)0x40500000)
+#define TLBFLUSH_ 0x01
+
+/*
+ * Address spaces
+ */
+
+#define UZERO KUSEG /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define TSTKTOP 0x10000000 /* end of new stack in sysexec */
+#define TSTKSIZ 100
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define KZERO KSEG /* base of kernel address space */
+#define KTZERO (KZERO+BY2PG) /* first address in kernel text */
+#define USTKSIZE (4*1024*1024) /* size of user stack */
+
+#define MACHSIZE 4096
+
+
+#define isphys(p) ((((ulong)(p))&0xF0000000) == KSEG)
+#define DBMAGIC 0xBADC0C0A
+
+/*
+ * Boot first processor
+ */
+TEXT start(SB), $-4
+
+ MOVW $(SUPER|SPL(7)), SR
+ MOVL $a6base(SB), A6
+ MOVL $0, R0
+ MOVL R0, CACR
+ MOVL R0, TACADDR /* zero tac counter (cause an intr?) */
+
+ MOVL $mach0(SB), A0
+ MOVL A0, m(SB)
+ MOVL $0, 0(A0)
+ MOVL A0, A7
+ ADDL $(MACHSIZE-4), A7 /* start stack under machine struct */
+ MOVL $0, u(SB)
+
+ MOVL $vectors(SB), A0
+ MOVL A0, VBR
+
+ BSR main(SB)
+ /* never returns */
+dead:
+ BRA dead
+
+/*
+ * Take first processor into user mode. Leave enough room on the stack
+ * for a full-sized Ureg (including long bus error format) to fit
+ */
+
+TEXT touser(SB), $-4
+
+ MOVL $(USERADDR+BY2PG-UREGVARSZ), A7
+ MOVW $0, -(A7)
+ MOVL $(UTZERO+32), -(A7) /* header is in text */
+ MOVW $0, -(A7)
+ MOVL $(USTKTOP-6*BY2WD), A0 /* MAXSYSARG=6 */
+ MOVL A0, USP
+ MOVW $(SUPER|SPL(0)), SR
+ MOVL $8, R0
+ MOVL R0, CACR
+ RTE
+
+TEXT firmware(SB), $0
+
+ MOVL $0x40000090, A0
+ JMP (A0)
+
+TEXT splhi(SB), $0
+
+ MOVL m(SB), A0
+ MOVL (A7), 4(A0)
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(7)), SR
+ RTS
+
+TEXT splduart(SB), $0
+
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(5)), SR
+ RTS
+
+TEXT spllo(SB), $0
+
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(0)), SR
+ RTS
+
+TEXT splx(SB), $0
+
+ MOVL sr+0(FP), R0
+ MOVW R0, SR
+ RTS
+
+TEXT spldone(SB), $0
+
+ RTS
+
+TEXT spl1(SB), $0
+
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(1)), SR
+ RTS
+
+TEXT flushcpucache(SB), $0
+
+ MOVL $(CCLEAR|CENABLE), R0
+ MOVL R0, CACR
+ RTS
+
+TEXT cacrtrap(SB), $0 /* user entry point to control cache, e.g. flush */
+
+ MOVL R0, CACR
+ RTE
+
+TEXT setlabel(SB), $0
+
+ MOVL sr+0(FP), A0
+ MOVL A7, (A0)+ /* stack pointer */
+ MOVL (A7), (A0)+ /* pc of caller */
+ MOVW SR, (A0)+ /* status register */
+ CLRL R0 /* ret 0 => not returning */
+ RTS
+
+TEXT gotolabel(SB), $0
+
+ MOVL p+0(FP), A0
+ MOVW $(SUPER|SPL(7)), SR
+ MOVL (A0)+, A7 /* stack pointer */
+ MOVL (A0)+, (A7) /* pc; stuff into stack frame */
+ MOVW (A0)+, R0 /* status register */
+ MOVW R0, SR
+ MOVL $1, R0 /* ret 1 => returning */
+ RTS
+
+/*
+ * Test and set, as a subroutine
+ */
+
+TEXT tas(SB), $0
+
+ MOVL $0, R0
+ MOVL a+0(FP), A0
+ TAS (A0)
+ BEQ tas_1
+ MOVL $1, R0
+tas_1:
+ RTS
+
+/*
+ * Floating point
+ */
+
+TEXT fpsave(SB), $0
+
+ FSAVE (fp+0(FP))
+ RTS
+
+TEXT fprestore(SB), $0
+
+ FRESTORE (fp+0(FP))
+ RTS
+
+TEXT fpregsave(SB), $0
+
+ FMOVEM $0xFF, (3*4)(fr+0(FP))
+ FMOVEMC $0x7, (fr+0(FP))
+ RTS
+
+TEXT fpregrestore(SB), $0
+
+ FMOVEMC (fr+0(FP)), $0x7
+ FMOVEM (3*4)(fr+0(FP)), $0xFF
+ RTS
+
+TEXT fpcr(SB), $0
+
+ MOVL new+0(FP), R1
+ MOVL FPCR, R0
+ MOVL R1, FPCR
+ RTS
+
+
+TEXT rfnote(SB), $0
+
+ MOVL uregp+0(FP), A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1+1)*BY2WD), A7
+ RTE
+
+TEXT illegal(SB), $0
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR trap(SB)
+ ADDL $4, A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+TEXT systrap(SB), $0
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVL A6, ((8+6)*BY2WD)(A7)
+ MOVL R0, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR syscall(SB)
+ MOVL ((1+8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVL ((1+8+6)*BY2WD)(A7), A6
+ ADDL $((1+8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+TEXT buserror(SB), $0
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ PEA ((8+8+1+3)*BY2WD)(A7)
+ PEA 4(A7)
+ BSR fault68020(SB)
+ ADDL $8, A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+TEXT tacintr(SB), $0 /* level 1 */
+
+ MOVL R0, -(A7)
+ MOVL TACADDR, R0
+ MOVL (A7)+, R0
+ RTE
+
+TEXT portintr(SB), $0 /* level 2 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR devportintr(SB)
+ BRA retintr
+
+TEXT dkintr(SB), $0 /* level 3 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR inconintr(SB)
+ BRA retintr
+
+TEXT mouseintr(SB), $0 /* level 4 */
+
+ MOVEM $0x80C2, -(A7) /* D0, A0, A1, A6 */
+ MOVL $a6base(SB), A6
+ MOVL $15, R0 /* mask off hex switch */
+ ANDB MOUSE,R0 /* clears quadrature interrupt */
+ LEA mousetab(SB)(R0.W*8), A0
+ LEA mouse(SB), A1
+ MOVL (A0)+, R0
+ ADDL R0, (A1)+ /* dx */
+ MOVL (A0), R0
+ ADDL R0, (A1)+ /* dy */
+ ADDL $1, (A1) /* track */
+ MOVEM (A7)+, $0x4301
+ RTE
+
+TEXT uartintr(SB), $0 /* level 5 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR duartintr(SB)
+ BRA retintr
+
+TEXT syncintr(SB), $0 /* level 6 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR clock(SB)
+ /* fall through */
+retintr:
+ BSR mousetry(SB)
+ ADDL $4, A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+GLOBL duarttimer+0(SB),$4
+
+TEXT duartreadtimer+0(SB), $0
+ MOVW SR, R1 /* spl7() */
+ MOVW $0x2700, SR
+ MOVL $0x40100000, A0
+ CLRL R0
+ TSTB 15(A0) /* stop timer */
+ MOVW 6(A0), R0 /* read hi,lo */
+ TSTB 14(A0) /* restart timer */
+ NOTW R0 /* timer counts down from 0xffff */
+ ADDL duarttimer(SB), R0
+ MOVL R0, duarttimer(SB)
+ MOVW R1, SR
+ RTS
+
+GLOBL mousetab(SB), $128
+DATA mousetab+ 0(SB)/4, -1 /* x down, */
+DATA mousetab+ 4(SB)/4, 1 /* y up */
+DATA mousetab+ 8(SB)/4, 0 /* x - */
+DATA mousetab+ 12(SB)/4, 1 /* y up */
+DATA mousetab+ 16(SB)/4, 1 /* x up */
+DATA mousetab+ 20(SB)/4, 1 /* y up */
+DATA mousetab+ 24(SB)/4, 0 /* x - */
+DATA mousetab+ 28(SB)/4, 1 /* y up */
+DATA mousetab+ 32(SB)/4, -1 /* x down */
+DATA mousetab+ 36(SB)/4, 0 /* y - */
+DATA mousetab+ 40(SB)/4, 0 /* x - */
+DATA mousetab+ 44(SB)/4, 0 /* y - */
+DATA mousetab+ 48(SB)/4, 1 /* x up, */
+DATA mousetab+ 52(SB)/4, 0 /* y - */
+DATA mousetab+ 56(SB)/4, 0 /* x - */
+DATA mousetab+ 60(SB)/4, 0 /* y - */
+DATA mousetab+ 64(SB)/4, -1 /* x down */
+DATA mousetab+ 68(SB)/4, -1 /* y down */
+DATA mousetab+ 72(SB)/4, 0 /* x - */
+DATA mousetab+ 76(SB)/4, -1 /* y down */
+DATA mousetab+ 80(SB)/4, 1 /* x up */
+DATA mousetab+ 84(SB)/4, -1 /* y down */
+DATA mousetab+ 88(SB)/4, 0 /* x - */
+DATA mousetab+ 92(SB)/4, -1 /* y down */
+DATA mousetab+ 96(SB)/4, -1 /* x down */
+DATA mousetab+100(SB)/4, 0 /* y - */
+DATA mousetab+104(SB)/4, 0 /* x - */
+DATA mousetab+108(SB)/4, 0 /* y - */
+DATA mousetab+112(SB)/4, 1 /* x up */
+DATA mousetab+116(SB)/4, 0 /* y - */
+DATA mousetab+120(SB)/4, 0 /* x - */
+DATA mousetab+124(SB)/4, 0 /* y - */
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL u(SB), $4
+GLOBL m(SB), $4
diff --git a/utils/1a/lex.c b/utils/1a/lex.c
new file mode 100644
index 00000000..a3936d26
--- /dev/null
+++ b/utils/1a/lex.c
@@ -0,0 +1,925 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = '1';
+ thestring = "68000";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+ "TOS", LTOS, D_TOS,
+ "CCR", LTOS, D_CCR,
+ "SR", LTOS, D_SR,
+ "SFC", LTOS, D_SFC,
+ "DFC", LTOS, D_DFC,
+ "CACR", LTOS, D_CACR,
+ "USP", LTOS, D_USP,
+ "VBR", LTOS, D_VBR,
+ "CAAR", LTOS, D_CAAR,
+ "MSP", LTOS, D_MSP,
+ "ISP", LTOS, D_ISP,
+ "FPCR", LTOS, D_FPCR,
+ "FPSR", LTOS, D_FPSR,
+ "FPIAR", LTOS, D_FPIAR,
+ "TC", LTOS, D_TC,
+ "ITT0", LTOS, D_ITT0,
+ "ITT1", LTOS, D_ITT1,
+ "DTT0", LTOS, D_DTT0,
+ "DTT1", LTOS, D_DTT1,
+ "MMUSR", LTOS, D_MMUSR,
+ "URP", LTOS, D_URP,
+ "SRP", LTOS, D_SRP,
+
+ "R0", LDREG, D_R0+0,
+ "R1", LDREG, D_R0+1,
+ "R2", LDREG, D_R0+2,
+ "R3", LDREG, D_R0+3,
+ "R4", LDREG, D_R0+4,
+ "R5", LDREG, D_R0+5,
+ "R6", LDREG, D_R0+6,
+ "R7", LDREG, D_R0+7,
+
+ "A0", LAREG, D_A0+0,
+ "A1", LAREG, D_A0+1,
+ "A2", LAREG, D_A0+2,
+ "A3", LAREG, D_A0+3,
+ "A4", LAREG, D_A0+4,
+ "A5", LAREG, D_A0+5,
+ "A6", LAREG, D_A0+6,
+ "A7", LAREG, D_A0+7,
+
+ "F0", LFREG, D_F0+0,
+ "F1", LFREG, D_F0+1,
+ "F2", LFREG, D_F0+2,
+ "F3", LFREG, D_F0+3,
+ "F4", LFREG, D_F0+4,
+ "F5", LFREG, D_F0+5,
+ "F6", LFREG, D_F0+6,
+ "F7", LFREG, D_F0+7,
+
+ "ABCD", LTYPE1, AABCD,
+ "ADDB", LTYPE1, AADDB,
+ "ADDL", LTYPE1, AADDL,
+ "ADDW", LTYPE1, AADDW,
+ "ADDXB", LTYPE1, AADDXB,
+ "ADDXL", LTYPE1, AADDXL,
+ "ADDXW", LTYPE1, AADDXW,
+ "ADJSP", LTYPE5, AADJSP,
+ "ANDB", LTYPE1, AANDB,
+ "ANDL", LTYPE1, AANDL,
+ "ANDW", LTYPE1, AANDW,
+ "ASLB", LTYPE1, AASLB,
+ "ASLL", LTYPE1, AASLL,
+ "ASLW", LTYPE1, AASLW,
+ "ASRB", LTYPE1, AASRB,
+ "ASRL", LTYPE1, AASRL,
+ "ASRW", LTYPE1, AASRW,
+ "BCASE", LTYPE7, ABCASE,
+ "BCC", LTYPE6, ABCC,
+ "BCHG", LTYPE1, ABCHG,
+ "BCLR", LTYPE1, ABCLR,
+ "BCS", LTYPE6, ABCS,
+ "BEQ", LTYPE6, ABEQ,
+ "BFCHG", LTYPEA, ABFCHG,
+ "BFCLR", LTYPEA, ABFCLR,
+ "BFEXTS", LTYPEA, ABFEXTS,
+ "BFEXTU", LTYPEA, ABFEXTU,
+ "BFFFO", LTYPEA, ABFFFO,
+ "BFINS", LTYPEA, ABFINS,
+ "BFSET", LTYPEA, ABFSET,
+ "BFTST", LTYPEA, ABFTST,
+ "BGE", LTYPE6, ABGE,
+ "BGT", LTYPE6, ABGT,
+ "BHI", LTYPE6, ABHI,
+ "BKPT", LTYPE1, ABKPT,
+ "BLE", LTYPE6, ABLE,
+ "BLS", LTYPE6, ABLS,
+ "BLT", LTYPE6, ABLT,
+ "BMI", LTYPE6, ABMI,
+ "BNE", LTYPE6, ABNE,
+ "BPL", LTYPE6, ABPL,
+ "BRA", LTYPE6, ABRA,
+ "BSET", LTYPE1, ABSET,
+ "BSR", LTYPE3, ABSR,
+ "BTST", LTYPE1, ABTST,
+ "BVC", LTYPE6, ABVC,
+ "BVS", LTYPE6, ABVS,
+ "CALLM", LTYPE1, ACALLM,
+ "CAS2B", LTYPE1, ACAS2B,
+ "CAS2L", LTYPE1, ACAS2L,
+ "CAS2W", LTYPE1, ACAS2W,
+ "CASB", LTYPE1, ACASB,
+ "CASEW", LTYPE2, ACASEW,
+ "CASL", LTYPE1, ACASL,
+ "CASW", LTYPE1, ACASW,
+ "CHK2B", LTYPE1, ACHK2B,
+ "CHK2L", LTYPE1, ACHK2L,
+ "CHK2W", LTYPE1, ACHK2W,
+ "CHKL", LTYPE1, ACHKL,
+ "CHKW", LTYPE1, ACHKW,
+ "CLRB", LTYPE3, ACLRB,
+ "CLRL", LTYPE3, ACLRL,
+ "CLRW", LTYPE3, ACLRW,
+ "CMP2B", LTYPE1, ACMP2B,
+ "CMP2L", LTYPE1, ACMP2L,
+ "CMP2W", LTYPE1, ACMP2W,
+ "CMPB", LTYPE1, ACMPB,
+ "CMPL", LTYPE1, ACMPL,
+ "CMPW", LTYPE1, ACMPW,
+ "DATA", LTYPE4, ADATA,
+ "DBCC", LTYPE7, ADBCC,
+ "DBCS", LTYPE7, ADBCS,
+ "DBEQ", LTYPE7, ADBEQ,
+ "DBF", LTYPE7, ADBF,
+ "DBGE", LTYPE7, ADBGE,
+ "DBGT", LTYPE7, ADBGT,
+ "DBHI", LTYPE7, ADBHI,
+ "DBLE", LTYPE7, ADBLE,
+ "DBLS", LTYPE7, ADBLS,
+ "DBLT", LTYPE7, ADBLT,
+ "DBMI", LTYPE7, ADBMI,
+ "DBNE", LTYPE7, ADBNE,
+ "DBPL", LTYPE7, ADBPL,
+ "DBT", LTYPE7, ADBT,
+ "DBVC", LTYPE7, ADBVC,
+ "DBVS", LTYPE7, ADBVS,
+ "DIVSL", LTYPE1, ADIVSL,
+ "DIVSW", LTYPE1, ADIVSW,
+ "DIVUL", LTYPE1, ADIVUL,
+ "DIVUW", LTYPE1, ADIVUW,
+ "END", LTYPE2, AEND,
+ "EORB", LTYPE1, AEORB,
+ "EORL", LTYPE1, AEORL,
+ "EORW", LTYPE1, AEORW,
+ "EXG", LTYPE1, AEXG,
+ "EXTBL", LTYPE3, AEXTBL,
+ "EXTBW", LTYPE3, AEXTBW,
+ "EXTWL", LTYPE3, AEXTWL,
+ "FABSB", LTYPE1, AFABSB,
+ "FABSD", LTYPE1, AFABSD,
+ "FABSF", LTYPE1, AFABSF,
+ "FABSL", LTYPE1, AFABSL,
+ "FABSW", LTYPE1, AFABSW,
+ "FACOSB", LTYPE1, AFACOSB,
+ "FACOSD", LTYPE1, AFACOSD,
+ "FACOSF", LTYPE1, AFACOSF,
+ "FACOSL", LTYPE1, AFACOSL,
+ "FACOSW", LTYPE1, AFACOSW,
+ "FADDB", LTYPE1, AFADDB,
+ "FADDD", LTYPE1, AFADDD,
+ "FADDF", LTYPE1, AFADDF,
+ "FADDL", LTYPE1, AFADDL,
+ "FADDW", LTYPE1, AFADDW,
+ "FASINB", LTYPE1, AFASINB,
+ "FASIND", LTYPE1, AFASIND,
+ "FASINF", LTYPE1, AFASINF,
+ "FASINL", LTYPE1, AFASINL,
+ "FASINW", LTYPE1, AFASINW,
+ "FATANB", LTYPE1, AFATANB,
+ "FATAND", LTYPE1, AFATAND,
+ "FATANF", LTYPE1, AFATANF,
+ "FATANHB", LTYPE1, AFATANHB,
+ "FATANHD", LTYPE1, AFATANHD,
+ "FATANHF", LTYPE1, AFATANHF,
+ "FATANHL", LTYPE1, AFATANHL,
+ "FATANHW", LTYPE1, AFATANHW,
+ "FATANL", LTYPE1, AFATANL,
+ "FATANW", LTYPE1, AFATANW,
+ "FBEQ", LTYPE6, AFBEQ,
+ "FBF", LTYPE6, AFBF,
+ "FBGE", LTYPE6, AFBGE,
+ "FBGT", LTYPE6, AFBGT,
+ "FBLE", LTYPE6, AFBLE,
+ "FBLT", LTYPE6, AFBLT,
+ "FBNE", LTYPE6, AFBNE,
+ "FBT", LTYPE6, AFBT,
+ "FCMPB", LTYPE1, AFCMPB,
+ "FCMPD", LTYPE1, AFCMPD,
+ "FCMPF", LTYPE1, AFCMPF,
+ "FCMPL", LTYPE1, AFCMPL,
+ "FCMPW", LTYPE1, AFCMPW,
+ "FCOSB", LTYPE1, AFCOSB,
+ "FCOSD", LTYPE1, AFCOSD,
+ "FCOSF", LTYPE1, AFCOSF,
+ "FCOSHB", LTYPE1, AFCOSHB,
+ "FCOSHD", LTYPE1, AFCOSHD,
+ "FCOSHF", LTYPE1, AFCOSHF,
+ "FCOSHL", LTYPE1, AFCOSHL,
+ "FCOSHW", LTYPE1, AFCOSHW,
+ "FCOSL", LTYPE1, AFCOSL,
+ "FCOSW", LTYPE1, AFCOSW,
+ "FDBEQ", LTYPE7, AFDBEQ,
+ "FDBF", LTYPE7, AFDBF,
+ "FDBGE", LTYPE7, AFDBGE,
+ "FDBGT", LTYPE7, AFDBGT,
+ "FDBLE", LTYPE7, AFDBLE,
+ "FDBLT", LTYPE7, AFDBLT,
+ "FDBNE", LTYPE7, AFDBNE,
+ "FDBT", LTYPE7, AFDBT,
+ "FDIVB", LTYPE1, AFDIVB,
+ "FDIVD", LTYPE1, AFDIVD,
+ "FDIVF", LTYPE1, AFDIVF,
+ "FDIVL", LTYPE1, AFDIVL,
+ "FDIVW", LTYPE1, AFDIVW,
+ "FETOXB", LTYPE1, AFETOXB,
+ "FETOXD", LTYPE1, AFETOXD,
+ "FETOXF", LTYPE1, AFETOXF,
+ "FETOXL", LTYPE1, AFETOXL,
+ "FETOXM1B", LTYPE1, AFETOXM1B,
+ "FETOXM1D", LTYPE1, AFETOXM1D,
+ "FETOXM1F", LTYPE1, AFETOXM1F,
+ "FETOXM1L", LTYPE1, AFETOXM1L,
+ "FETOXM1W", LTYPE1, AFETOXM1W,
+ "FETOXW", LTYPE1, AFETOXW,
+ "FGETEXPB", LTYPE1, AFGETEXPB,
+ "FGETEXPD", LTYPE1, AFGETEXPD,
+ "FGETEXPF", LTYPE1, AFGETEXPF,
+ "FGETEXPL", LTYPE1, AFGETEXPL,
+ "FGETEXPW", LTYPE1, AFGETEXPW,
+ "FGETMANB", LTYPE1, AFGETMANB,
+ "FGETMAND", LTYPE1, AFGETMAND,
+ "FGETMANF", LTYPE1, AFGETMANF,
+ "FGETMANL", LTYPE1, AFGETMANL,
+ "FGETMANW", LTYPE1, AFGETMANW,
+ "FINTB", LTYPE1, AFINTB,
+ "FINTD", LTYPE1, AFINTD,
+ "FINTF", LTYPE1, AFINTF,
+ "FINTL", LTYPE1, AFINTL,
+ "FINTRZB", LTYPE1, AFINTRZB,
+ "FINTRZD", LTYPE1, AFINTRZD,
+ "FINTRZF", LTYPE1, AFINTRZF,
+ "FINTRZL", LTYPE1, AFINTRZL,
+ "FINTRZW", LTYPE1, AFINTRZW,
+ "FINTW", LTYPE1, AFINTW,
+ "FLOG10B", LTYPE1, AFLOG10B,
+ "FLOG10D", LTYPE1, AFLOG10D,
+ "FLOG10F", LTYPE1, AFLOG10F,
+ "FLOG10L", LTYPE1, AFLOG10L,
+ "FLOG10W", LTYPE1, AFLOG10W,
+ "FLOG2B", LTYPE1, AFLOG2B,
+ "FLOG2D", LTYPE1, AFLOG2D,
+ "FLOG2F", LTYPE1, AFLOG2F,
+ "FLOG2L", LTYPE1, AFLOG2L,
+ "FLOG2W", LTYPE1, AFLOG2W,
+ "FLOGNB", LTYPE1, AFLOGNB,
+ "FLOGND", LTYPE1, AFLOGND,
+ "FLOGNF", LTYPE1, AFLOGNF,
+ "FLOGNL", LTYPE1, AFLOGNL,
+ "FLOGNP1B", LTYPE1, AFLOGNP1B,
+ "FLOGNP1D", LTYPE1, AFLOGNP1D,
+ "FLOGNP1F", LTYPE1, AFLOGNP1F,
+ "FLOGNP1L", LTYPE1, AFLOGNP1L,
+ "FLOGNP1W", LTYPE1, AFLOGNP1W,
+ "FLOGNW", LTYPE1, AFLOGNW,
+ "FMODB", LTYPE1, AFMODB,
+ "FMODD", LTYPE1, AFMODD,
+ "FMODF", LTYPE1, AFMODF,
+ "FMODL", LTYPE1, AFMODL,
+ "FMODW", LTYPE1, AFMODW,
+ "FMOVEB", LTYPE1, AFMOVEB,
+ "FMOVED", LTYPE1, AFMOVED,
+ "FMOVEF", LTYPE1, AFMOVEF,
+ "FMOVEL", LTYPE1, AFMOVEL,
+ "FMOVEW", LTYPE1, AFMOVEW,
+ "FMULB", LTYPE1, AFMULB,
+ "FMULD", LTYPE1, AFMULD,
+ "FMULF", LTYPE1, AFMULF,
+ "FMULL", LTYPE1, AFMULL,
+ "FMULW", LTYPE1, AFMULW,
+ "FNEGB", LTYPE8, AFNEGB,
+ "FNEGD", LTYPE8, AFNEGD,
+ "FNEGF", LTYPE8, AFNEGF,
+ "FNEGL", LTYPE8, AFNEGL,
+ "FNEGW", LTYPE8, AFNEGW,
+ "FREMB", LTYPE1, AFREMB,
+ "FREMD", LTYPE1, AFREMD,
+ "FREMF", LTYPE1, AFREMF,
+ "FREML", LTYPE1, AFREML,
+ "FREMW", LTYPE1, AFREMW,
+ "FSCALEB", LTYPE1, AFSCALEB,
+ "FSCALED", LTYPE1, AFSCALED,
+ "FSCALEF", LTYPE1, AFSCALEF,
+ "FSCALEL", LTYPE1, AFSCALEL,
+ "FSCALEW", LTYPE1, AFSCALEW,
+ "FSEQ", LTYPE1, AFSEQ,
+ "FSF", LTYPE1, AFSF,
+ "FSGE", LTYPE1, AFSGE,
+ "FSGT", LTYPE1, AFSGT,
+ "FSINB", LTYPE1, AFSINB,
+ "FSIND", LTYPE1, AFSIND,
+ "FSINF", LTYPE1, AFSINF,
+ "FSINHB", LTYPE1, AFSINHB,
+ "FSINHD", LTYPE1, AFSINHD,
+ "FSINHF", LTYPE1, AFSINHF,
+ "FSINHL", LTYPE1, AFSINHL,
+ "FSINHW", LTYPE1, AFSINHW,
+ "FSINL", LTYPE1, AFSINL,
+ "FSINW", LTYPE1, AFSINW,
+ "FSLE", LTYPE1, AFSLE,
+ "FSLT", LTYPE1, AFSLT,
+ "FSNE", LTYPE1, AFSNE,
+ "FSQRTB", LTYPE1, AFSQRTB,
+ "FSQRTD", LTYPE1, AFSQRTD,
+ "FSQRTF", LTYPE1, AFSQRTF,
+ "FSQRTL", LTYPE1, AFSQRTL,
+ "FSQRTW", LTYPE1, AFSQRTW,
+ "FST", LTYPE1, AFST,
+ "FSUBB", LTYPE1, AFSUBB,
+ "FSUBD", LTYPE1, AFSUBD,
+ "FSUBF", LTYPE1, AFSUBF,
+ "FSUBL", LTYPE1, AFSUBL,
+ "FSUBW", LTYPE1, AFSUBW,
+ "FTANB", LTYPE1, AFTANB,
+ "FTAND", LTYPE1, AFTAND,
+ "FTANF", LTYPE1, AFTANF,
+ "FTANHB", LTYPE1, AFTANHB,
+ "FTANHD", LTYPE1, AFTANHD,
+ "FTANHF", LTYPE1, AFTANHF,
+ "FTANHL", LTYPE1, AFTANHL,
+ "FTANHW", LTYPE1, AFTANHW,
+ "FTANL", LTYPE1, AFTANL,
+ "FTANW", LTYPE1, AFTANW,
+ "FTENTOXB", LTYPE1, AFTENTOXB,
+ "FTENTOXD", LTYPE1, AFTENTOXD,
+ "FTENTOXF", LTYPE1, AFTENTOXF,
+ "FTENTOXL", LTYPE1, AFTENTOXL,
+ "FTENTOXW", LTYPE1, AFTENTOXW,
+ "FTSTB", LTYPE1, AFTSTB,
+ "FTSTD", LTYPE1, AFTSTD,
+ "FTSTF", LTYPE1, AFTSTF,
+ "FTSTL", LTYPE1, AFTSTL,
+ "FTSTW", LTYPE1, AFTSTW,
+ "FTWOTOXB", LTYPE1, AFTWOTOXB,
+ "FTWOTOXD", LTYPE1, AFTWOTOXD,
+ "FTWOTOXF", LTYPE1, AFTWOTOXF,
+ "FTWOTOXL", LTYPE1, AFTWOTOXL,
+ "FTWOTOXW", LTYPE1, AFTWOTOXW,
+ "FMOVEM", LTYPE1, AFMOVEM,
+ "FMOVEMC", LTYPE1, AFMOVEMC,
+ "FRESTORE", LTYPE3, AFRESTORE,
+ "FSAVE", LTYPE3, AFSAVE,
+ "GLOBL", LTYPE1, AGLOBL,
+ "GOK", LTYPE2, AGOK,
+ "HISTORY", LTYPE2, AHISTORY,
+ "ILLEG", LTYPE2, AILLEG,
+ "INSTR", LTYPE3, AINSTR,
+ "JMP", LTYPE3, AJMP,
+ "JSR", LTYPE3, AJSR,
+ "LEA", LTYPE1, ALEA,
+ "LINKL", LTYPE1, ALINKL,
+ "LINKW", LTYPE1, ALINKW,
+ "LOCATE", LTYPE1, ALOCATE,
+ "LONG", LTYPE3, ALONG,
+ "LSLB", LTYPE1, ALSLB,
+ "LSLL", LTYPE1, ALSLL,
+ "LSLW", LTYPE1, ALSLW,
+ "LSRB", LTYPE1, ALSRB,
+ "LSRL", LTYPE1, ALSRL,
+ "LSRW", LTYPE1, ALSRW,
+ "MOVB", LTYPE1, AMOVB,
+ "MOVEM", LTYPE1, AMOVEM,
+ "MOVEPL", LTYPE1, AMOVEPL,
+ "MOVEPW", LTYPE1, AMOVEPW,
+ "MOVESB", LTYPE1, AMOVESB,
+ "MOVESL", LTYPE1, AMOVESL,
+ "MOVESW", LTYPE1, AMOVESW,
+ "MOVL", LTYPE1, AMOVL,
+ "MOVW", LTYPE1, AMOVW,
+ "MULSL", LTYPE1, AMULSL,
+ "MULSW", LTYPE1, AMULSW,
+ "MULUL", LTYPE1, AMULUL,
+ "MULUW", LTYPE1, AMULUW,
+ "NAME", LTYPE1, ANAME,
+ "NBCD", LTYPE3, ANBCD,
+ "NEGB", LTYPE3, ANEGB,
+ "NEGL", LTYPE3, ANEGL,
+ "NEGW", LTYPE3, ANEGW,
+ "NEGXB", LTYPE3, ANEGXB,
+ "NEGXL", LTYPE3, ANEGXL,
+ "NEGXW", LTYPE3, ANEGXW,
+ "NOP", LTYPE9, ANOP,
+ "NOTB", LTYPE3, ANOTB,
+ "NOTL", LTYPE3, ANOTL,
+ "NOTW", LTYPE3, ANOTW,
+ "ORB", LTYPE1, AORB,
+ "ORL", LTYPE1, AORL,
+ "ORW", LTYPE1, AORW,
+ "PACK", LTYPE1, APACK,
+ "PEA", LTYPE3, APEA,
+ "RESET", LTYPE2, ARESET,
+ "ROTLB", LTYPE1, AROTLB,
+ "ROTLL", LTYPE1, AROTLL,
+ "ROTLW", LTYPE1, AROTLW,
+ "ROTRB", LTYPE1, AROTRB,
+ "ROTRL", LTYPE1, AROTRL,
+ "ROTRW", LTYPE1, AROTRW,
+ "ROXLB", LTYPE1, AROXLB,
+ "ROXLL", LTYPE1, AROXLL,
+ "ROXLW", LTYPE1, AROXLW,
+ "ROXRB", LTYPE1, AROXRB,
+ "ROXRL", LTYPE1, AROXRL,
+ "ROXRW", LTYPE1, AROXRW,
+ "RTD", LTYPE3, ARTD,
+ "RTE", LTYPE2, ARTE,
+ "RTM", LTYPE3, ARTM,
+ "RTR", LTYPE2, ARTR,
+ "RTS", LTYPE2, ARTS,
+ "SBCD", LTYPE1, ASBCD,
+ "SCC", LTYPE3, ASCC,
+ "SCS", LTYPE3, ASCS,
+ "SEQ", LTYPE3, ASEQ,
+ "SF", LTYPE3, ASF,
+ "SGE", LTYPE3, ASGE,
+ "SGT", LTYPE3, ASGT,
+ "SHI", LTYPE3, ASHI,
+ "SLE", LTYPE3, ASLE,
+ "SLS", LTYPE3, ASLS,
+ "SLT", LTYPE3, ASLT,
+ "SMI", LTYPE3, ASMI,
+ "SNE", LTYPE3, ASNE,
+ "SPL", LTYPE3, ASPL,
+ "ST", LTYPE3, AST,
+ "STOP", LTYPE3, ASTOP,
+ "SUBB", LTYPE1, ASUBB,
+ "SUBL", LTYPE1, ASUBL,
+ "SUBW", LTYPE1, ASUBW,
+ "SUBXB", LTYPE1, ASUBXB,
+ "SUBXL", LTYPE1, ASUBXL,
+ "SUBXW", LTYPE1, ASUBXW,
+ "SVC", LTYPE2, ASVC,
+ "SVS", LTYPE2, ASVS,
+ "SWAP", LTYPE3, ASWAP,
+ "SYS", LTYPE2, ASYS,
+ "TAS", LTYPE3, ATAS,
+ "TEXT", LTYPEB, ATEXT,
+ "TRAP", LTYPE3, ATRAP,
+ "TRAPCC", LTYPE2, ATRAPCC,
+ "TRAPCS", LTYPE2, ATRAPCS,
+ "TRAPEQ", LTYPE2, ATRAPEQ,
+ "TRAPF", LTYPE2, ATRAPF,
+ "TRAPGE", LTYPE2, ATRAPGE,
+ "TRAPGT", LTYPE2, ATRAPGT,
+ "TRAPHI", LTYPE2, ATRAPHI,
+ "TRAPLE", LTYPE2, ATRAPLE,
+ "TRAPLS", LTYPE2, ATRAPLS,
+ "TRAPLT", LTYPE2, ATRAPLT,
+ "TRAPMI", LTYPE2, ATRAPMI,
+ "TRAPNE", LTYPE2, ATRAPNE,
+ "TRAPPL", LTYPE2, ATRAPPL,
+ "TRAPT", LTYPE2, ATRAPT,
+ "TRAPV", LTYPE2, ATRAPV,
+ "TRAPVC", LTYPE2, ATRAPVC,
+ "TRAPVS", LTYPE2, ATRAPVS,
+ "TSTB", LTYPE3, ATSTB,
+ "TSTL", LTYPE3, ATSTL,
+ "TSTW", LTYPE3, ATSTW,
+ "UNLK", LTYPE3, AUNLK,
+ "UNPK", LTYPE1, AUNPK,
+ "WORD", LTYPE3, AWORD,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.s0.sym = S;
+ nullgen.s0.offset = 0;
+ nullgen.type = D_NONE;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+ nullgen.displace = 0;
+ nullgen.type = D_NONE;
+ nullgen.field = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+ Gen2 g2;
+
+ g2.from = nullgen;
+ g2.to = nullgen;
+ outcode(AEND, &g2);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME); /* as */
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->field)
+ t |= T_FIELD;
+ if(a->displace != 0)
+ t |= T_INDEX;
+ if(a->s0.offset != 0)
+ t |= T_OFFSET;
+ if(s != 0)
+ t |= T_SYM;
+
+ if(a->type == D_FCONST)
+ t |= T_FCONST;
+ else
+ if(a->type == D_SCONST)
+ t |= T_SCONST;
+ else
+ if(a->type & ~0xff)
+ t |= T_TYPE;
+ Bputc(&obuf, t);
+
+ if(t & T_FIELD) { /* implies field */
+ i = a->field;
+ Bputc(&obuf, i);
+ Bputc(&obuf, i>>8);
+ }
+ if(t & T_INDEX) { /* implies index, scale, displace */
+ i = D_NONE;
+ Bputc(&obuf, i);
+ Bputc(&obuf, i>>8);
+ Bputc(&obuf, 0);
+ l = a->displace;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->s0.offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(&obuf, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ l = e.h;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ return;
+ }
+ i = a->type;
+ Bputc(&obuf, i);
+ if(t & T_TYPE)
+ Bputc(&obuf, i>>8);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+
+jackpot:
+ sf = 0;
+ s = g2->from.s0.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g2->from.type & D_MASK;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->to.s0.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->to.type & D_MASK;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, a>>8);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(&g2->from, sf);
+ zaddr(&g2->to, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.s0.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, AHISTORY>>8);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/1a/mkfile b/utils/1a/mkfile
new file mode 100644
index 00000000..da0bd1f5
--- /dev/null
+++ b/utils/1a/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=1a
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../2c/2.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/1c/cgen.c b/utils/1c/cgen.c
new file mode 100644
index 00000000..2f121e51
--- /dev/null
+++ b/utils/1c/cgen.c
@@ -0,0 +1,1396 @@
+#include "gc.h"
+
+void
+cgen(Node *n, int result, Node *nn)
+{
+ Node *l, *r, nod;
+ int lg, rg, xg, yg, g, o;
+ long v;
+ Prog *p1;
+
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, result, nn, n->type->width);
+ return;
+ }
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "cgen");
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(result == D_NONE) {
+ if(nn == Z)
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n->type, nn->type, D_TREE, n, result, nn);
+ return;
+ }
+
+ v = 0; /* set */
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ /*
+ * recursive use of result
+ */
+ if(result == D_NONE)
+ if(l->addable > INDEXED)
+ if(l->complex < FNX) {
+ cgen(r, D_TREE, l);
+ break;
+ }
+
+ /*
+ * function calls on both sides
+ */
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ adjsp(v - argoff);
+ gmove(r->type, l->type, D_TOS, r, lg, l);
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+
+ rg = D_TREE;
+ lg = D_TREE;
+ if(r->complex >= l->complex) {
+ /*
+ * right side before left
+ */
+ if(result != D_NONE) {
+ rg = regalloc(n->type, result);
+ cgen(r, rg, n);
+ } else
+ if(r->complex >= FNX || r->addable < INDEXED) {
+ rg = regalloc(r->type, result);
+ cgen(r, rg, r);
+ }
+ if(l->addable < INDEXED) {
+ lg = regaddr(lg);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ } else {
+ /*
+ * left before right
+ */
+ if(l->complex >= FNX || l->addable < INDEXED) {
+ lg = regaddr(lg);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(result != D_NONE) {
+ rg = regalloc(n->type, result);
+ cgen(r, rg, n);
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(r->type, result);
+ cgen(r, rg, r);
+ }
+ }
+ if(result != D_NONE) {
+ gmove(n->type, l->type, rg, r, lg, l);
+ gmove(n->type, nn->type, rg, r, result, nn);
+ } else
+ gmove(r->type, l->type, rg, r, lg, l);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ bitas:
+ n = l->left;
+ rg = regalloc(tfield, result);
+ if(l->complex >= r->complex) {
+ lg = regaddr(D_NONE);
+ lcgen(n, lg, Z);
+ lg |= I_INDIR;
+ cgen(r, rg, r);
+ } else {
+ cgen(r, rg, r);
+ lg = regaddr(D_NONE);
+ lcgen(n, lg, Z);
+ lg |= I_INDIR;
+ }
+ g = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, g, l);
+ bitstore(l, rg, lg, g, result, nn);
+ break;
+
+ case OBIT:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ g = bitload(n, D_NONE, D_NONE, result, nn);
+ gopcode(OAS, nn->type, g, n, result, nn);
+ regfree(g);
+ break;
+
+ case ODOT:
+ sugen(l, D_TREE, nodrat, l->type->width);
+ if(result != D_NONE) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += r->vconst;
+ nod.type = n->type;
+ cgen(&nod, result, nn);
+ }
+ break;
+
+ case OASLDIV:
+ case OASLMOD:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ if(l->complex >= FNX || r->complex >= FNX) {
+ rg = D_TOS;
+ cgen(r, rg, r);
+ v = argoff;
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ lg = D_TREE;
+ if(!simplv(l)) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z); /* destroys register optimization */
+ lg |= I_INDIR;
+ }
+ g = regpair(result);
+ gmove(l->type, n->type, lg, l, g, n);
+ if(rg == D_TOS)
+ adjsp(v - argoff);
+ gopcode(o, n->type, rg, r, g, n);
+ if(o == OASLMOD || o == OASMOD)
+ gmove(n->type, l->type, g+1, n, lg, l);
+ else
+ gmove(n->type, l->type, g, n, lg, l);
+ if(result != D_NONE)
+ if(o == OASLMOD || o == OASMOD)
+ gmove(n->type, nn->type, g+1, n, result, nn);
+ else
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ regfree(g+1);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ if(r->op != OCONST) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ gopcode(o, l->type, rg, r, D_TREE, l);
+ regfree(rg);
+ break;
+
+ case OASADD:
+ case OASSUB:
+ if(l->op == OBIT ||
+ l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ v = vconst(r);
+ if(v > 0 && v <= 8) {
+ gopcode(o, n->type, D_TREE, r, D_TREE, l);
+ break;
+ }
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ gopcode(o, n->type, rg, r, D_TREE, l);
+ regfree(rg);
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ if(l->op == OBIT ||
+ l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ lg = regalloc(n->type, D_NONE);
+ cgen(l, lg, l);
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, n->type, lg, l, D_TREE, l);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ asbinop:
+ if(l->op == OBIT)
+ goto asbitop;
+ rg = D_TREE;
+ if(l->complex >= FNX || r->complex >= FNX) {
+ rg = D_TOS;
+ cgen(r, rg, r);
+ v = argoff;
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ } else {
+ if(o == OASLSHR || o == OASASHR || o == OASASHL) {
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ }
+ }
+ lg = D_TREE;
+ if(!simplv(l)) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z); /* destroys register optimization */
+ lg |= I_INDIR;
+ }
+ g = regalloc(n->type, result);
+ gmove(l->type, n->type, lg, l, g, n);
+ if(rg == D_TOS)
+ adjsp(v - argoff);
+ if(o == OASXOR)
+ if(rg == D_TREE) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL)
+ if(rg == D_TOS) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(n->type, n->type, D_TOS, n, rg, n);
+ }
+ gopcode(o, n->type, rg, r, g, n);
+ gmove(n->type, l->type, g, n, lg, l);
+ if(result != D_NONE)
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ asbitop:
+ rg = regaddr(D_NONE);
+ lg = regalloc(tfield, D_NONE);
+ if(l->complex >= r->complex) {
+ g = bitload(l, lg, rg, result, nn);
+ xg = regalloc(r->type, D_NONE);
+ cgen(r, xg, nn);
+ } else {
+ xg = regalloc(r->type, D_NONE);
+ cgen(r, xg, nn);
+ g = bitload(l, lg, rg, result, nn);
+ }
+
+ if(!typefd[n->type->etype]) {
+ if(o == OASLDIV || o == OASDIV) {
+ yg = regpair(result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg, n, g, l);
+ regfree(yg);
+ regfree(yg+1);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ if(o == OASLMOD || o == OASMOD) {
+ yg = regpair(result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg+1, n, g, l);
+ regfree(yg);
+ regfree(yg+1);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ }
+
+ yg = regalloc(n->type, result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg, n, g, l);
+ regfree(yg);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+
+ case OCAST:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = result;
+ if(l->complex >= FNX)
+ lg = regret(l->type);
+ lg = eval(l, lg);
+ if(nocast(l->type, n->type)) {
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ if(nocast(n->type, nn->type)) {
+ gmove(l->type, n->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ rg = regalloc(n->type, result);
+ gmove(l->type, n->type, lg, l, rg, n);
+ gmove(n->type, nn->type, rg, n, result, nn);
+ regfree(rg);
+ regfree(lg);
+ break;
+
+ case OCOND:
+ doinc(l, PRE);
+ boolgen(l, 1, D_NONE, Z, l);
+ p1 = p;
+
+ inargs++;
+ doinc(r->left, PRE);
+ cgen(r->left, result, nn);
+ doinc(r->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ cgen(r->right, result, nn);
+ doinc(r->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OIND:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = nodalloc(types[TIND], result, &nod);
+ nod.lineno = n->lineno;
+ if(l->op == OADD) {
+ if(l->left->op == OCONST) {
+ nod.xoffset += l->left->vconst;
+ l = l->right;
+ } else
+ if(l->right->op == OCONST) {
+ nod.xoffset += l->right->vconst;
+ l = l->left;
+ }
+ }
+ cgen(l, lg, l);
+ gmove(n->type, nn->type, D_TREE, &nod, result, nn);
+ regfree(lg);
+ break;
+
+ case OFUNC:
+ v = argoff;
+ inargs++;
+ gargs(r);
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ inargs--;
+ doinc(r, POST);
+ doinc(l, POST);
+ gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
+ regfree(lg);
+ if(inargs)
+ adjsp(v - argoff);
+ if(result != D_NONE) {
+ lg = regret(n->type);
+ gmove(n->type, nn->type, lg, n, result, nn);
+ }
+ break;
+
+ case OLDIV:
+ case OLMOD:
+ case ODIV:
+ case OMOD:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto binop;
+ if(r->addable >= INDEXED && r->complex < FNX) {
+ lg = regpair(result);
+ cgen(l, lg, l);
+ rg = D_TREE;
+ } else {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regpair(result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ rg = D_TOS;
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ if(o == OMOD || o == OLMOD)
+ gmove(l->type, nn->type, lg+1, l, result, nn);
+ else
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(lg+1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ if(l->op == OCONST)
+ if(mulcon(r, l, result, nn))
+ break;
+ if(r->op == OCONST)
+ if(mulcon(l, r, result, nn))
+ break;
+ if(debug['M'])
+ print("%L multiply\n", n->lineno);
+ goto binop;
+
+ case OAND:
+ if(r->op == OCONST)
+ if(typeil[n->type->etype])
+ if(l->op == OCAST) {
+ if(typec[l->left->type->etype])
+ if(!(r->vconst & ~0xff)) {
+ l = l->left;
+ goto binop;
+ }
+ if(typeh[l->left->type->etype])
+ if(!(r->vconst & ~0xffff)) {
+ l = l->left;
+ goto binop;
+ }
+ }
+ goto binop;
+
+ case OADD:
+ if(result == D_TOS)
+ if(r->addable >= INDEXED)
+ if(l->op == OCONST)
+ if(typeil[l->type->etype]) {
+ v = l->vconst;
+ if(v > -32768 && v < 32768) {
+ rg = regaddr(D_NONE);
+ gmove(r->type, r->type, D_TREE, r, rg, r);
+ gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r);
+ p->to.offset = v;
+ p->to.type |= I_INDIR;
+ regfree(rg);
+ break;
+ }
+ }
+
+ case OSUB:
+ if(result == D_TOS)
+ if(l->addable >= INDEXED)
+ if(r->op == OCONST)
+ if(typeil[r->type->etype]) {
+ v = r->vconst;
+ if(v > -32768 && v < 32768) {
+ if(n->op == OSUB)
+ v = -v;
+ lg = regaddr(D_NONE);
+ gmove(l->type, l->type, D_TREE, l, lg, l);
+ gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l);
+ p->to.offset = v;
+ p->to.type |= I_INDIR;
+ regfree(lg);
+ break;
+ }
+ }
+ goto binop;
+
+ case OOR:
+ case OXOR:
+ binop:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ if(o == OXOR) {
+ rg = regalloc(r->type, D_NONE);
+ gmove(r->type, r->type, D_TOS, r, rg, r);
+ gopcode(o, n->type, rg, r, lg, l);
+ regfree(rg);
+ } else
+ gopcode(o, n->type, D_TOS, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OADDR && (o == OADD || o == OSUB))
+ lg = regaddr(result);
+ else
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ rg = eval(r, D_NONE);
+ } else {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ }
+ if(o == OXOR) {
+ if(rg == D_TREE) {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ if(rg == D_TOS) {
+ rg = regalloc(r->type, D_NONE);
+ gmove(r->type, r->type, D_TOS, r, rg, r);
+ }
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASHL:
+ if(r->op == OCONST)
+ if(shlcon(l, r, result, nn))
+ break;
+ case OLSHR:
+ case OASHR:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ rg = regalloc(r->type, D_NONE);
+ gopcode(OAS, r->type, D_TOS, r, rg, r);
+ gopcode(n->op, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ } else
+ rg = eval(r, D_NONE);
+ } else {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ gopcode(o, l->type, D_NONE, Z, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+
+ case OADDR:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, result, nn);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, result, nn, Z);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, result, nn, Z);
+ if(result == D_NONE)
+ patch(p, pc);
+ break;
+
+ case OCOMMA:
+ cgen(l, D_NONE, l);
+ doinc(l, POST);
+ doinc(r, PRE);
+ cgen(r, result, nn);
+ break;
+
+ case ONOT:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, result, nn, Z);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ if(typefd[n->type->etype]) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, rg, l);
+ gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
+ gmove(l->type, l->type, rg, l, lg, l);
+ regfree(rg);
+ } else {
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
+ }
+ regfree(lg);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(typefd[n->type->etype]) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, rg, l);
+ gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
+ gmove(l->type, l->type, rg, l, lg, l);
+ regfree(rg);
+ } else {
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
+ }
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+
+ bitinc:
+ rg = regaddr(D_NONE);
+ lg = regalloc(tfield, D_NONE);
+ if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) {
+ g = bitload(l, lg, rg, D_NONE, nn);
+ if(nn != Z)
+ gmove(l->type, nn->type, g, l, result, nn);
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), g, n);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ g = bitload(l, lg, rg, result, nn);
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), g, n);
+ if(result != D_NONE)
+ gmove(l->type, nn->type, g, l, result, nn);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+}
+
+void
+lcgen(Node *n, int result, Node *nn)
+{
+ Node rn;
+ Prog *p1;
+ int lg;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "lcgen");
+ }
+ if(nn == Z) {
+ nn = &rn;
+ nn->type = types[TIND];
+ }
+ switch(n->op) {
+ case OCOMMA:
+ cgen(n->left, D_NONE, n->left);
+ doinc(n->left, POST);
+ doinc(n->right, PRE);
+ lcgen(n->right, result, nn);
+ break;
+
+ case OCOND:
+ doinc(n->left, PRE);
+ boolgen(n->left, 1, D_NONE, Z, n->left);
+ p1 = p;
+
+ inargs++;
+ doinc(n->right->left, PRE);
+ lcgen(n->right->left, result, nn);
+ doinc(n->right->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(n->right->right, PRE);
+ lcgen(n->right->right, result, nn);
+ doinc(n->right->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OIND:
+ if(n->addable >= INDEXED) {
+ if(result >= D_A0 && result < D_A0+NREG) {
+ gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
+ break;
+ }
+ if(result == D_TOS) {
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
+ break;
+ }
+ }
+ cgen(n->left, result, nn);
+ break;
+
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ if(result >= D_A0 && result < D_A0+NREG) {
+ gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
+ break;
+ }
+ if(result == D_TOS) {
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
+ break;
+ }
+ lg = regaddr(result);
+ gopcode(OADDR, types[TLONG], D_TREE, n, lg, nn);
+ gopcode(OAS, nn->type, lg, nn, result, nn);
+ regfree(lg);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ boolgen(n, true, D_NONE, Z, Z);
+}
+
+void
+boolgen(Node *n, int true, int result, Node *nn, Node *post)
+{
+ Prog *p1, *p2;
+ Node *l, *r;
+ int lg, rg, fp, o;
+ long v;
+
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "boolgen");
+ }
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ lg = eval(n, result);
+ if(lg >= D_A0 && lg < D_A0+NREG) {
+ rg = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], lg, n, rg, Z);
+ regfree(rg);
+ } else
+ gopcode(OTST, n->type, D_NONE, Z, lg, n);
+ regfree(lg);
+ o = ONE;
+ fp = typefd[n->type->etype];
+ goto genbool;
+
+ case OCONST:
+ fp = vconst(n);
+ if(!true)
+ fp = !fp;
+ gbranch(OGOTO);
+ if(fp) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case ONOT:
+ boolgen(l, !true, result, nn, post);
+ break;
+
+ case OCOND:
+ doinc(l, PRE);
+ boolgen(l, 1, D_NONE, Z, l);
+ p1 = p;
+
+ inargs++;
+ doinc(r->left, PRE);
+ boolgen(r->left, true, result, nn, r->left);
+ if(result != D_NONE) {
+ doinc(r->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ boolgen(r->right, !true, result, nn, r->right);
+ doinc(r->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+ }
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ boolgen(r->right, !true, result, nn, r->right);
+ patch(p2, pc);
+ p2 = p;
+ if(doinc(post, POST|TEST)) {
+ lg = regalloc(types[TSHORT], D_NONE);
+ gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
+ doinc(post, POST);
+ gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
+ regfree(lg);
+ }
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ doinc(l, PRE);
+ boolgen(l, true, D_NONE, Z, l);
+ p1 = p;
+ inargs++;
+ doinc(r, PRE);
+ boolgen(r, !true, D_NONE, Z, r);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ doinc(l, PRE);
+ boolgen(l, !true, D_NONE, Z, l);
+ p1 = p;
+ inargs++;
+ doinc(r, PRE);
+ boolgen(r, !true, D_NONE, Z, r);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OEQ:
+ case ONE:
+ if(vconst(l) == 0) {
+ if(n->op == ONE) {
+ boolgen(r, true, result, nn, post);
+ break;
+ }
+ boolgen(r, !true, result, nn, post);
+ break;
+ }
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ fp = typefd[r->type->etype];
+ if(l->op == OCONST) {
+ v = vconst(l);
+ if(v == 0) { /* tst instruction */
+ o = invrel[relindex(n->op)];
+ rg = eval(r, result);
+ gopcode(OTST, r->type, D_NONE, Z, rg, r);
+ regfree(rg);
+ goto genbool;
+ }
+ if(!fp) { /* cmpi and movq, saves about .5% both time and space */
+ if(v < 128 && v >= -128 &&
+ ewidth[r->type->etype] == SZ_LONG) {
+ rg = eval(r, result);
+ lg = regalloc(l->type, D_NONE);
+ cgen(l, lg, l);
+ o = n->op;
+ gopcode(o, l->type, lg, l, rg, r);
+ regfree(lg);
+ regfree(rg);
+ goto genbool;
+ }
+ o = invrel[relindex(n->op)];
+ rg = eval(r, result);
+ gopcode(o, r->type, rg, r, D_TREE, l);
+ regfree(rg);
+ goto genbool;
+ }
+ }
+ lg = D_TOS;
+ if(r->complex < FNX)
+ lg = regalloc(l->type, lg);
+ cgen(l, lg, l);
+ v = argoff;
+ rg = eval(r, result);
+ if(lg == D_TOS) {
+ adjsp(v - argoff);
+ lg = regalloc(l->type, lg);
+ gopcode(OAS, l->type, D_TOS, l, lg, l);
+ }
+ o = n->op;
+ gopcode(o, l->type, lg, l, rg, r);
+ regfree(lg);
+ regfree(rg);
+
+ genbool:
+ if(true)
+ o = comrel[relindex(o)];
+ if(doinc(post, POST|TEST)) {
+ lg = regalloc(types[TSHORT], D_NONE);
+ gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
+ doinc(post, POST);
+ gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
+ regfree(lg);
+ }
+ gbranch(o);
+ if(fp)
+ fpbranch();
+
+ com:
+ if(result == D_NONE)
+ break;
+ p1 = p;
+ gopcode(OAS, nn->type, D_CONST, nodconst(1), result, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nn->type, D_CONST, nodconst(0), result, nn);
+ patch(p2, pc);
+ break;
+ }
+}
+
+void
+sugen(Node *n, int result, Node *nn, long w)
+{
+ long s, v, o;
+ int lg, rg, ng;
+ Prog *p1;
+ Node *l, *r, nod;
+ Type *t;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R width = %ld\n", result, w);
+ prtree(n, "sugen");
+ }
+ s = argoff;
+ if(result == D_TREE) {
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ }
+
+ if(n->addable >= INDEXED && n->op != OCONST)
+ goto copy;
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in sugen: %O", n->op);
+ break;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(result == D_NONE) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ lg = regaddr(D_NONE);
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ if(result == D_TREE) {
+ lcgen(nn, lg, Z);
+ } else
+ diag(n, "unknown su result: %R", result);
+
+ gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst>>32)),
+ lg|I_INDINC, n);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst)),
+ lg|I_INDINC, n);
+ regfree(lg);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, D_TREE, nodrat, l->type->width);
+ if(result != D_NONE) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += r->vconst;
+ nod.type = n->type;
+ sugen(&nod, result, nn, w);
+ }
+ break;
+
+ case OIND:
+ if(result == D_NONE) {
+ nullwarn(n->left, Z);
+ break;
+ }
+ goto copy;
+
+ case OSTRUCT:
+ lg = nodalloc(types[TIND], result, &nod);
+ nod.lineno = n->lineno;
+ if(result == D_TREE)
+ lcgen(nn, lg, Z);
+ else
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ diag(n, "unknown su result: %R", result);
+ o = 0;
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ nod.type = t;
+ if(l->complex < FNX) {
+ nod.xoffset = 0;
+ if(o != t->offset) {
+ gopcode(OADD, types[TIND], D_CONST,
+ nodconst(t->offset-o), lg, Z);
+ o = t->offset;
+ }
+ cgen(l, D_TREE, &nod);
+ continue;
+ }
+ nod.xoffset = t->offset - o;
+ gopcode(OAS, types[TIND], lg, Z, D_TOS, Z);
+ s = argoff;
+ if(typesuv[t->etype]) {
+ sugen(l, D_TREE, nodrat, t->width);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, D_TREE, &nod, t->width);
+ continue;
+ }
+ rg = regalloc(t, D_NONE);
+ cgen(l, rg, l);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
+ gopcode(OAS, t, rg, Z, D_TREE, &nod);
+ regfree(rg);
+ }
+ regfree(lg);
+ break;
+
+ case OAS:
+ if(result == D_NONE) {
+ sugen(n->right, D_TREE, n->left, w);
+ break;
+ }
+ sugen(n->right, D_TREE, nodrat, w); /* could do better */
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, D_TREE, n->left, w);
+ sugen(nodrat, result, nn, w);
+ break;
+
+ case OFUNC:
+ if(result == D_NONE) {
+ sugen(n, D_TREE, nodrat, w);
+ break;
+ }
+ inargs++;
+ /* prepare zero-th arg: address of result */
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ v = argoff;
+ gargs(n->right);
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, result, nn);
+ p->to.type = D_STACK;
+ p->to.offset = argoff - v;
+ } else
+ if(result == D_TREE) {
+ v = argoff;
+ gargs(n->right);
+ if(nn->complex >= FNX) {
+ rg = regalloc(types[TIND], regret(types[TIND]));
+ lcgen(nn, rg, Z);
+ gopcode(OAS, types[TIND], rg, Z, D_TOS, Z);
+ regfree(rg);
+ } else
+ lcgen(nn, D_TOS, Z);
+ } else {
+ diag(n, "unknown result in FUNC sugen");
+ break;
+ }
+ argoff += types[TIND]->width;
+ l = n->left;
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ inargs--;
+ doinc(n->right, POST);
+ doinc(n->left, POST);
+ gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
+ regfree(lg);
+ if(inargs)
+ adjsp(v - argoff);
+ break;
+
+ case OCOND:
+ doinc(n->left, PRE);
+ boolgen(n->left, 1, D_NONE, Z, n->left);
+ p1 = p;
+
+ inargs++;
+ doinc(n->right->left, PRE);
+ sugen(n->right->left, result, nn, w);
+ doinc(n->right->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(n->right->right, PRE);
+ sugen(n->right->right, result, nn, w);
+ doinc(n->right->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OCOMMA:
+ cgen(n->left, D_NONE, n->left);
+ doinc(n->left, POST);
+ doinc(n->right, PRE);
+ sugen(n->right, result, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(result == D_NONE)
+ return;
+ rg = regaddr(D_NONE);
+ lcgen(n, rg, Z);
+
+ lg = regaddr(D_NONE);
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ if(result == D_TREE) {
+ if(nn->complex >= FNX) {
+ gopcode(OAS, types[TIND], rg, n, D_TOS, n);
+ s = argoff;
+ lcgen(nn, lg, Z);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, n, rg, n);
+ } else
+ lcgen(nn, lg, Z);
+ } else
+ diag(n, "unknown su result: %R", result);
+
+ if(w % SZ_LONG)
+ diag(Z, "sucopy width not 0%%%d", SZ_LONG);
+ v = w / SZ_LONG;
+ if(v & 1) {
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ v--;
+ }
+ if(v > 6) {
+ ng = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(v/2-1), ng, n);
+ v = pc;
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ gbranch(OGT);
+ patch(p, v);
+ p->from.type = ng;
+ p->as = ADBF;
+ regfree(ng);
+ } else
+ while(v > 0) {
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ v--;
+ }
+
+ regfree(lg);
+ regfree(rg);
+}
diff --git a/utils/1c/enam.c b/utils/1c/enam.c
new file mode 100644
index 00000000..be6917af
--- /dev/null
+++ b/utils/1c/enam.c
@@ -0,0 +1,425 @@
+char *anames[] =
+{
+ "XXX",
+ "ABCD",
+ "ADDB",
+ "ADDL",
+ "ADDW",
+ "ADDXB",
+ "ADDXL",
+ "ADDXW",
+ "ADJSP",
+ "ANDB",
+ "ANDL",
+ "ANDW",
+ "ASLB",
+ "ASLL",
+ "ASLW",
+ "ASRB",
+ "ASRL",
+ "ASRW",
+ "BCASE",
+ "BCC",
+ "BCHG",
+ "BCLR",
+ "BCS",
+ "BEQ",
+ "BFCHG",
+ "BFCLR",
+ "BFEXTS",
+ "BFEXTU",
+ "BFFFO",
+ "BFINS",
+ "BFSET",
+ "BFTST",
+ "BGE",
+ "BGT",
+ "BHI",
+ "BKPT",
+ "BLE",
+ "BLS",
+ "BLT",
+ "BMI",
+ "BNE",
+ "BPL",
+ "BRA",
+ "BSET",
+ "BSR",
+ "BTST",
+ "BVC",
+ "BVS",
+ "CALLM",
+ "CAS2B",
+ "CAS2L",
+ "CAS2W",
+ "CASB",
+ "CASEW",
+ "CASL",
+ "CASW",
+ "CHK2B",
+ "CHK2L",
+ "CHK2W",
+ "CHKL",
+ "CHKW",
+ "CLRB",
+ "CLRL",
+ "CLRW",
+ "CMP2B",
+ "CMP2L",
+ "CMP2W",
+ "CMPB",
+ "CMPL",
+ "CMPW",
+ "DATA",
+ "DBCC",
+ "DBCS",
+ "DBEQ",
+ "DBF",
+ "DBGE",
+ "DBGT",
+ "DBHI",
+ "DBLE",
+ "DBLS",
+ "DBLT",
+ "DBMI",
+ "DBNE",
+ "DBPL",
+ "DBT",
+ "DBVC",
+ "DBVS",
+ "DIVSL",
+ "DIVSW",
+ "DIVUL",
+ "DIVUW",
+ "END",
+ "EORB",
+ "EORL",
+ "EORW",
+ "EXG",
+ "EXTBL",
+ "EXTBW",
+ "EXTWL",
+ "FABSB",
+ "FABSD",
+ "FABSF",
+ "FABSL",
+ "FABSW",
+ "FACOSB",
+ "FACOSD",
+ "FACOSF",
+ "FACOSL",
+ "FACOSW",
+ "FADDB",
+ "FADDD",
+ "FADDF",
+ "FADDL",
+ "FADDW",
+ "FASINB",
+ "FASIND",
+ "FASINF",
+ "FASINL",
+ "FASINW",
+ "FATANB",
+ "FATAND",
+ "FATANF",
+ "FATANHB",
+ "FATANHD",
+ "FATANHF",
+ "FATANHL",
+ "FATANHW",
+ "FATANL",
+ "FATANW",
+ "FBEQ",
+ "FBF",
+ "FBGE",
+ "FBGT",
+ "FBLE",
+ "FBLT",
+ "FBNE",
+ "FBT",
+ "FCMPB",
+ "FCMPD",
+ "FCMPF",
+ "FCMPL",
+ "FCMPW",
+ "FCOSB",
+ "FCOSD",
+ "FCOSF",
+ "FCOSHB",
+ "FCOSHD",
+ "FCOSHF",
+ "FCOSHL",
+ "FCOSHW",
+ "FCOSL",
+ "FCOSW",
+ "FDBEQ",
+ "FDBF",
+ "FDBGE",
+ "FDBGT",
+ "FDBLE",
+ "FDBLT",
+ "FDBNE",
+ "FDBT",
+ "FDIVB",
+ "FDIVD",
+ "FDIVF",
+ "FDIVL",
+ "FDIVW",
+ "FETOXB",
+ "FETOXD",
+ "FETOXF",
+ "FETOXL",
+ "FETOXM1B",
+ "FETOXM1D",
+ "FETOXM1F",
+ "FETOXM1L",
+ "FETOXM1W",
+ "FETOXW",
+ "FGETEXPB",
+ "FGETEXPD",
+ "FGETEXPF",
+ "FGETEXPL",
+ "FGETEXPW",
+ "FGETMANB",
+ "FGETMAND",
+ "FGETMANF",
+ "FGETMANL",
+ "FGETMANW",
+ "FINTB",
+ "FINTD",
+ "FINTF",
+ "FINTL",
+ "FINTRZB",
+ "FINTRZD",
+ "FINTRZF",
+ "FINTRZL",
+ "FINTRZW",
+ "FINTW",
+ "FLOG10B",
+ "FLOG10D",
+ "FLOG10F",
+ "FLOG10L",
+ "FLOG10W",
+ "FLOG2B",
+ "FLOG2D",
+ "FLOG2F",
+ "FLOG2L",
+ "FLOG2W",
+ "FLOGNB",
+ "FLOGND",
+ "FLOGNF",
+ "FLOGNL",
+ "FLOGNP1B",
+ "FLOGNP1D",
+ "FLOGNP1F",
+ "FLOGNP1L",
+ "FLOGNP1W",
+ "FLOGNW",
+ "FMODB",
+ "FMODD",
+ "FMODF",
+ "FMODL",
+ "FMODW",
+ "FMOVEB",
+ "FMOVED",
+ "FMOVEF",
+ "FMOVEL",
+ "FMOVEM",
+ "FMOVEMC",
+ "FMOVEW",
+ "FMULB",
+ "FMULD",
+ "FMULF",
+ "FMULL",
+ "FMULW",
+ "FNEGB",
+ "FNEGD",
+ "FNEGF",
+ "FNEGL",
+ "FNEGW",
+ "FREMB",
+ "FREMD",
+ "FREMF",
+ "FREML",
+ "FREMW",
+ "FRESTORE",
+ "FSAVE",
+ "FSCALEB",
+ "FSCALED",
+ "FSCALEF",
+ "FSCALEL",
+ "FSCALEW",
+ "FSEQ",
+ "FSF",
+ "FSGE",
+ "FSGT",
+ "FSINB",
+ "FSIND",
+ "FSINF",
+ "FSINHB",
+ "FSINHD",
+ "FSINHF",
+ "FSINHL",
+ "FSINHW",
+ "FSINL",
+ "FSINW",
+ "FSLE",
+ "FSLT",
+ "FSNE",
+ "FSQRTB",
+ "FSQRTD",
+ "FSQRTF",
+ "FSQRTL",
+ "FSQRTW",
+ "FST",
+ "FSUBB",
+ "FSUBD",
+ "FSUBF",
+ "FSUBL",
+ "FSUBW",
+ "FTANB",
+ "FTAND",
+ "FTANF",
+ "FTANHB",
+ "FTANHD",
+ "FTANHF",
+ "FTANHL",
+ "FTANHW",
+ "FTANL",
+ "FTANW",
+ "FTENTOXB",
+ "FTENTOXD",
+ "FTENTOXF",
+ "FTENTOXL",
+ "FTENTOXW",
+ "FTSTB",
+ "FTSTD",
+ "FTSTF",
+ "FTSTL",
+ "FTSTW",
+ "FTWOTOXB",
+ "FTWOTOXD",
+ "FTWOTOXF",
+ "FTWOTOXL",
+ "FTWOTOXW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "ILLEG",
+ "INSTR",
+ "JMP",
+ "JSR",
+ "LEA",
+ "LINKL",
+ "LINKW",
+ "LOCATE",
+ "LONG",
+ "LSLB",
+ "LSLL",
+ "LSLW",
+ "LSRB",
+ "LSRL",
+ "LSRW",
+ "MOVB",
+ "MOVEM",
+ "MOVEPL",
+ "MOVEPW",
+ "MOVESB",
+ "MOVESL",
+ "MOVESW",
+ "MOVL",
+ "MOVW",
+ "MULSL",
+ "MULSW",
+ "MULUL",
+ "MULUW",
+ "NAME",
+ "NBCD",
+ "NEGB",
+ "NEGL",
+ "NEGW",
+ "NEGXB",
+ "NEGXL",
+ "NEGXW",
+ "NOP",
+ "NOTB",
+ "NOTL",
+ "NOTW",
+ "ORB",
+ "ORL",
+ "ORW",
+ "PACK",
+ "PEA",
+ "RESET",
+ "ROTLB",
+ "ROTLL",
+ "ROTLW",
+ "ROTRB",
+ "ROTRL",
+ "ROTRW",
+ "ROXLB",
+ "ROXLL",
+ "ROXLW",
+ "ROXRB",
+ "ROXRL",
+ "ROXRW",
+ "RTD",
+ "RTE",
+ "RTM",
+ "RTR",
+ "RTS",
+ "SBCD",
+ "SCC",
+ "SCS",
+ "SEQ",
+ "SF",
+ "SGE",
+ "SGT",
+ "SHI",
+ "SLE",
+ "SLS",
+ "SLT",
+ "SMI",
+ "SNE",
+ "SPL",
+ "ST",
+ "STOP",
+ "SUBB",
+ "SUBL",
+ "SUBW",
+ "SUBXB",
+ "SUBXL",
+ "SUBXW",
+ "SVC",
+ "SVS",
+ "SWAP",
+ "SYS",
+ "TAS",
+ "TEXT",
+ "TRAP",
+ "TRAPCC",
+ "TRAPCS",
+ "TRAPEQ",
+ "TRAPF",
+ "TRAPGE",
+ "TRAPGT",
+ "TRAPHI",
+ "TRAPLE",
+ "TRAPLS",
+ "TRAPLT",
+ "TRAPMI",
+ "TRAPNE",
+ "TRAPPL",
+ "TRAPT",
+ "TRAPV",
+ "TRAPVC",
+ "TRAPVS",
+ "TSTB",
+ "TSTL",
+ "TSTW",
+ "UNLK",
+ "UNPK",
+ "WORD",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/1c/gc.h b/utils/1c/gc.h
new file mode 100644
index 00000000..288971f3
--- /dev/null
+++ b/utils/1c/gc.h
@@ -0,0 +1,339 @@
+#include "../cc/cc.h"
+#include "../2c/2.out.h"
+/*
+ * 1c/68000
+ * Motorola 68000
+ */
+
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+
+#define ALLOP OEND
+#define NRGN 300
+#define FNX 100
+#define INDEXED 9
+
+#define PRE 1
+#define POST 2
+#define TEST 4
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Txt Txt;
+typedef struct Cases Case;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Var Var;
+typedef struct Multab Multab;
+typedef struct C1 C1;
+
+struct Adr
+{
+ long displace;
+ long offset;
+
+ char sval[NSNAME];
+ double dval;
+
+ Sym* sym;
+ short type;
+ short field;
+ short etype;
+};
+#define A ((Adr*)0)
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Txt
+{
+ short movas;
+ short postext;
+ char preclr;
+};
+
+struct Cases
+{
+ long val;
+ long label;
+ uchar def;
+ Case* link;
+};
+#define C ((Case*)0)
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char type;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ ulong regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Rgn
+{
+ Reg* enter;
+ short costr;
+ short costa;
+ short varno;
+ short regno;
+};
+
+struct Multab
+{
+ short val;
+ char code[6];
+};
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 8
+#define CREF 5
+#define CTEST 2
+#define CXREF 3
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits addrs;
+EXTERN ulong regbits;
+
+#define B_INDIR (1<<0)
+#define B_ADDR (1<<1)
+EXTERN int mvbits;
+EXTERN int changer;
+EXTERN int changea;
+
+EXTERN Txt txt[NTYPE][NTYPE];
+EXTERN short opxt[ALLOP][NTYPE];
+EXTERN Txt* txtp;
+EXTERN int multabsize;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+
+EXTERN long argoff;
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN long continpc;
+EXTERN Prog* firstp;
+EXTERN Reg* firstr;
+EXTERN int inargs;
+EXTERN Prog* lastp;
+EXTERN int retok;
+EXTERN long mnstring;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN long nrathole;
+EXTERN long nstatic;
+EXTERN int nregion;
+EXTERN long nstring;
+EXTERN int nvar;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Sym* symstatic;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+EXTERN Prog zprog;
+
+EXTERN uchar regused[NREG];
+EXTERN uchar aregused[NREG];
+EXTERN uchar fregused[NREG];
+EXTERN uchar regbase[I_MASK];
+EXTERN long exregoffset;
+EXTERN long exaregoffset;
+EXTERN long exfregoffset;
+extern char* anames[];
+extern Multab multab[];
+
+void cgen(Node*, int, Node*);
+void lcgen(Node*, int, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, int, Node*, Node*);
+void sugen(Node*, int, Node*, long);
+
+
+void listinit(void);
+int Bconv(Fmt*);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Xconv(Fmt*);
+int Dconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int findtst(Reg*, Prog*, int);
+int setcc(Prog*, Prog*);
+int compat(Adr*, Adr*);
+int aregind(Adr*);
+int asize(int);
+int usedin(int, Adr*);
+Reg* findccr(Reg*);
+int setccr(Prog*);
+Reg* findop(Reg*, int, int, int);
+int regtyp(int);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+int copyas(Adr*, Adr*);
+int tasas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, Prog*, int);
+
+ulong RtoB(int);
+ulong AtoB(int);
+ulong FtoB(int);
+int BtoR(ulong);
+int BtoA(ulong);
+int BtoF(ulong);
+
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, ulong, int);
+void addreg(Adr*, int);
+
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+Node* nodconst(long);
+
+int swcmp(const void*, const void*);
+void doswit(int, Node*);
+void swit1(C1*, int, long, int, Node*);
+void cas(void);
+int bitload(Node*, int, int, int, Node*);
+void bitstore(Node*, int, int, int, int, Node*);
+long outstring(char*, long);
+int doinc(Node*, int);
+void setsp(void);
+void adjsp(long);
+int simplv(Node*);
+int eval(Node*, int);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+int nodalloc(Type*, int, Node*);
+int mulcon(Node*, Node*, int, Node*);
+int shlcon(Node*, Node*, int, Node*);
+int mulcon1(Node*, long, int, Node*);
+void nullwarn(Node*, Node*);
+
+void tindex(Type*, Type*);
+void ginit(void);
+void gclean(void);
+void oinit(int, int, int, int, int, int);
+Prog* prg(void);
+void nextpc(void);
+void gargs(Node*);
+void naddr(Node*, Adr*, int);
+int regalloc(Type*, int);
+int regaddr(int);
+int regpair(int);
+int regret(Type*);
+void regfree(int);
+void gmove(Type*, Type*, int, Node*, int, Node*);
+void gopcode(int, Type*, int, Node*, int, Node*);
+void asopt(void);
+int relindex(int);
+void gbranch(int);
+void fpbranch(void);
+void patch(Prog*, long);
+void gpseudo(int, Sym*, int, long);
+void gpseudotree(int, Sym*, Node*);
+
+void indx(Node*);
+void bcomplex(Node*);
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+#pragma varargck type "R" int
diff --git a/utils/1c/list.c b/utils/1c/list.c
new file mode 100644
index 00000000..f6bc2e62
--- /dev/null
+++ b/utils/1c/list.c
@@ -0,0 +1,319 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('B', Bconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[20];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ sprint(str, " %A %D,%D", p->as, &p->from, &p->to);
+ if(p->from.field) {
+ sprint(s, ",%d,%d", p->to.field, p->from.field);
+ strcat(str, s);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int r;
+
+ r = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[r]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i, j;
+ long d;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ j = i & I_MASK;
+ if(j) {
+ a->type = i & D_MASK;
+ d = a->offset;
+ a->offset = 0;
+ switch(j) {
+ case I_INDINC:
+ sprint(str, "(%D)+", a);
+ break;
+
+ case I_INDDEC:
+ sprint(str, "-(%D)", a);
+ break;
+
+ case I_INDIR:
+ if(a->type == D_CONST)
+ sprint(str, "%ld", d);
+ else
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_ADDR:
+ a->offset = d;
+ sprint(str, "$%D", a);
+ break;
+ }
+ a->type = i;
+ a->offset = d;
+ goto out;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", a->sym->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_STACK:
+ sprint(str, "TOS+%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ goto out;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ goto out;
+ }
+ if(a->displace) {
+ sprint(s, "/%ld", a->displace);
+ strcat(str, s);
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_R0 && r < D_R0+NREG)
+ sprint(str, "R%d", r-D_R0);
+ else
+ if(r >= D_A0 && r < D_A0+NREG)
+ sprint(str, "A%d", r-D_A0);
+ else
+ if(r >= D_F0 && r < D_F0+NREG)
+ sprint(str, "F%d", r-D_F0);
+ else
+ switch(r) {
+
+ default:
+ sprint(str, "gok(%d)", r);
+ break;
+
+ case D_NONE:
+ sprint(str, "NONE");
+ break;
+
+ case D_TOS:
+ sprint(str, "TOS");
+ break;
+
+ case D_CCR:
+ sprint(str, "CCR");
+ break;
+
+ case D_SR:
+ sprint(str, "SR");
+ break;
+
+ case D_SFC:
+ sprint(str, "SFC");
+ break;
+
+ case D_DFC:
+ sprint(str, "DFC");
+ break;
+
+ case D_CACR:
+ sprint(str, "CACR");
+ break;
+
+ case D_USP:
+ sprint(str, "USP");
+ break;
+
+ case D_VBR:
+ sprint(str, "VBR");
+ break;
+
+ case D_CAAR:
+ sprint(str, "CAAR");
+ break;
+
+ case D_MSP:
+ sprint(str, "MSP");
+ break;
+
+ case D_ISP:
+ sprint(str, "ISP");
+ break;
+
+ case D_TREE:
+ sprint(str, "TREE");
+ break;
+
+ case D_FPCR:
+ sprint(str, "FPCR");
+ break;
+
+ case D_FPSR:
+ sprint(str, "FPSR");
+ break;
+
+ case D_FPIAR:
+ sprint(str, "FPIAR");
+ break;
+
+ case D_TC:
+ sprint(str, "TC");
+ break;
+
+ case D_ITT0:
+ sprint(str, "ITT0");
+ break;
+
+ case D_ITT1:
+ sprint(str, "ITT1");
+ break;
+
+ case D_DTT0:
+ sprint(str, "DTT0");
+ break;
+
+ case D_DTT1:
+ sprint(str, "DTT1");
+ break;
+
+ case D_MMUSR:
+ sprint(str, "MMUSR");
+ break;
+ case D_URP:
+ sprint(str, "URP");
+ break;
+
+ case D_SRP:
+ sprint(str, "SRP");
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *s;
+
+ s = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = s[i] & 0xff;
+ if(c != '\\' && c != '"' && isprint(c)) {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = '0';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = ((c>>6) & 7) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = ((c>>0) & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/1c/mkfile b/utils/1c/mkfile
new file mode 100644
index 00000000..e5486b5c
--- /dev/null
+++ b/utils/1c/mkfile
@@ -0,0 +1,29 @@
+<../../mkconfig
+
+TARG=1c
+
+OFILES=\
+ cgen.$O\
+ reg.$O\
+ txt.$O\
+ peep.$O\
+ swt.$O\
+ sgen.$O\
+ list.$O\
+ enam.$O\
+ mul.$O\
+
+HFILES= gc.h\
+ ../2c/2.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/1c/mul.c b/utils/1c/mul.c
new file mode 100644
index 00000000..65ddda2f
--- /dev/null
+++ b/utils/1c/mul.c
@@ -0,0 +1,174 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant
+ * all sequences start with leading '0'.
+ * if sequence starts with 'i', then the
+ * leading '0' is suppressed.
+ * '0' mov r0,r1
+ * '1' sub r0,r1
+ * '2' sub r1,r0
+ * '3' add r0,r1
+ * '4' add r1,r0
+ * '5' add r0,r0
+ * '6' add r1,r1
+ * 'b' lsh $2,r0
+ * 'c' lsh $3,r0
+ * 'd'-'h' ...
+ * 'j' lsh $2,r1
+ * 'k'-'p' ...
+ */
+Multab multab[] =
+{
+ 2, "i5",
+ 3, "64",
+ 4, "i55",
+ 5, "664",
+ 6, "645",
+ 7, "c2",
+ 9, "k4",
+ 10, "6645",
+ 11, "66364",
+ 12, "6455",
+ 13, "66464",
+ 14, "6d2",
+ 15, "d2",
+ 17, "l4",
+ 18, "6d4",
+ 19, "64k4",
+ 20, "66455",
+ 21, "664664",
+ 22, "64c2",
+ 23, "44c2",
+ 24, "64c",
+ 25, "63k4",
+ 26, "64c4",
+ 27, "663e2",
+ 28, "66e2",
+ 29, "63e2",
+ 30, "6e2",
+ 31, "e2",
+ 33, "m4",
+ 34, "6e4",
+ 35, "64l4",
+ 36, "66e4",
+ 37, "664k4",
+ 38, "64k45",
+ 39, "454c2",
+ 40, "664c",
+ 41, "663k4",
+ 42, "644c4",
+ 43, "643k4",
+ 44, "664c4",
+ 45, "640d2",
+ 46, "64d2",
+ 47, "44d2",
+ 48, "64d",
+ 49, "63l4",
+ 50, "64d4",
+ 51, "640l4",
+ 52, "646d4",
+ 53, "643d4",
+ 54, "6636f2",
+ 55, "k3f2",
+ 56, "kf2",
+ 57, "k2k4",
+ 58, "636f2",
+ 59, "663f2",
+ 60, "66f2",
+ 61, "63f2",
+ 62, "6f2",
+ 63, "f2",
+ 65, "n4",
+ 66, "6f4",
+ 67, "64m4",
+ 68, "66f4",
+ 69, "664l4",
+ 70, "64l45",
+ 71, "k1f4",
+ 72, "k4c",
+ 73, "k4k4",
+ 74, "664k45",
+ 75, "6640d2",
+ 76, "664d2",
+ 77, "434d2",
+ 78, "644d2",
+ 79, "454d2",
+ 80, "664d",
+ 81, "663l4",
+ 82, "644d4",
+ 83, "643l4",
+ 84, "664d4",
+ 85, "6640l4",
+ 86, "6634l4",
+ 87, "6443d4",
+ 88, "6646d4",
+ 89, "6643d4",
+ 90, "6406e2",
+ 91, "643e2",
+ 92, "646e2",
+ 93, "640e2",
+ 94, "64e2",
+ 95, "44e2",
+ 96, "64e",
+ 97, "63m4",
+ 98, "64e4",
+ 99, "640m4",
+ 100, "646e4",
+ 200, "66f364",
+ 300, "j40jf2",
+ 400, "64kg4",
+ 500, "66h212",
+ 600, "64m4c4",
+ 700, "j4c4d2",
+ 800, "64lh4",
+ 900, "6464g4",
+ 1000, "63g2c",
+ 1100, "j4d2p4",
+ 1200, "64k4f2",
+ 1300, "j4n4b4",
+ 1400, "64j4g2",
+ 1600, "64d4e",
+ 1800, "p4c2",
+ 2000, "63g2d",
+ 2100, "l4b2o4",
+ 2200, "k4d4p4",
+ 2300, "6644h2",
+ 2400, "j4k4f4",
+ 2500, "j4e2d4",
+ 2600, "j40n4c",
+ 3100, "jd12p2",
+ 3200, "64d4f",
+ 3600, "6d1p2",
+ 3800, "e3k3g2",
+ 3900, "jf20n4",
+ 4000, "o4e2",
+ 4100, "66p455",
+ 4200, "l4c3e2",
+ 4300, "l4b1f4",
+ 4400, "64o4d4",
+ 4600, "k45h2",
+ 4700, "k3j4g2",
+ 4800, "j40d2f",
+ 5000, "l4c3m4",
+ 5100, "j40h2b",
+ 5200, "j40n4d",
+ 6000, "d1o3h2",
+ 6100, "o1l4b2",
+ 6200, "ke12p2",
+ 6400, "64d4g",
+ 7200, "66e1p2",
+ 7400, "m3m4c2",
+ 7600, "l4f3c2",
+ 7800, "kg20n4",
+ 8000, "63g2f",
+ 8100, "m2b4p4",
+ 8200, "66p4c",
+ 8700, "66f4g2",
+ 8900, "l3j4g4",
+ 9200, "k45h25",
+ 9600, "j40d2g",
+ 9800, "k4f3d4",
+};
+
+int multabsize = sizeof(multab) / sizeof(multab[0]);
diff --git a/utils/1c/peep.c b/utils/1c/peep.c
new file mode 100644
index 00000000..e0a535c2
--- /dev/null
+++ b/utils/1c/peep.c
@@ -0,0 +1,1060 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t, s;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ /*
+ * propigate move's by renaming
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVL || p->as == AFMOVEF || p->as == AFMOVED)
+ if(regtyp(p->from.type))
+ if(anyvar(&p->to)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ /*
+ * convert (A) ... A++ into (A)++
+ * and A-- ... (A) into --(A)
+ */
+ t = aregind(&p->from);
+ if(t == D_NONE)
+ goto out1;
+ s = asize(p->as);
+ if(s == 0)
+ goto out1;
+ r1 = findop(r, t, AADDL, s);
+ if(r1 != R) {
+ if(usedin(t, &p->to))
+ goto out1;
+ p->from.type += I_INDINC - I_INDIR;
+ excise(r1);
+ goto out1;
+ }
+ r1 = findop(r, t, ASUBL, s);
+ if(r1 != R) {
+ p->from.type += I_INDDEC - I_INDIR;
+ excise(r1);
+ }
+ out1:
+ t = aregind(&p->to);
+ if(t == D_NONE)
+ goto out2;
+ s = asize(p->as);
+ if(s == 0)
+ goto out2;
+ r1 = findop(r, t, AADDL, s);
+ if(r1 != R) {
+ p->to.type += I_INDINC - I_INDIR;
+ excise(r1);
+ goto out2;
+ }
+ r1 = findop(r, t, ASUBL, s);
+ if(r1 != R) {
+ if(usedin(t, &p->from))
+ goto out2;
+ p->to.type += I_INDDEC - I_INDIR;
+ excise(r1);
+ }
+ out2:
+ /*
+ * get rid of unneeded save/restore CCR
+ */
+ if(p->from.type == D_CCR) {
+ r1 = findccr(r);
+ if(r1 != R) {
+ excise(r);
+ excise(r1);
+ }
+ }
+ switch(p->as) {
+ case ATSTB:
+ case ATSTW:
+ case ATSTL:
+ if(findtst(r, r->prog, 0))
+ excise(r);
+ }
+ /*
+ * turn TSTB (A); BLT; ORB $128,(A) into TAS (A); BLT; NOP
+ */
+ if(p->as == ATSTB && (r1 = r->s1)) {
+ if((r1->prog->as == ABLT && (r2 = r1->s1)) ||
+ (r1->prog->as == ABGE && (r2 = r1->s2))) {
+ p1 = r2->prog;
+ if(p1->as == AORB)
+ if(p1->from.type == D_CONST)
+ if(p1->from.offset == 128)
+ if(r1 == uniqp(r2))
+ if(tasas(&p->to, &p1->to)) {
+ p->as = ATAS;
+ excise(r2);
+ }
+ }
+ }
+ }
+}
+
+void
+excise(Reg *r)
+{
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+/*
+ * chase backward all cc setting.
+ * returns 1 if all set same.
+ */
+int
+findtst(Reg *r0, Prog *rp, int n)
+{
+ Reg *r;
+ int c;
+
+loop:
+ n++;
+ if(n >= 10)
+ return 0;
+ for(r=r0->p2; r!=R; r=r->p2link) {
+ c = setcc(r->prog, rp);
+ if(c > 0)
+ continue;
+ if(c == 0)
+ return 0;
+ if(findtst(r, rp, n) == 0)
+ return 0;
+ }
+ r = r0->p1;
+ if(r == R)
+ return 1;
+ c = setcc(r->prog, rp);
+ if(c > 0)
+ return 1;
+ if(c == 0)
+ return 0;
+ r0 = r;
+ goto loop;
+}
+
+/*
+ * tests cc
+ * returns -1 if no change
+ * returns 1 if set the same
+ * returns 0 if set different
+ */
+int
+setcc(Prog *p, Prog *rp)
+{
+ int s;
+
+ s = asize(rp->as);
+ switch(p->as) {
+ default:
+ if(debug['P'])
+ print("unknown setcc %A\n", p->as);
+ break;
+
+ case ACMPB:
+ case ACMPW:
+ case ACMPL:
+ case ABSR:
+ return 0;
+
+ case ABRA:
+ case ABGE:
+ case ABNE:
+ case ABLE:
+ case ABEQ:
+ case ABHI:
+ case ABLS:
+ case ABMI:
+ case ABPL:
+ case ABGT:
+ case ABLT:
+ case ABCC:
+ case ABCS:
+ case APEA:
+ case ALEA:
+ case ANOP:
+
+ case AFADDD:
+ case AFMULD:
+ case AFDIVD:
+ case AFSUBD:
+ case AFADDF:
+ case AFMULF:
+ case AFDIVF:
+ case AFSUBF:
+ case AADJSP:
+ return -1;
+
+ case AADDW:
+ case AADDL:
+ case ASUBW:
+ case ASUBL:
+ case ACLRL:
+ case ACLRW:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ goto areg;
+
+ case AADDB:
+ case ASUBB:
+ case AANDB:
+ case AANDW:
+ case AANDL:
+ case AORB:
+ case AORW:
+ case AORL:
+ case AEORB:
+ case AEORW:
+ case AEORL:
+ case ALSLB:
+ case ALSLW:
+ case ALSLL:
+ case ALSRB:
+ case ALSRW:
+ case ALSRL:
+ case AASLB:
+ case AASLW:
+ case AASLL:
+ case AASRB:
+ case AASRW:
+ case AASRL:
+ case ATSTB:
+ case ATSTW:
+ case ATSTL:
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ACLRB:
+ if(asize(p->as) != s)
+ break;
+ if(compat(&rp->to, &p->to))
+ return 1;
+ break;
+
+ case AMOVW:
+ case AMOVL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ goto areg;
+ case AMOVB:
+ if(asize(p->as) != s)
+ break;
+ if(compat(&rp->to, &p->to))
+ return 1;
+ if(compat(&rp->to, &p->from))
+ return 1;
+ }
+ return 0;
+
+areg:
+ if((rp->to.type&D_MASK) == p->to.type)
+ return 0;
+ return -1;
+}
+
+int
+compat(Adr *a, Adr *b)
+{
+ int o;
+
+ o = a->type;
+ if((o >= D_R0 && o < D_R0+NREG) ||
+ (o >= D_A0 && o < D_A0+NREG))
+ return o == b->type;
+ o &= D_MASK;
+ if(o >= D_A0 && o < D_A0+NREG) {
+ if(o != (b->type&D_MASK))
+ return 0;
+ if(a->offset != b->offset)
+ return 0;
+ o = a->type & I_MASK;
+ if(o == I_INDIR) {
+ o = b->type & I_MASK;
+ if(o == I_INDIR || o == I_INDDEC)
+ return 1;
+ return 0;
+ }
+ if(o == I_INDINC) {
+ o = b->type & I_MASK;
+ if(o == I_INDIR) {
+ b->type += I_INDINC-I_INDIR;
+ return 1;
+ }
+ if(o == I_INDDEC) {
+ b->type += I_INDIR-I_INDDEC;
+ return 1;
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int
+aregind(Adr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t >= (D_A0|I_INDIR) && t < ((D_A0+NREG)|I_INDIR))
+ while(a->offset == 0)
+ return t & D_MASK;
+ return D_NONE;
+}
+
+int
+asize(int a)
+{
+
+ switch(a) {
+ case AFTSTD:
+ case AFMOVED:
+ case AFADDD:
+ case AFSUBD:
+ case AFMULD:
+ case AFDIVD:
+ case AFCMPD:
+ case AFNEGD:
+ return 8;
+
+ case AFTSTF:
+ case AFMOVEF:
+ case AFADDF:
+ case AFSUBF:
+ case AFMULF:
+ case AFDIVF:
+ case AFCMPF:
+ case AFNEGF:
+
+ case ACLRL:
+ case ATSTL:
+ case AMOVL:
+ case AADDL:
+ case ASUBL:
+ case ACMPL:
+ case AANDL:
+ case AORL:
+ case AEORL:
+ case ALSLL:
+ case ALSRL:
+ case AASLL:
+ case AASRL:
+ case ANEGL:
+ return 4;
+
+ case ACLRW:
+ case ATSTW:
+ case AMOVW:
+ case AADDW:
+ case ASUBW:
+ case ACMPW:
+ case AANDW:
+ case AORW:
+ case AEORW:
+ case ALSLW:
+ case ALSRW:
+ case AASLW:
+ case AASRW:
+ case ANEGW:
+ return 2;
+
+ case ACLRB:
+ case ATSTB:
+ case AMOVB:
+ case AADDB:
+ case ASUBB:
+ case ACMPB:
+ case AANDB:
+ case AORB:
+ case AEORB:
+ case ALSLB:
+ case ALSRB:
+ case AASLB:
+ case AASRB:
+ case ANEGB:
+ return 1;
+ }
+ if(debug['P'])
+ print("unknown asize %A\n", p->as);
+ return 0;
+}
+
+int
+usedin(int t, Adr *a)
+{
+
+ if((a->type&D_MASK) == t)
+ return 1;
+ return 0;
+}
+
+Reg*
+findccr(Reg *r)
+{
+ Prog *p;
+
+ for(;;) {
+ r = uniqs(r);
+ if(r == R)
+ break;
+ p = r->prog;
+ if(p->to.type == D_CCR)
+ return r;
+ if(setccr(p))
+ break;
+ }
+ return R;
+}
+
+int
+setccr(Prog *p)
+{
+
+ switch(p->as) {
+ case ANOP:
+ return 0;
+
+ case AADDL:
+ case AMOVL:
+ case ACLRL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ return 0;
+ }
+ return 1;
+}
+
+Reg*
+findop(Reg *r, int t, int o, int s)
+{
+ Prog *p;
+ Reg *r1;
+
+ for(;;) {
+ if(o == AADDL) {
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ if(uniqp(r1) != r)
+ break;
+ } else {
+ r1 = uniqp(r);
+ if(r1 == R)
+ break;
+ if(uniqs(r1) != r)
+ break;
+ }
+ r = r1;
+ p = r->prog;
+ if(usedin(t, &p->from))
+ break;
+ if(usedin(t, &p->to)) {
+ if(p->as == o)
+ if(p->to.type == t)
+ if(p->from.type == D_CONST)
+ if(p->from.offset == s)
+ return r;
+ break;
+ }
+ }
+ return R;
+}
+
+int
+regtyp(int t)
+{
+
+ if(t >= D_R0 && t < D_R0+8)
+ return 1;
+ if(t >= D_A0 && t < D_A0+8)
+ return 1;
+ if(t >= D_F0 && t < D_F0+8)
+ return 1;
+ return 0;
+}
+
+int
+anyvar(Adr *a)
+{
+
+ if(regtyp(a->type))
+ return 1;
+ return 0;
+ if(a->type == D_AUTO || a->type == D_PARAM)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOVL
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1->type))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2->type))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ADIVUW: /* these set Rn and Rn+1 */
+ case ADIVUL:
+ case ADIVSW:
+ case ADIVSL:
+ case ABSR:
+ return 0;
+
+ case AFMOVED:
+ case AFMOVEF:
+ case AMOVL:
+ if(p->to.type == v1->type)
+ goto gotit;
+ }
+ if(copyau(&p->from, v2) || copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, p, 0) || copysub(&p->to, v1, v2, p, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, p, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ if(p->from.type == v2->type)
+ excise(r);
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, p, 1);
+ copysub(&p->to, v1, v2, p, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+
+ if(r->active) {
+ if(debug['P'])
+ print("copyret 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D\n", v1, v2);
+ for(; r != R; r = r->s1) {
+ if(debug['P'])
+ print("%P", r->prog);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(r->prog, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; rar return 0\n");
+ return 0;
+ case 3: /* set */
+ if(debug['P'])
+ print("; set; return 1\n");
+ return 1;
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(debug['P'])
+ print("; used and f; return 0\n");
+ return 0;
+ }
+ if(copyu(r->prog, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; substitute");
+ if(t == 4) {
+ if(debug['P'])
+ print("; used and set; return 1\n");
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(r->prog, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ if(debug['P'])
+ print("; f set used");
+ f = 1;
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+ int t;
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print("unknown op %A\n", p->as);
+ return 2;
+
+ case APEA: /* rhs addr */
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ALEA: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+ case AMOVL: /* rhs store */
+ case ACLRL:
+ case AFMOVEF:
+ case AFMOVED:
+ case AFMOVEB:
+ case AFMOVEW:
+ case AFMOVEL:
+ case ANOP:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, p, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AADDL: /* rhs rar */
+ case AADDW:
+ case AADDB:
+ case ASUBL:
+ case ASUBW:
+ case ASUBB:
+ case AANDL:
+ case AANDW:
+ case AANDB:
+ case AORL:
+ case AORW:
+ case AORB:
+ case AEORL:
+ case AEORW:
+ case AEORB:
+ case AASRL:
+ case AASRW:
+ case AASRB:
+ case AASLL:
+ case AASLW:
+ case AASLB:
+ case ALSRL:
+ case ALSRW:
+ case ALSRB:
+ case ANOTL:
+ case ANOTW:
+ case ANOTB:
+ case ANEGL:
+ case ANEGW:
+ case ANEGB:
+ case AEXTBL:
+ case AEXTWL:
+ case AEXTBW:
+
+ case AMULSL:
+ case AMULUL:
+
+ case AMOVW: /* only sets part of register */
+ case AMOVB:
+ case ACLRW:
+ case ACLRB:
+
+ case AFADDD:
+ case AFMULD:
+ case AFDIVD:
+ case AFSUBD:
+ case AFNEGD:
+ case AFADDF:
+ case AFMULF:
+ case AFDIVF:
+ case AFSUBF:
+ case AFNEGF:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ADBF: /* lhs rar */
+ if(copyas(&p->from, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case AFCMPF:
+ case AFCMPD:
+ case ATSTL:
+ case ATSTW:
+ case ATSTB:
+ case AFTSTF:
+ case AFTSTD:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, p, 1))
+ return 1;
+ return copysub(&p->to, v, s, p, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case ABRA: /* no reference */
+ case ABGE:
+ case ABNE:
+ case ABLE:
+ case ABEQ:
+ case ABHI:
+ case ABLS:
+ case ABMI:
+ case ABPL:
+ case ABGT:
+ case ABLT:
+ case ABCC:
+ case ABCS:
+
+ case AFBEQ:
+ case AFBNE:
+ case AFBGT:
+ case AFBGE:
+ case AFBLE:
+ case AFBLT:
+
+ case AADJSP:
+ case ACASEW:
+ break;
+
+ case ADIVUW: /* these set Rn and Rn+1 */
+ case ADIVUL:
+ case ADIVSW:
+ case ADIVSL:
+ t = v->type;
+ if(t == p->to.type || t == p->to.type+1)
+ return 2;
+ goto caseread;
+
+ case ARTS: /* funny */
+ t = v->type;
+ if(t == D_R0 || t == D_F0)
+ return 2;
+ if(t >= D_R0 && t < D_R0+NREG)
+ if(t-D_R0 > exregoffset)
+ return 2;
+ if(t >= D_A0 && t < D_A0+NREG)
+ if(t-D_A0 > exaregoffset)
+ return 2;
+ if(t >= D_F0 && t < D_F0+NREG)
+ if(t-D_F0 > exfregoffset)
+ return 2;
+ return 3;
+
+ case ABSR: /* funny */
+ t = v->type;
+ if(t >= D_R0 && t < D_R0+NREG)
+ if(t-D_R0 > exregoffset)
+ return 2;
+ if(t >= D_A0 && t < D_A0+NREG)
+ if(t-D_A0 > exaregoffset)
+ return 2;
+ if(t >= D_F0 && t < D_F0+NREG)
+ if(t-D_F0 > exfregoffset)
+ return 2;
+ if(copyau(&p->to, v))
+ return 2;
+ return 3;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v->type))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM) {
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * indirect
+ */
+int
+tasas(Adr *a, Adr *v)
+{
+ int t;
+
+ t = a->type;
+ if(t < I_INDIR+D_A0 && t >= I_INDIR+D_A0+8)
+ return 0;
+ if(v->type != t)
+ return 0;
+ if(a->displace != v->displace)
+ return 0;
+ return 1;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+ int t;
+
+ if(copyas(a, v))
+ return 1;
+ t = v->type;
+ if(regtyp(t)) {
+ if((a->type & D_MASK) == t)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, Prog *p, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_F0 && t < D_F0+8) {
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ if(t >= D_R0 && t < D_R0+8) {
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ if(!(t >= D_A0 && t < D_A0+8))
+ return 1;
+ switch(p->as) {
+ default:
+ return 1;
+
+ case AMOVL:
+ case AMOVW:
+ case ACMPL:
+ case ACMPW:
+ break;
+
+ case AADDL:
+ case AADDW:
+ case ASUBL:
+ case ASUBW:
+ if(a == &p->from && !regtyp(p->to.type))
+ return 1;
+ break;
+ }
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ t = v->type;
+ if(regtyp(t)) {
+ if((a->type & D_MASK) == t) {
+ if((s->type ^ t) & ~(NREG-1))
+ return 1;
+ if(f)
+ a->type = (a->type & ~D_MASK) | s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/utils/1c/reg.c b/utils/1c/reg.c
new file mode 100644
index 00000000..ad4231c0
--- /dev/null
+++ b/utils/1c/reg.c
@@ -0,0 +1,1221 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->costr;
+ if(p2->costa > c1)
+ c1 = p2->costa;
+ c2 = p1->costr;
+ if(p1->costa > c2)
+ c2 = p1->costa;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long val, initpc, npc;
+ ulong vreg;
+ Bits bit;
+ Var *v;
+ struct {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+ regbits = RtoB(0) | /* return reg */
+ AtoB(6) | AtoB(7) | /* sp and sb */
+ FtoB(0) | FtoB(1); /* floating return reg */
+ for(i=0; i<NREG; i++) {
+ if(regused[i])
+ regbits |= RtoB(i);
+ if(fregused[i])
+ regbits |= FtoB(i);
+ if(aregused[i])
+ regbits |= AtoB(i);
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ABRA:
+ case ARTS:
+ case ARTE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(&p->from, AGOK);
+ if(bany(&bit))
+ switch(p->as) {
+ case ALEA:
+ if(!(mvbits & B_INDIR))
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+
+ default:
+ if(mvbits & B_ADDR)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ }
+
+ bit = mkvar(&p->to, p->as);
+ if(bany(&bit))
+ switch(p->as) {
+ case ABSR: /* funny */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ goto def;
+
+ case APEA:
+ if(!(mvbits & B_INDIR))
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+
+ def:
+ case ACMPB: case ACMPW: case ACMPL:
+ case AFCMPF: case AFCMPD:
+ case ATSTB: case ATSTW: case ATSTL:
+ case AFTSTF: case AFTSTD:
+ case ABFEXTU: case ABFEXTS:
+ if(mvbits & B_ADDR)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+
+ case AADDB: case AADDW: case AADDL:
+ case ASUBB: case ASUBW: case ASUBL:
+ case AANDB: case AANDW: case AANDL:
+ case AORB: case AORW: case AORL:
+ case AEORB: case AEORW: case AEORL:
+ case ABFINS:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+
+ case ANOP:
+ case AMOVB: case AMOVW: case AMOVL:
+ case AFMOVEB: case AFMOVEW: case AFMOVEL:
+ case ACLRB: case ACLRW: case ACLRL:
+ case AFMOVEF: case AFMOVED:
+ if(mvbits & B_INDIR)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ else
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ diag(Z, "ref not found\n%L:%P", p->lineno, p);
+ continue;
+ }
+ if(r1 == r) {
+ diag(Z, "ref to self");
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R'])
+ print("\n%L %D\n", firstr->prog->lineno, &firstr->prog->from);
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ changer = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] | r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ changer = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARTS)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(changer)
+ goto loop1;
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ changer = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(changer)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+
+ /*
+ * 68040 'feature':
+ * load of a denormalized fp will trap
+ */
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ v = var + i;
+ if(v->type == D_AUTO) {
+ r->set.b[i/32] |= (1L << (i%32));
+ if(typefd[v->etype])
+ addmove(r, i, NREG+NREG, 1);
+ }
+ }
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n set = %B; rah = %B; cal = %B\n",
+ r->prog, r->set, r->refahead, r->calahead);
+ r->act = zbits;
+ }
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set an not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ changer = 0;
+ changea = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(changer <= 0 && changea <= 0) {
+ if(debug['R'])
+ print("%L$%d.%d: %B\n",
+ r->prog->lineno,
+ changer, changea, blsh(i));
+ continue;
+ }
+ rgp->costr = changer;
+ rgp->costa = changea;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R'])
+ print("%L$%d.%d %R: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->costr, rgp->costa,
+ rgp->regno,
+ bit);
+ if(rgp->regno != D_NONE)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Var *v;
+ int badccr;
+
+ badccr = 0;
+ p = r->prog;
+ p1 = p->link;
+ if(p1)
+ switch(p1->as) {
+ case AMOVW:
+ if(p1->from.type == D_CCR)
+ p = p1;
+ break;
+
+ case ABEQ:
+ case ABNE:
+ case ABLE:
+ case ABLS:
+ case ABLT:
+ case ABMI:
+ case ABGE:
+ case ABPL:
+ case ABGT:
+ case ABHI:
+ case ABCC:
+ case ABCS:
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ p1->from.type = D_CCR;
+ p1->to.type = D_TOS;
+ p1->as = AMOVW;
+ p = p1;
+ badccr = 1;
+ }
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+ p1->from.sym = v->sym;
+ p1->from.type = v->type;
+ p1->from.offset = v->offset;
+ p1->from.etype = v->etype;
+ p1->to.type = rn;
+ if(f) {
+ p1->to = p1->from;
+ p1->from = zprog.from;
+ p1->from.type = rn;
+ }
+ p1->as = opxt[OAS][v->etype];
+ if(badccr) {
+ p = p1;
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ p1->from.type = D_TOS;
+ p1->to.type = D_CCR;
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int as)
+{
+ Var *v;
+ int i, t, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ mvbits = 0;
+ t = a->type & D_MASK;
+ switch(t) {
+
+ default:
+ if(t >= D_R0 && t < D_R0+NREG) {
+ regbits |= RtoB(t-D_R0);
+ if(as == ADIVUL || as == ADIVSL)
+ regbits |= RtoB(t-D_R0+1);
+ }
+ if(t >= D_A0 && t < D_A0+NREG)
+ regbits |= AtoB(t-D_A0);
+ if(t >= D_F0 && t < D_F0+NREG)
+ regbits |= FtoB(t-D_F0);
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+
+ if((a->type & I_MASK) == I_ADDR)
+ mvbits |= B_ADDR;
+
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(t == v->type)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = a->etype;
+ v->type = t;
+ if(debug['R'])
+ print("bit=%2d et=%2d %s (%p,%d,%ld)\n",
+ i, a->etype, s->name,
+ v->sym, v->type, v->offset);
+
+out:
+ bit = blsh(i);
+ if(t == D_EXTERN || t == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(t == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(a->etype != v->etype || !typechlpfd[a->etype])
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z]; /* funny punning */
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ changer++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ changer++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABSR:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARTS:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ changer++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i, j;
+
+ v = var + r->varno;
+ r->regno = D_NONE;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype");
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = BtoR(~b);
+ j = BtoA(~b);
+ if(r->costa == r->costr)
+ if(i > j)
+ i = NREG;
+ if(j < NREG && r->costa > 0)
+ if(r->costa > r->costr || i >= NREG) {
+ r->regno = D_A0 + j;
+ return AtoB(j);
+ }
+ if(i < NREG && r->costr > 0) {
+ r->regno = D_R0 + i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i < NREG) {
+ r->regno = D_F0 + i;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+ int x;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ changer -= CLOAD * r->loop;
+ changea -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d.%d\n", r->loop,
+ r->prog, blsh(bn), changer, changea);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ changer += CREF * r->loop;
+ changea += CREF * r->loop;
+ switch(p->as) {
+ default:
+ changea = -CINF;
+ case AADDL:
+ case ASUBL:
+ case AMOVL:
+ case ACMPL:
+ break;
+ }
+ if(p->as == AMOVL) {
+ x = p->to.type;
+ if(x >= D_R0 && x < D_R0+NREG)
+ changer += r->loop;
+ if(x >= D_A0 && x < D_A0+NREG)
+ changea += r->loop;
+ }
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ changer += CREF * r->loop;
+ changea += CREF * r->loop;
+ switch(p->as) {
+ default:
+ changea = -CINF;
+ break;
+ case AMOVL:
+ case AADDL:
+ case ACMPL:
+ case ASUBL:
+ case ACLRL: /* can be faked */
+ case ATSTL: /* can be faked */
+ break;
+ }
+ if(p->as == AMOVL) {
+ x = p->from.type;
+ if(x >= D_R0 && x < D_R0+NREG)
+ changer += r->loop;
+ if(x >= D_A0 && x < D_A0+NREG)
+ changea += r->loop;
+ }
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ changer -= CLOAD * r->loop;
+ changea -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, ulong rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+ a->sym = 0;
+ if(rn >= D_R0 && rn < D_R0+NREG)
+ goto addr;
+ a->type = rn | (a->type & I_INDIR);
+ return;
+
+addr:
+ a->type = rn | (a->type & I_INDIR);
+}
+
+/*
+ * bit reg
+ * 0-7 R0-R7
+ * 8-15 A0-A7
+ * 16-23 F0-F7
+ */
+ulong
+RtoB(int r)
+{
+
+ if(r < 0 || r >= NREG)
+ return 0;
+ return 1L << (r + 0);
+}
+
+int
+BtoR(ulong b)
+{
+
+ b &= 0x0000ffL;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - 0;
+}
+
+ulong
+AtoB(int a)
+{
+
+ if(a < 0 || a >= NREG)
+ return 0;
+ return 1L << (a + NREG);
+}
+
+int
+BtoA(ulong b)
+{
+
+ b &= 0x00ff00L;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - NREG;
+}
+
+ulong
+FtoB(int f)
+{
+
+ if(f < 0 || f >= NREG)
+ return 0;
+ return 1L << (f + NREG+NREG);
+}
+
+int
+BtoF(ulong b)
+{
+
+ b &= 0xff0000L;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - NREG-NREG;
+}
diff --git a/utils/1c/sgen.c b/utils/1c/sgen.c
new file mode 100644
index 00000000..b7da4762
--- /dev/null
+++ b/utils/1c/sgen.c
@@ -0,0 +1,694 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+
+ argoff = 0;
+ inargs = 0;
+ for(;; nn = nn->left) {
+ if(nn == Z) {
+ diag(Z, "cant find function name");
+ return;
+ }
+ if(nn->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, nn->sym, D_CONST, stkoff);
+ sp = p;
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", nn->sym->name);
+
+ noretval(3);
+ gbranch(ORETURN);
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+}
+
+void
+gen(Node *n)
+{
+ Node *l;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int g, o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ doinc(n, PRE);
+ cgen(n, D_NONE, n);
+ doinc(n, POST);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ doinc(l, PRE);
+ if(typesuv[n->type->etype]) {
+ sugen(l, D_TREE, nodret, n->type->width);
+ doinc(l, POST);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ g = regalloc(n->type, regret(n->type));
+ cgen(l, g, n);
+ doinc(l, POST);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ regfree(g);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ gbranch(OGOTO);
+ if(n->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ setsp();;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ setsp();
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ doinc(l, PRE);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+ g = regalloc(types[TLONG], D_NONE);
+ n->type = types[TLONG];
+ cgen(l, g, n);
+ regfree(g);
+ doinc(l, POST);
+ setsp();
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ doswit(g, l);
+
+ patch(spb, pc);
+ cases = cn;
+ breakpc = sbc;
+ setsp();
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ bcomplex(l);
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z);
+ p->as = ANOP;
+ break;
+ case ONAME:
+ if(o == OSET)
+ gopcode(OTST, types[TINT], D_NONE, Z, D_TREE, n);
+ else
+ gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z);
+ p->as = ANOP;
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TLONG]), Z);
+ p->as = ANOP;
+ }
+ if(n & 2) {
+ gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TDOUBLE]), Z);
+ p->as = ANOP;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * REGISTER ==> 12 register
+ * NAME ==> 11 name+value(SB/SP)
+ * note that 10 is no longer generated
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 12 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (12) + (20) ==> 12 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(12) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (2,10,11) + (20) ==> 2 indirect w offset
+ * (2) ==> &13
+ * *(10,11) ==> 13 indirect, no index
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (12,1) ==> 8 adder in indexing (addresses)
+ * (X,7) + (10,11,2) ==> 8 adder in indexing (names)
+ * (8) ==> &9 index, almost addressable
+ *
+ * (X)++ ==> X fake addressability
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 11; /* difference to make relocatable */
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 12;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ if(l->addable == 20)
+ switch(r->addable) {
+ case 12:
+ case 1:
+ n->addable = r->addable;
+ goto brk;
+ }
+ if(r->addable == 20)
+ switch(l->addable) {
+ case 12:
+ case 1:
+ n->addable = l->addable;
+ goto brk;
+ }
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 12:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vconst(r);
+ if(g >= 0 && g < 4)
+ n->addable = 7;
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ if(g < 4)
+ n->addable = 7;
+ break;
+ }
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ n->op = OASHL;
+ r->vconst = g;
+ if(g < 4)
+ n->addable = 7;
+ break;
+ }
+ break;
+
+ case ODIV:
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ if(n->op == ODIV)
+ n->op = OASHR;
+ else
+ n->op = OLSHR;
+ r->vconst = g;
+ }
+ break;
+
+ case OSUB:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ if(vconst(l) == 0) {
+ n->op = ONEG;
+ n->left = r;
+ n->right = Z;
+ }
+ break;
+
+ case OXOR:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ if(vconst(l) == -1) {
+ n->op = OCOM;
+ n->left = r;
+ n->right = Z;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ goto aseae;
+
+ case OASDIV:
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ if(n->op == OASDIV)
+ n->op = OASASHR;
+ else
+ n->op = OASLSHR;
+ r->vconst = g;
+ }
+ goto aseae;
+
+ case OASLMOD:
+ case OASMOD:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+
+ aseae: /* hack that there are no byte/short mul/div operators */
+ if(n->type->etype == TCHAR || n->type->etype == TSHORT) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = types[TLONG];
+ n->type = types[TLONG];
+ }
+ if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = types[TULONG];
+ n->type = types[TULONG];
+ }
+ goto asop;
+
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+ case OAS:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+
+ asop:
+ if(l->addable > INDEXED &&
+ l->complex < FNX &&
+ r && r->complex < FNX)
+ n->addable = l->addable;
+ break;
+
+ case OPOSTINC:
+ case OPREINC:
+ case OPOSTDEC:
+ case OPREDEC:
+ xcom(l);
+ if(typev[n->type->etype])
+ break;
+ if(l->addable > INDEXED &&
+ l->complex < FNX)
+ n->addable = l->addable;
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+
+brk:
+ n->complex = 0;
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OMUL:
+ case OLMUL:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * symmetric operators, make right side simple
+ * if same, put constant on left to get movq
+ */
+ if(r->complex > l->complex ||
+ (r->complex == l->complex && r->addable == 20)) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OEQ:
+ case ONE:
+ /*
+ * relational operators, make right side simple
+ * if same, put constant on left to get movq
+ */
+ if(r->complex > l->complex || r->addable == 20) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+bcomplex(Node *n)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ bool64(n);
+ doinc(n, PRE);
+ boolgen(n, 1, D_NONE, Z, n);
+ } else
+ gbranch(OGOTO);
+}
+
+Node*
+nodconst(long v)
+{
+
+ return (Node*)v;
+}
diff --git a/utils/1c/swt.c b/utils/1c/swt.c
new file mode 100644
index 00000000..dc735a29
--- /dev/null
+++ b/utils/1c/swt.c
@@ -0,0 +1,964 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(int g, Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ swit1(iq, nc, def, g, n);
+}
+
+#define N1 4 /* ncase: always linear */
+ /* else binary */
+void
+swit1(C1 *q, int nc, long def, int g, Node *n)
+{
+ C1 *r;
+ int i;
+ long v;
+ Prog *sp1, *sp2;
+
+ /* note that g and g+1 are not allocated */
+ if(nc <= N1)
+ goto linear;
+
+ /*
+ * divide and conquer
+ */
+ i = nc / 2;
+ r = q+i;
+ v = r->val;
+ /* compare median */
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g, n, g+1, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OLT);
+ sp1 = p;
+ gbranch(OGT);
+ sp2 = p;
+ gbranch(OGOTO);
+ patch(p, r->label);
+
+ patch(sp1, pc);
+ swit1(q, i, def, g, n);
+
+ patch(sp2, pc);
+ swit1(r+1, nc-i-1, def, g, n);
+ return;
+
+linear:
+ for(i=0; i<nc; i++) {
+ v = q->val;
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g+1, n, g, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OEQ);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+
+int
+bitload(Node *b, int n1, int n2, int n3, Node *nn)
+{
+ int sh, g, gs;
+ long v;
+ Node *l;
+ Type *t;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ gs = 0;
+ t = tfield;
+
+ l = b->left;
+ g = regalloc(t, n3);
+ if(n2 != D_NONE) {
+ lcgen(l, n2, Z);
+ n2 |= I_INDIR;
+ gmove(t, t, n2, l, g, l);
+ gmove(t, t, g, l, n1, l);
+ } else
+ cgen(l, g, nn);
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, t, D_CONST, nodconst(v), g, l);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ if(sh >= 8) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ gopcode(OASHL, t, gs, l, g, l);
+ if(b->type->shift)
+ regfree(gs);
+ } else
+ gopcode(OASHL, t, D_CONST, nodconst(sh), g, l);
+ sh += b->type->shift;
+ if(sh > 0) {
+ if(sh >= 8) {
+ if(b->type->shift) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ }
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, t, gs, l, g, l);
+ else
+ gopcode(OASHR, t, gs, l, g, l);
+ regfree(gs);
+ } else {
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, t, D_CONST, nodconst(sh), g, l);
+ else
+ gopcode(OASHR, t, D_CONST, nodconst(sh), g, l);
+ }
+ }
+ }
+ return g;
+}
+
+void
+bitstore(Node *b, int n1, int n2, int n3, int result, Node *nn)
+{
+ long v;
+ Node *l;
+ Type *t;
+ int sh, g, gs;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ t = tfield;
+
+ l = b->left;
+ g = regalloc(t, D_NONE);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, t, D_CONST, nodconst(v), n1, l);
+ gmove(t, t, n1, l, g, l);
+ if(result != D_NONE)
+ gmove(t, nn->type, n1, l, result, nn);
+ sh = b->type->shift;
+ if(sh > 0) {
+ if(sh >= 8) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ gopcode(OASHL, t, gs, l, g, l);
+ regfree(gs);
+ } else
+ gopcode(OASHL, t, D_CONST, nodconst(sh), g, l);
+ }
+ v <<= sh;
+ gopcode(OAND, t, D_CONST, nodconst(~v), n3, l);
+ gopcode(OOR, t, n3, l, g, l);
+ gmove(t, t, g, l, n2|I_INDIR, l);
+
+ regfree(g);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, D_SCONST, 0L);
+ memmove(p->to.sval, string, NSNAME);
+ p->from.offset = nstring - NSNAME;
+ p->from.displace = NSNAME;
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+doinc(Node *n, int f)
+{
+ Node *l;
+ int a;
+
+loop:
+ if(n == Z)
+ return 0;
+ l = n->left;
+ switch(n->op) {
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(f & POST) {
+ a = n->addable;
+ if(a >= INDEXED) {
+ if(f & TEST)
+ return 1;
+ n->addable = 0;
+ cgen(n, D_NONE, n);
+ n->addable = a;
+ }
+ }
+ break;
+
+ case OAS:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+
+ case OPREINC:
+ case OPREDEC:
+ if(f & PRE) {
+ a = n->addable;
+ if(a >= INDEXED) {
+ if(f & TEST)
+ return 1;
+ n->addable = 0;
+ doinc(n, PRE);
+ cgen(n, D_NONE, n);
+ n->addable = a;
+ return 0;
+ }
+ }
+ break;
+
+ case OFUNC:
+ if(f & PRE)
+ break;
+ return 0;
+
+ case ONAME:
+ case OREGISTER:
+ case OSTRING:
+ case OCONST:
+
+ case OANDAND:
+ case OOROR:
+ return 0;
+
+ case OCOND:
+ return 0;
+
+ case OCOMMA:
+ n = n->right;
+ if(f & PRE)
+ n = l;
+ goto loop;
+ }
+ if(l != Z)
+ if(doinc(l, f))
+ return 1;
+ n = n->right;
+ goto loop;
+}
+
+void
+setsp(void)
+{
+
+ nextpc();
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+}
+
+void
+adjsp(long o)
+{
+
+ if(o != 0) {
+ nextpc();
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = o;
+ argoff += o;
+ }
+}
+
+int
+simplv(Node *n)
+{
+
+ if(n->addable <= INDEXED)
+ return 0;
+ while(n->op == OIND)
+ n = n->left;
+ if(n->op == ONAME)
+ return 1;
+ return 0;
+}
+
+int
+eval(Node *n, int g)
+{
+
+ if(n->addable >= INDEXED)
+ return D_TREE;
+ g = regalloc(n->type, g);
+ cgen(n, g, n);
+ return g;
+}
+
+void outhist(Biobuf*);
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cant open %s", outfile);
+ errorexit();
+ }
+ Binit(&b, f, OWRITE);
+ Bseek(&b, 0L, 2);
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type & D_MASK;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type & D_MASK;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&b, p, sf, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ long l;
+
+ l = p->as;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ l = p->lineno;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ zaddr(b, &p->from, sf);
+ zaddr(b, &p->to, st);
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->field)
+ t |= T_FIELD;
+ if(s)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ if(a->offset)
+ t |= T_OFFSET;
+ if(a->displace)
+ t |= T_INDEX;
+ if(a->type & ~0xff)
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_FIELD) { /* implies field */
+ i = a->field;
+ Bputc(b, i);
+ Bputc(b, i>>8);
+ }
+ if(t & T_INDEX) { /* implies index, scale, displace */
+ i = D_NONE;
+ Bputc(b, i);
+ Bputc(b, i>>8);
+ Bputc(b, 0);
+ l = a->displace;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ i = a->type;
+ Bputc(b, i);
+ if(t & T_TYPE)
+ Bputc(b, i>>8);
+}
+
+
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+int
+nodalloc(Type *t, int g, Node *n)
+{
+
+ n->type = t;
+ n->op = OREGISTER;
+ n->addable = 12;
+ n->complex = 0;
+ g = regaddr(g);
+ n->reg = g | I_INDIR;
+ n->xoffset = 0;
+ return g;
+}
+
+int
+mulcon(Node *n, Node *c, int result, Node *nn)
+{
+ long v;
+
+ if(typefd[n->type->etype])
+ return 0;
+ v = c->vconst;
+ if(mulcon1(n, v, result, nn))
+ return 1;
+ return 0;
+}
+
+int
+shlcon(Node *n, Node *c, int result, Node *nn)
+{
+ long v;
+
+ v = 1L << c->vconst;
+ return mulcon1(n, v, result, nn);
+}
+
+int
+mulcon1(Node *n, long v, int result, Node *nn)
+{
+ int g, g1, a1, a2, neg;
+ int o;
+ char code[10], *p;
+
+ if(result == D_NONE)
+ return 0;
+ neg = 0;
+ if(v < 0) {
+ v = -v;
+ neg++;
+ }
+ a1 = 0;
+ a2 = multabsize;
+ for(;;) {
+ if(a1 >= a2)
+ return 0;
+ g1 = (a2 + a1)/2;
+ if(v < multab[g1].val) {
+ a2 = g1;
+ continue;
+ }
+ if(v > multab[g1].val) {
+ a1 = g1+1;
+ continue;
+ }
+ break;
+ }
+ strcpy(code, "0");
+ strncat(code, multab[g1].code, sizeof(multab[0].code));
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ g = regalloc(n->type, result);
+ cgen(n, g, n);
+ if(neg)
+ gopcode(ONEG, n->type, D_NONE, n, g, n);
+ g1 = regalloc(n->type, D_NONE);
+loop:
+ switch(*p) {
+ case 0:
+ regfree(g1);
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ return 1;
+ case '0':
+ o = OAS;
+ *p -= '0';
+ goto com;
+ case '1':
+ case '2':
+ o = OSUB;
+ *p -= '1';
+ goto com;
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ o = OADD;
+ *p -= '3';
+ com:
+ a1 = g;
+ if(*p == 1 || *p == 3)
+ a1 = g1;
+ a2 = g;
+ if(*p == 0 || *p == 3)
+ a2 = g1;
+ gopcode(o, n->type, a1, n, a2, n);
+ p++;
+ break;
+ default:
+ a1 = *p++ - 'a' + 1;
+ a2 = g;
+ if(a1 > 8) {
+ a2 = g1;
+ a1 -= 8;
+ }
+ gopcode(OASHL, n->type, D_CONST, nodconst(a1), a2, n);
+ break;
+ }
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, D_NONE, Z);
+ if(r != Z)
+ cgen(r, D_NONE, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, D_SCONST, 0L);
+ p->from.offset += o+e;
+ p->from.displace = lw;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, D_CONST, (long)(a->vconst>>32));
+ p->from.offset += o;
+ p->from.displace = 4;
+ gpseudo(ADATA, s, D_CONST, (long)(a->vconst));
+ p->from.offset += o + 4;
+ p->from.displace = 4;
+ return;
+ }
+ gpseudotree(ADATA, s, a);
+ p->from.offset += o;
+ p->from.displace = w;
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_SHORT)
+ w = SZ_SHORT;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ o += SZ_LONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/utils/1c/txt.c b/utils/1c/txt.c
new file mode 100644
index 00000000..e439c40c
--- /dev/null
+++ b/utils/1c/txt.c
@@ -0,0 +1,903 @@
+#include "gc.h"
+
+void
+tindex(Type *tf, Type *tt)
+{
+ int i, j;
+
+ j = 0;
+ if(tt != T) {
+ j = tt->etype;
+ if(j >= NTYPE)
+ j = 0;
+ }
+ i = 0;
+ if(tf != T) {
+ i = tf->etype;
+ if(i >= NTYPE)
+ if(typesu[i])
+ i = j;
+ else
+ i = 0;
+ }
+ txtp = &txt[i][j];
+}
+
+void
+ginit(void)
+{
+ int i, j, si, sj;
+
+ thestring = "68000";
+ thechar = '1';
+ exregoffset = 7;
+ exaregoffset = 5;
+ exfregoffset = 7;
+ listinit();
+ for(i=0; i<NREG; i++) {
+ regused[i] = 0;
+ fregused[i] = 0;
+ aregused[i] = 0;
+ }
+ regaddr(D_A0+6);
+ regaddr(D_A0+7);
+ for(i=0; i<sizeof(regbase); i++)
+ regbase[i] = D_NONE;
+ for(i=0; i<NREG; i++) {
+ regbase[D_R0+i] = D_R0+i;
+ regbase[D_A0+i] = D_A0+i;
+ regbase[D_F0+i] = D_F0+i;
+ }
+ regbase[D_TOS] = D_TOS;
+
+ for(i=0; i<NTYPE; i++)
+ for(j=0; j<NTYPE; j++) {
+ txtp = &txt[i][j];
+ txtp->movas = AGOK;
+ txtp->preclr = 0;
+ txtp->postext = AGOK;
+ if(!(typechlp[i] && typechlp[j]))
+ continue;
+ si = types[i]->width;
+ sj = types[j]->width;
+ if(sj < si)
+ txtp->preclr = -1;
+ if(sj > si) {
+ if(typeu[i]) {
+ txtp->preclr = 1;
+ } else {
+ if(sj == 2)
+ txtp->postext = AEXTBW;
+ else
+ if(sj == 4)
+ if(si == 1)
+ txtp->postext = AEXTBL;
+ else
+ txtp->postext = AEXTWL;
+ }
+ sj = si;
+ }
+ if(sj == 1)
+ txtp->movas = AMOVB;
+ if(sj == 2)
+ txtp->movas = AMOVW;
+ if(sj == 4)
+ txtp->movas = AMOVL;
+ }
+
+ for(i=0; i<ALLOP; i++)
+ for(j=0; j<NTYPE; j++)
+ opxt[i][j] = AGOK;
+ oinit(OFUNC, ABSR, ATRAP, AGOK, AGOK, AGOK);
+
+ oinit(OAS, AMOVB, AMOVW, AMOVL, AFMOVEF, AFMOVED);
+ oinit(OFAS, AFMOVEB, AFMOVEW, AFMOVEL, AFMOVEF, AFMOVED);
+ oinit(OADDR, AGOK, APEA, ALEA, AGOK, AGOK);
+ oinit(OPREINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OPOSTINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OPREDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OPOSTDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OASADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OASSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OASMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OASLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(ODIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
+ oinit(OLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
+ oinit(OASDIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
+ oinit(OASLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
+ oinit(OMOD, AGOK, ADIVSW, ADIVSL, AFMODF, AFMODD);
+ oinit(OASMOD, AGOK, ADIVSW, ADIVSL, AGOK, AGOK);
+ oinit(OLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
+ oinit(OASLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
+ oinit(OAND, AANDB, AANDW, AANDL, AGOK, AGOK);
+ oinit(OASAND, AANDB, AANDW, AANDL, AGOK, AGOK);
+ oinit(OOR, AORB, AORW, AORL, AGOK, AGOK);
+ oinit(OASOR, AORB, AORW, AORL, AGOK, AGOK);
+ oinit(OXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
+ oinit(OASXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
+ oinit(ONEG, ANEGB, ANEGW, ANEGL, AFNEGF, AFNEGD);
+ oinit(OCOM, ANOTB, ANOTW, ANOTL, AGOK, AGOK);
+ oinit(OTST, ATSTB, ATSTW, ATSTL, AFTSTF, AFTSTD);
+ oinit(OEQ, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(ONE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OGE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OGT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLO, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OHS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OHI, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
+ oinit(OASASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
+ oinit(OLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
+ oinit(OASLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
+ oinit(OASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
+ oinit(OASASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
+ oinit(OBIT, ABFEXTU, AGOK, AGOK, AGOK, AGOK);
+
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ nstatic = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.to = zprog.from;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = types[TIND]->etype;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = typ(TARRAY, types[TCHAR]);
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = symrathole->type;
+
+ com64init();
+
+ symstatic = slookup(".static");
+ symstatic->class = CSTATIC;
+ symstatic->type = typ(TARRAY, types[TLONG]);
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ regfree(D_A0+6);
+ regfree(D_A0+7);
+ for(i=0; i<NREG; i++) {
+ if(regused[i])
+ diag(Z, "missing R%d", i);
+ if(aregused[i])
+ diag(Z, "missing A%d", i);
+ if(fregused[i])
+ diag(Z, "missing F%d", i);
+ }
+
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symstatic->type->width = nstatic;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, D_CONST, s->type->width);
+ pc--;
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+oinit(int o, int ab, int aw, int al, int af, int ad)
+{
+ int i;
+
+ i = o;
+ if(i >= ALLOP) {
+ diag(Z, "op(%d) >= ALLOP(%d)", i, ALLOP);
+ errorexit();
+ }
+ opxt[i][TCHAR] = ab;
+ opxt[i][TUCHAR] = ab;
+ opxt[i][TSHORT] = aw;
+ opxt[i][TUSHORT] = aw;
+ opxt[i][TINT] = al;
+ opxt[i][TUINT] = al;
+ opxt[i][TLONG] = al;
+ opxt[i][TULONG] = al;
+ opxt[i][TIND] = al;
+ opxt[i][TFLOAT] = af;
+ opxt[i][TDOUBLE] = ad;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ return p;
+}
+
+void
+nextpc(void)
+{
+
+ p = prg();
+ pc++;
+ p->lineno = nearln;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n)
+{
+ long s;
+
+loop:
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ gargs(n->right);
+ n = n->left;
+ goto loop;
+ }
+ s = argoff;
+ cgen(n, D_TOS, n);
+ argoff = s + n->type->width;
+}
+
+void
+naddr(Node *n, Adr *a, int x)
+{
+ Node *l;
+ long v;
+
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OADDR:
+ case OIND:
+ naddr(n->left, a, x);
+ goto noadd;
+
+ case OREGISTER:
+ a->sym = S;
+ a->type = n->reg;
+ a->offset = n->xoffset;
+ a->displace = 0;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->displace = 0;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ a->type = D_STATIC;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->displace = 0;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ break;
+
+ case OADD:
+ l = n->left;
+ if(l->addable == 20) {
+ v = l->vconst;
+ naddr(n->right, a, x);
+ goto add;
+ }
+ l = n->right;
+ if(l->addable == 20) {
+ v = l->vconst;
+ naddr(n->left, a, x);
+ goto add;
+ }
+ goto bad;
+
+ noadd:
+ v = 0;
+ add:
+ switch(n->addable) {
+ default:
+ goto bad;
+ case 2:
+ a->displace += v;
+ break;
+ case 21:
+ a->type &= D_MASK;
+ a->type |= I_INDIR;
+ break;
+ case 1:
+ case 12:
+ a->offset += v;
+ a->type &= D_MASK;
+ a->type |= I_ADDR;
+ break;
+ case 10:
+ case 11:
+ case 20:
+ a->type &= D_MASK;
+ a->type |= I_DIR;
+ break;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+
+ case OAS:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+ naddr(n->left, a, x);
+ break;
+ }
+}
+
+int
+regalloc(Type *t, int g)
+{
+
+ if(t == T)
+ return D_NONE;
+ g &= D_MASK;
+ if(typefd[t->etype]) {
+ if(g >= D_F0 && g < D_F0+NREG) {
+ fregused[g-D_F0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(fregused[g] == 0) {
+ fregused[g]++;
+ return g + D_F0;
+ }
+ } else {
+ if(g >= D_R0 && g < D_R0+NREG) {
+ regused[g-D_R0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(regused[g] == 0) {
+ regused[g]++;
+ return g + D_R0;
+ }
+ }
+ diag(Z, "out of registers");
+ return D_TOS;
+}
+
+int
+regaddr(int g)
+{
+
+ if(g >= D_A0 && g < D_A0+NREG) {
+ aregused[g-D_A0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(aregused[g] == 0) {
+ aregused[g]++;
+ return g + D_A0;
+ }
+ diag(Z, "out of addr registers");
+ return D_TOS;
+}
+
+int
+regpair(int g)
+{
+
+ if(g >= D_R0+1 && g < D_R0+NREG)
+ if(!regused[g-D_R0-1]) {
+ regused[g-D_R0-1]++;
+ regused[g-D_R0]++;
+ return g-1;
+ }
+ if(g >= D_R0 && g < D_R0+NREG-1)
+ if(!regused[g-D_R0+1]) {
+ regused[g-D_R0+1]++;
+ regused[g-D_R0]++;
+ return g;
+ }
+ for(g = 0; g < NREG-1; g++)
+ if(!regused[g])
+ if(!regused[g+1]) {
+ regused[g]++;
+ regused[g+1]++;
+ return g + D_R0;
+ }
+ diag(Z, "out of register pairs");
+ return D_TOS;
+}
+
+int
+regret(Type *t)
+{
+
+ if(t == T)
+ return D_NONE;
+ if(typefd[t->etype])
+ return D_F0;
+ return D_R0;
+}
+
+void
+regfree(int g)
+{
+
+ g &= D_MASK;
+ if(g == D_TOS || g == D_TREE || g == D_NONE)
+ return;
+ if(g >= D_R0 && g < D_R0+NREG) {
+ regused[g-D_R0]--;
+ return;
+ }
+ if(g >= D_A0 && g < D_A0+NREG) {
+ aregused[g-D_A0]--;
+ return;
+ }
+ if(g >= D_F0 && g < D_F0+NREG) {
+ fregused[g-D_F0]--;
+ return;
+ }
+ diag(Z, "bad in regfree: %d", g);
+}
+
+void
+gmove(Type *tf, Type *tt, int gf, Node *f, int gt, Node *t)
+{
+ int g, a, b;
+ Prog *p1;
+
+ tindex(tf, tt);
+ if(txtp->preclr) {
+ if(gf >= D_R0 && gf < D_R0+NREG)
+ if(txtp->preclr < 0) {
+ gmove(tt, tt, gf, f, gt, t);
+ return;
+ }
+ g = regalloc(types[TLONG], gt);
+ if(g == gf) {
+ g = regalloc(types[TLONG], D_NONE);
+ regfree(gf);
+ }
+ if(txtp->preclr > 0)
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(0), g, Z);
+ gopcode(OAS, tf, gf, f, g, Z);
+ if(g != gt)
+ gopcode(OAS, tt, g, Z, gt, t);
+ regfree(g);
+ return;
+ }
+ a = txtp->postext;
+ if(a != AGOK) {
+ if(gf >= D_R0 && gf < D_R0+NREG)
+ g = regalloc(types[TLONG], gf);
+ else
+ g = regalloc(types[TLONG], gt);
+ if(g != gf)
+ gopcode(OAS, tf, gf, f, g, Z);
+ nextpc();
+ p->as = a;
+ p->to.type = g;
+ if(debug['g'])
+ print("%P\n", p);
+ if(g != gt)
+ gopcode(OAS, tt, g, Z, gt, t);
+ regfree(g);
+ return;
+ }
+ if((regbase[gf] != D_NONE && regbase[gf] == regbase[gt]) ||
+ (gf == D_TREE && gt == D_TREE && f == t))
+ return;
+ if(typefd[tf->etype] || typefd[tt->etype]) {
+ if(typeu[tf->etype] && typefd[tt->etype]) { /* unsign->float */
+ a = regalloc(types[TLONG], D_NONE);
+ gmove(tf, types[TLONG], gf, f, a, t);
+ if(tf->etype == TULONG) {
+ b = regalloc(types[TDOUBLE], D_NONE);
+ gmove(types[TLONG], tt, a, t, b, t);
+ gopcode(OTST, types[TLONG], D_NONE, Z, a, t);
+ gbranch(OGE);
+ p1 = p;
+ gopcode(OASADD, types[TDOUBLE],
+ D_CONST, nodconst(100), b, t);
+ p->from.dval = 4294967296.;
+ patch(p1, pc);
+ gmove(types[TDOUBLE], tt, b, t, gt, t);
+ regfree(b);
+ } else
+ gmove(types[TLONG], tt, a, t, gt, t);
+ regfree(a);
+ return;
+ }
+ if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */
+ a = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], D_FPCR, t, a, t);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(16), D_FPCR, t);
+ }
+ if(gf < D_F0 || gf >= D_F0+NREG) {
+ g = regalloc(types[TDOUBLE], gt);
+ gopcode(OFAS, tf, gf, f, g, t);
+ if(g != gt)
+ gopcode(OFAS, tt, g, t, gt, t);
+ regfree(g);
+ } else
+ gopcode(OFAS, tt, gf, f, gt, t);
+ if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */
+ gopcode(OAS, types[TLONG], a, t, D_FPCR, t);
+ regfree(a);
+ }
+ return;
+ }
+ gopcode(OAS, tt, gf, f, gt, t);
+}
+
+void
+gopcode(int o, Type *ty, int gf, Node *f, int gt, Node *t)
+{
+ int i, fidx, tidx;
+
+ if(o == OAS)
+ if(gf == gt)
+ if(gf != D_TREE || f == t)
+ return;
+
+ fidx = D_NONE;
+ tidx = D_NONE;
+ i = 0;
+ if(ty != T) {
+ i = ty->etype;
+ if(i >= NTYPE)
+ i = 0;
+ }
+ nextpc();
+ if(gf == D_TREE) {
+ naddr(f, &p->from, fidx);
+ } else {
+ p->from.type = gf;
+ if(gf == D_CONST) {
+ p->from.offset = (long)(uintptr)f;
+ if(typefd[i]) {
+ p->from.type = D_FCONST;
+ p->from.dval = (long)(uintptr)f;
+ }
+ }
+ }
+ p->as = opxt[o][i];
+ if(gt == D_TREE) {
+ naddr(t, &p->to, tidx);
+ } else {
+ p->to.type = gt;
+ if(gt == D_CONST)
+ p->to.offset = (long)(uintptr)t;
+ }
+ if(o == OBIT) {
+ p->from.field = f->type->nbits;
+ p->to.field = f->type->shift;
+ if(p->from.field == 0)
+ diag(Z, "BIT zero width bit field");
+ }
+ if(p->as == AMOVL || p->as == AMOVW || p->as == AMOVB)
+ asopt();
+ if(debug['g'])
+ print("%P\n", p);
+ if(p->as == AGOK)
+ diag(Z, "GOK in gopcode: %s", onames[o]);
+ if(fidx != D_NONE)
+ regfree(fidx);
+ if(tidx != D_NONE)
+ regfree(tidx);
+}
+
+void
+asopt(void)
+{
+ long v;
+ int g;
+ Prog *q;
+
+ /*
+ * mov $0, ...
+ * ==>
+ * clr , ...
+ */
+ v = 0;
+ if(p->from.type == D_CONST) {
+ v = p->from.offset;
+ if(v == 0) {
+ p->from.type = D_NONE;
+ if(p->as == AMOVL)
+ p->as = ACLRL;
+ if(p->as == AMOVW)
+ p->as = ACLRW;
+ if(p->as == AMOVB)
+ p->as = ACLRB;
+ return;
+ }
+ }
+ /*
+ * mov ..., TOS
+ * ==>
+ * pea (...)
+ */
+ if(p->as == AMOVL && p->to.type == D_TOS)
+ switch(p->from.type) {
+ case D_CONST:
+ p->from.type |= I_INDIR;
+ p->to = p->from;
+ p->from = zprog.from;
+ p->as = APEA;
+ return;
+
+ case I_ADDR|D_EXTERN:
+ case I_ADDR|D_STATIC:
+ p->from.type &= ~I_ADDR;
+ p->to = p->from;
+ p->from = zprog.from;
+ p->as = APEA;
+ return;
+ }
+ /*
+ * movL $Qx, ...
+ * ==>
+ * movL $Qx,R
+ * movL R, ...
+ */
+ if(p->as == AMOVL && p->from.type == D_CONST)
+ if(v >= -128 && v < 128)
+ if(p->to.type < D_R0 || p->to.type >= D_R0+NREG) {
+ g = regalloc(types[TLONG], D_NONE);
+ q = p;
+ nextpc();
+ p->as = AMOVL;
+ p->from.type = g;
+ p->to = q->to;
+ q->to = p->from;
+ regfree(g);
+ if(debug['g'])
+ print("%P\n", q);
+ return;
+ }
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = ABNE;
+ switch(o) {
+ case ORETURN: a = ARTS; break;
+ case OGOTO: a = ABRA; break;
+ case OEQ: a = ABEQ; break;
+ case ONE: a = ABNE; break;
+ case OLE: a = ABLE; break;
+ case OLS: a = ABLS; break;
+ case OLT: a = ABLT; break;
+ case OLO: a = ABCS; break;
+ case OGE: a = ABGE; break;
+ case OHS: a = ABCC; break;
+ case OGT: a = ABGT; break;
+ case OHI: a = ABHI; break;
+ case OBIT: a = ABCS; break;
+ case OCASE: a = ABCASE; break;
+ }
+ nextpc();
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+ p->as = a;
+}
+
+void
+fpbranch(void)
+{
+ int a;
+
+ a = p->as;
+ switch(a) {
+ case ABEQ: a = AFBEQ; break;
+ case ABNE: a = AFBNE; break;
+ case ABLE: a = AFBLE; break;
+ case ABLT: a = AFBLT; break;
+ case ABGE: a = AFBGE; break;
+ case ABGT: a = AFBGT; break;
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, int g, long v)
+{
+
+ nextpc();
+ if(a == ADATA)
+ pc--;
+ p->as = a;
+ p->to.type = g;
+ p->to.offset = v;
+ p->from.sym = s;
+ p->from.type = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+}
+
+void
+gpseudotree(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ if(a == ADATA)
+ pc--;
+ p->as = a;
+ naddr(n, &p->to, D_NONE);
+ p->from.sym = s;
+ p->from.type = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechl[t->etype]) {
+ if(exregoffset <= 5)
+ return 0;
+ o = exregoffset + D_R0;
+ exregoffset--;
+ return o;
+ }
+ if(t->etype == TIND) {
+ if(exaregoffset <= 3)
+ return 0;
+ o = exaregoffset + D_A0;
+ exaregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 5)
+ return 0;
+ o = exfregoffset + D_F0;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/1l/Nt.c b/utils/1l/Nt.c
new file mode 100644
index 00000000..2efff499
--- /dev/null
+++ b/utils/1l/Nt.c
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/1l/Plan9.c b/utils/1l/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/1l/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/1l/Posix.c b/utils/1l/Posix.c
new file mode 100644
index 00000000..aa5d9551
--- /dev/null
+++ b/utils/1l/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fials if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
diff --git a/utils/1l/asm.c b/utils/1l/asm.c
new file mode 100644
index 00000000..f8dba670
--- /dev/null
+++ b/utils/1l/asm.c
@@ -0,0 +1,1534 @@
+#include "l.h"
+
+short opa[20];
+short *op;
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long v;
+ int a;
+ short *op1;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ curp = firstp;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->pc != pc) {
+ if(!debug['a'])
+ print("%P\n", curp);
+ diag("phase error %.4lux sb %.4lux in %s", p->pc, pc, TNAME);
+ pc = p->pc;
+ }
+ curp = p;
+ if(debug['a'])
+ Bprint(&bso, "%lux:%P\n", pc, curp);
+ asmins(p);
+ if(cbc < sizeof(opa))
+ cflush();
+ for(op1 = opa; op1 < op; op1++) {
+ a = *op1;
+ *cbp++ = a >> 8;
+ *cbp++ = a;
+ }
+ a = 2*(op - opa);
+ pc += a;
+ cbc -= a;
+ if(debug['a']) {
+ for(op1 = opa; op1 < op; op1++)
+ if(op1 == opa)
+ Bprint(&bso, "\t\t%4ux", *op1 & 0xffff);
+ else
+ Bprint(&bso, " %4ux", *op1 & 0xffff);
+ if(op != opa)
+ Bprint(&bso, "\n");
+ }
+ }
+ cflush();
+ switch(HEADTYPE) {
+ case 0: /* this is garbage */
+ seek(cout, rnd(HEADR+textsize, 8192), 0);
+ break;
+ case 1: /* plan9 boot data goes into text */
+ seek(cout, rnd(HEADR+textsize, INITRND), 0);
+ break;
+ case 2: /* plan 9 */
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 3: /* next boot */
+ seek(cout, HEADR+rnd(textsize, INITRND), 0);
+ break;
+ case 4: /* preprocess pilot */
+ seek(cout, HEADR+textsize, 0);
+ break;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ for(v = 0; v < datsize; v += sizeof(buf)-100) {
+ if(datsize-v > sizeof(buf)-100)
+ datblk(v, sizeof(buf)-100);
+ else
+ datblk(v, datsize-v);
+ }
+
+ symsize = 0;
+ spsize = 0;
+ lcsize = 0;
+ relocsize = 0;
+
+ Bflush(&bso);
+
+ switch(HEADTYPE) {
+ default:
+ seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ break;
+ case 1: /* plan9 boot data goes into text */
+ seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ break;
+ case 2: /* plan 9 */
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 3: /* next boot */
+ seek(cout, HEADR+rnd(textsize, INITRND)+datsize, 0);
+ break;
+ case 4: /* preprocess pilot */
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ }
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ asmsym();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ asmsp();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ asmlc();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ asmreloc();
+ }
+ cflush();
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ default:
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lput((0413<<16)|0437L); /* magic and version */
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT-HEADR); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ break;
+ case 1: /* plan9 boot data goes into text */
+ lput(0407); /* magic */
+ lput(rnd(HEADR+textsize, INITRND)-HEADR+datsize); /* sizes */
+ lput(0);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 2: /* plan 9 */
+ lput(0407); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 3: /* next boot */
+ /* header */
+ lput(0xfeedfaceL); /* magic */
+ lput(6); /* 68040 */
+ lput(1); /* more 68040 */
+ lput(5); /* file type 'boot' */
+ lput(HEADTYPE); /* number commands */
+ lput(HEADR-7*4); /* sizeof commands */
+ lput(1); /* no undefineds */
+ /* command 1 text */
+ lput(1); /* command = 'segment' */
+ lput(124); /* command size */
+ s16put("__TEXT");
+ /* botch?? entryvalue() */
+ lput(INITTEXT); /* va of start */
+ lput(rnd(textsize, 8192)); /* va size */
+ lput(HEADR); /* file offset */
+ lput(rnd(textsize, 8192)); /* file size */
+ lput(7); /* max prot */
+ lput(7); /* init prot */
+ lput(1); /* number of sections */
+ lput(0); /* flags */
+ /* text section */
+ s16put("__text");
+ s16put("__TEXT");
+ /* botch?? entryvalue() */
+ lput(INITTEXT); /* va of start */
+ lput(textsize); /* va size */
+ lput(HEADR); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(0); /* flags */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* command 1 data */
+ lput(1); /* command = 'segment' */
+ lput(192); /* command size */
+ s16put("__DATA");
+ lput(INITDAT); /* va of start */
+ lput(rnd(datsize, 8192)); /* va size */
+ lput(HEADR+rnd(textsize, 8192)); /* file offset */
+ lput(rnd(datsize, 8192)); /* file size */
+ lput(7); /* max prot */
+ lput(7); /* init prot */
+ lput(2); /* number of sections */
+ lput(0); /* flags */
+ /* data section */
+ s16put("__data");
+ s16put("__DATA");
+ lput(INITDAT); /* va of start */
+ lput(datsize); /* va size */
+ lput(HEADR+rnd(textsize, 8192)); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(0); /* flags */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* bss section */
+ s16put("__bss");
+ s16put("__DATA");
+ lput(INITDAT+datsize); /* va of start */
+ lput(bsssize); /* va size */
+ lput(0); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(1); /* flags = zero fill */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* command 2 symbol */
+ lput(2); /* command = 'symbol' */
+ lput(24); /* command size */
+ lput(HEADR+rnd(textsize, INITRND)
+ +datsize); /* symoff */
+ lput(symsize); /* nsyms */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 4: /* preprocess pilot */
+ lput(0407); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ lput(relocsize); /* relocation */
+ break;
+ }
+ cflush();
+}
+
+void
+asmins(Prog *p)
+{
+ Optab *o;
+ int t, a, b;
+ long v;
+
+ op = opa + 1;
+ if(special[p->from.type])
+ switch(p->from.type) {
+
+ case D_CCR:
+ if(p->as != AMOVW)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x42c0 | a; /* mov from ccr */
+ return;
+
+ case D_SR:
+ if(p->as != AMOVW)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x40c0 | a; /* mov from sr */
+ return;
+
+ case D_USP:
+ if(p->as != AMOVL)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010) {
+ opa[0] = 0x4e68|(a&7); /* mov usp An */
+ return;
+ }
+ t = 0x800;
+ goto movec1;
+
+ case D_SFC:
+ t = 0x000;
+ goto movec1;
+
+ case D_DFC:
+ t = 0x001;
+ goto movec1;
+
+ case D_CACR:
+ t = 0x002;
+ goto movec1;
+
+ case D_TC:
+ t = 0x003;
+ goto movec1;
+
+ case D_ITT0:
+ t = 0x004;
+ goto movec1;
+
+ case D_ITT1:
+ t = 0x005;
+ goto movec1;
+
+ case D_DTT0:
+ t = 0x006;
+ goto movec1;
+
+ case D_DTT1:
+ t = 0x007;
+ goto movec1;
+
+ case D_VBR:
+ t = 0x801;
+ goto movec1;
+
+ case D_CAAR:
+ t = 0x802;
+ goto movec1;
+
+ case D_MSP:
+ t = 0x803;
+ goto movec1;
+
+ case D_ISP:
+ t = 0x804;
+ goto movec1;
+
+ case D_MMUSR:
+ t = 0x805;
+ goto movec1;
+
+ case D_URP:
+ t = 0x806;
+ goto movec1;
+
+ case D_SRP:
+ t = 0x807;
+ goto movec1;
+
+ movec1:
+ if(p->as != AMOVL)
+ goto bad;
+ opa[0] = 0x4e7a; /* mov spc Dn */
+ a = asmea(p, &p->to);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ *op++ = (a<<12) | t;
+ return;
+ }
+ goto bad;
+
+ case D_FPCR:
+ t = 0xb000;
+ goto movec3;
+
+ case D_FPSR:
+ t = 0xa800;
+ goto movec3;
+
+ case D_FPIAR:
+ t = 0xa400;
+
+ movec3:
+ if(p->as != AMOVL)
+ goto bad;
+ op++;
+ a = asmea(p, &p->to);
+ opa[0] = optab[AFMOVEL].opcode0 | a;
+ opa[1] = t;
+ return;
+ }
+ if(special[p->to.type])
+ switch(p->to.type) {
+
+ case D_CCR:
+ if(p->as != AMOVW) /* botch, needs and, eor etc. */
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x44c0 | a; /* mov to ccr */
+ return;
+
+ case D_SR:
+ if(p->as != AMOVW) /* botch, needs and, eor etc. */
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x46c0 | a; /* mov to sr */
+ return;
+
+ case D_USP:
+ if(p->as != AMOVL)
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010) {
+ opa[0] = 0x4e60|(a&7); /* mov An usp */
+ return;
+ }
+ t = 0x800;
+ goto movec2;
+
+ case D_SFC:
+ t = 0x000;
+ goto movec2;
+
+ case D_DFC:
+ t = 0x001;
+ goto movec2;
+
+ case D_CACR:
+ t = 0x002;
+ goto movec2;
+
+ case D_TC:
+ t = 0x003;
+ goto movec2;
+
+ case D_ITT0:
+ t = 0x004;
+ goto movec2;
+
+ case D_ITT1:
+ t = 0x005;
+ goto movec2;
+
+ case D_DTT0:
+ t = 0x006;
+ goto movec2;
+
+ case D_DTT1:
+ t = 0x007;
+ goto movec2;
+
+ case D_VBR:
+ t = 0x801;
+ goto movec2;
+
+ case D_CAAR:
+ t = 0x802;
+ goto movec2;
+
+ case D_MSP:
+ t = 0x803;
+ goto movec2;
+
+ case D_ISP:
+ t = 0x804;
+ goto movec2;
+
+ case D_MMUSR:
+ t = 0x805;
+ goto movec2;
+
+ case D_URP:
+ t = 0x806;
+ goto movec2;
+
+ case D_SRP:
+ t = 0x807;
+ goto movec2;
+
+ movec2:
+ if(p->as != AMOVL)
+ goto bad;
+ opa[0] = 0x4e7b; /* mov Dn spc */
+ a = asmea(p, &p->from);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ *op++ = (a<<12) | t;
+ return;
+ }
+ goto bad;
+
+ case D_FPCR:
+ t = 0x9000;
+ goto movec4;
+
+ case D_FPSR:
+ t = 0x8800;
+ goto movec4;
+
+ case D_FPIAR:
+ t = 0x8400;
+
+ movec4:
+ if(p->as != AMOVL)
+ goto bad;
+ op++;
+ a = asmea(p, &p->from);
+ opa[0] = optab[AFMOVEL].opcode0 | a;
+ opa[1] = t;
+ return;
+ }
+
+ o = &optab[p->as];
+ t = o->opcode0;
+ switch(o->optype) {
+ case 0: /* pseudo ops */
+ if(p->as != ATEXT && p->as != ANOP) {
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("unimplemented instruction in %s", TNAME);
+ return;
+ }
+ op = opa;
+ return;
+
+ case 1: /* branches */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ a = asmea(p, &p->to);
+ if(a == 071)
+ t = o->opcode1;
+ t |= a;
+ break;
+
+ case 2: /* move */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0110) { /* src quick */
+ t = o->opcode1;
+ if((b & 0170) != 0)
+ goto bad;
+ t |= a >> 7;
+ t |= b << 9;
+ break;
+ }
+ t |= a;
+ t |= (b&7) << 9;
+ t |= (b&070) << 3;
+ break;
+
+ case 3: /* add */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0110) { /* src quick */
+ t = o->opcode1;
+ t |= (a&01600) << 2;
+ t |= b;
+ break;
+ }
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+ }
+ if((b & 0170) == 010) { /* dst An */
+ if((t & 0xc0) == 0)
+ goto bad;
+ t = o->opcode2;
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t |= 0x100;
+ t |= (a & 7) << 9;
+ t |= b;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode3;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 4: /* no operands */
+ break;
+
+ case 5: /* tst */
+ t |= asmea(p, &p->to);
+ if((t&0170) == 010)
+ goto bad;
+ break;
+
+ case 6: /* lea */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) != 010)
+ goto bad;
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+
+ case 7: /* cmp */
+ b = asmea(p, &p->to);
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010) { /* dst An */
+ t = o->opcode1;
+ if(t == 0) /* cmpb illegal */
+ goto bad;
+ t |= 0xc0;
+ t |= b;
+ t |= (a & 7) << 9;
+ break;
+ }
+ if((b & 0177) == 074) { /* src immed */
+ t = o->opcode2;
+ t |= a;
+ break;
+ }
+ if((a & 0170) == 0) { /* dst Dn */
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((b&0170) == 030 && (a&0170) == 030) { /* (A)+,(A)+ */
+ t = o->opcode3;
+ t |= b & 7;
+ t |= (a & 7) << 9;
+ break;
+ }
+ goto bad;
+
+ case 8: /* svc */
+ *op++ = optab[ARTS].opcode0;
+ break;
+
+ case 9: /* and */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= a;
+ t |= (b&7) << 9;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t = o->opcode1;
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode2;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 10: /* eor */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ if((a & 0170) == 0) { /* src Dn */
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode1;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 11: /* ext */
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 12: /* shift */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0177) == 0110) { /* src quick */
+ t |= (a & 01600) << 2;
+ t |= b;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t |= 0x20;
+ t |= a << 9;
+ t |= b;
+ break;
+ }
+ goto bad;
+ }
+ goto bad;
+
+ case 13: /* mul, div short */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0170) == 010)
+ goto bad;
+ t |= a;
+ t |= b << 9;
+ break;
+ }
+ goto bad;
+
+ case 14: /* mul, div long */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0170) == 010)
+ goto bad;
+ t |= a;
+ opa[1] |= b << 12;
+ opa[1] |= b+1;
+ break;
+ }
+ goto bad;
+
+ case 15: /* dec and branch */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ a = asmea(p, &p->from);
+ if((a & 0170) != 0)
+ goto bad;
+ t |= a;
+ break;
+
+ case 16: /* fmove */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0100) { /* src Fn */
+ if((b & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= b;
+ opa[1] = o->opcode2;
+ opa[1] |= (a&7) << 7;
+ break;
+ }
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ t |= a;
+ opa[1] = o->opcode3;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 17: /* floating ea,Fn */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((a & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 18: /* floating branchs */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ break;
+
+ case 19: /* floating dec and branch */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ *op++ = o->opcode1;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ a = asmea(p, &p->from);
+ if((a & 0170) != 0)
+ goto bad;
+ t |= a;
+ break;
+
+ case 20: /* ftst ea */
+ *op++ = o->opcode1;
+ if(p->from.type != D_NONE)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 0100) { /* Fn */
+ opa[1] |= (a&7) << 10;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ break;
+
+ case 21: /* fneg */
+ *op++ = o->opcode1;
+ if(p->from.type == D_NONE) {
+ b = asmea(p, &p->to);
+ a = b;
+ } else {
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ }
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((a & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 22: /* floating cmp Fn,ea */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((b & 0170) == 0100) { /* both Fn */
+ opa[1] |= (b&7) << 10;
+ opa[1] |= (a&7) << 7;
+ break;
+ }
+ t |= b;
+ opa[1] = o->opcode2;
+ opa[1] |= (a&7) << 7;
+ break;
+
+ case 23: /* word, long */
+ op = opa;
+ a = asmea(p, &p->to);
+ if(a == ((7<<3)|4))
+ return;
+ if(a == ((7<<3)|1)) {
+ if(p->as == AWORD) {
+ op = opa;
+ *op++ = opa[1];
+ }
+ return;
+ }
+ if(a == ((7<<3)|0)) {
+ if(p->as == ALONG) {
+ *op++ = opa[0];
+ opa[0] = 0;
+ }
+ return;
+ }
+ goto bad;
+
+ case 24: /* bit field */
+ a = ((p->to.field&31)<<6) | (p->from.field&31);
+ if(p->as == ABFINS) {
+ b = asmea(p, &p->from);
+ if((b&0170) != 0)
+ goto bad;
+ a |= b<<12;
+ *op++ = a;
+ a = asmea(p, &p->to);
+ } else {
+ if(p->to.type != D_NONE) {
+ b = asmea(p, &p->to);
+ if((b&0170) != 0)
+ goto bad;
+ a |= b<<12;
+ }
+ *op++ = a;
+ a = asmea(p, &p->from);
+ }
+ t |= a;
+ a &= 0170;
+ if(a == 010 || a == 030 || a == 040 || a == 074)
+ goto bad;
+ break;
+
+ case 25: /* movem */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ asmea(p, &p->from);
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ t |= 0x400;
+ asmea(p, &p->to);
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 26: /* chk */
+ a = asmea(p, &p->from);
+ if((a&0170) == 010)
+ goto bad;
+ b = asmea(p, &p->to);
+ if((b&0170) != 0)
+ goto bad;
+ t |= a;
+ t |= b<<9;
+ break;
+
+ case 27: /* btst */
+ a = asmea(p, &p->from);
+ if(a == 074) {
+ t = o->opcode1;
+ } else
+ if((a&0170) != 0)
+ goto bad;
+ b = asmea(p, &p->to);
+ if(b == 074 || (b&0170) == 010)
+ goto bad;
+ t |= b;
+ break;
+
+ case 28: /* fmovem */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ b = p->from.offset & 0xff;
+ b |= 0xf000; /* control or postinc */
+ *op++ = b;
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ if(b == 040)
+ op[-1] &= ~0x1000; /* predec */
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ b = p->to.offset & 0xff;
+ b |= 0xd000; /* control or postinc */
+ *op++ = b;
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 29: /* fmovemc */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ b = (p->from.offset & 0x7) << 10;
+ b |= 0xa000;
+ *op++ = b;
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ b = (p->to.offset & 0x7) << 10;
+ b |= 0x8000;
+ *op++ = b;
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 30: /* trap */
+ if(p->to.type == D_CONST) {
+ t |= p->to.offset & 0xf;
+ break;
+ }
+ goto bad;
+
+ case 31: /* chk2, cmp2 */
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a == 000 || a == 010) {
+ *op++ = o->opcode1 | (b << 12);
+ t |= asmea(p, &p->from);
+ break;
+ }
+ goto bad;
+
+ case 32: /* casew */
+ /* jmp (0,pc,r0.w*1) */
+ casepc = p->pc;
+ *op++ = o->opcode1;
+ break;
+
+ case 34: /* moves */
+ op++;
+ a = asmea(p, &p->from);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ opa[1] = (a << 12) | 0x800;
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a == 0 || a == 010)
+ goto bad;
+ t |= b;
+ break;
+ }
+ t |= a;
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a != 0 && a != 010)
+ goto bad;
+ opa[1] = (b << 12);
+ break;
+
+ case 35: /* swap */
+ a = asmea(p, &p->to);
+ if((a & 0170) == 0) {
+ t |= a;
+ break;
+ }
+ goto bad;
+ }
+ opa[0] = t;
+ return;
+
+bad:
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("bad combination of addressing in %s", TNAME);
+ opa[0] = 0;
+}
+
+int
+asmea(Prog *p, Adr *a)
+{
+ Optab *o;
+ int f, t, r, i;
+ long v;
+
+ t = a->type;
+ r = simple[t];
+ v = a->offset;
+ if(r != 0177) {
+ if(v == 0)
+ return r;
+ if((r & 070) != 020)
+ return r;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return t-D_A0-I_INDIR+050; /* d(Ax) */
+ }
+ goto toobig;
+ }
+ f = 0;
+ if(a == &p->from)
+ f++;
+ o = &optab[p->as];
+ switch(t) {
+ case D_TOS:
+ if(f) {
+ if(o->srcsp)
+ return (3<<3) | 7; /* (A7)+ */
+ } else
+ if(o->dstsp)
+ return (4<<3) | 7; /* -(A7) */
+ return (2<<3) | 7; /* (A7) */
+
+ case D_BRANCH:
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L) {
+ if(p->as == ABSR || p->as == ABRA) {
+ v = p->pcond->pc;
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ goto toobig;
+ }
+ if(v < -128 || v >= 128 || p->mark == 4) {
+ *op++ = v;
+ return 0;
+ }
+ return v & 0xff;
+
+ case I_ADDR|D_STATIC:
+ case I_ADDR|D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ v = a->sym->value + a->offset;
+ if(t != STEXT)
+ v += INITDAT;
+ if(strcmp(a->sym->name, "a6base"))
+ break;
+
+ case D_CONST:
+ switch(f? o->srcsp: o->dstsp) {
+ case 4:
+ *op++ = v>>16;
+
+ case 2:
+ *op++ = v;
+ break;
+
+ default:
+ diag("unknown srcsp asmea in %s", TNAME);
+ }
+ return (7<<3) | 4;
+
+ case D_FCONST:
+ r = f? o->srcsp: o->dstsp;
+ for(i=0; i<r; i++)
+ ((char*)op)[i] = gnuxi(&a->ieee, i, r);
+ op += r/2;
+ return (7<<3) | 4;
+
+ case D_QUICK:
+ v = a->offset & 0xff;
+ return 0110 | (v<<7);
+
+ case D_STACK:
+ case D_AUTO:
+ case D_PARAM:
+ if(v == 0)
+ return (2<<3) | 7; /* (A7) */
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (5<<3) | 7; /* d(A7) */
+ }
+ goto toobig;
+
+ case I_INDIR|D_CONST:
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 0;
+ }
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+
+ case D_STATIC:
+ case D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ if(t == STEXT) {
+ if(HEADTYPE == 4) {
+ v = a->sym->value + a->offset - p->pc - 2;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 2;
+ }
+ goto toobig;
+ }
+ v = a->sym->value + a->offset;
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ v = a->sym->value + a->offset - A6OFFSET;
+ if(v < -32768L || v >= 32768L) {
+ v += INITDAT + A6OFFSET;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 0;
+ }
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ if(v == 0)
+ return (2<<3) | 6;
+ *op++ = v;
+ return (5<<3) | 6;
+ }
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("unknown addressing mode: %d in %s", t, TNAME);
+ return 0;
+
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("bad operand in %s", TNAME);
+ return 0;
+
+toobig:
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("addressing mode >> 2^16: %d in %s", t, TNAME);
+ return 0;
+}
+
+void
+lput(long l)
+{
+
+ CPUT(l>>24)
+ CPUT(l>>16)
+ CPUT(l>>8)
+ CPUT(l)
+}
+
+void
+s16put(char *n)
+{
+ char name[16];
+ int i;
+
+ strncpy(name, n, sizeof(name));
+ for(i=0; i<sizeof(name); i++)
+ CPUT(name[i])
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->from.displace;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ switch(p->to.type) {
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (char*)&fl;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j+4]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i+4]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.scon[i];
+ l++;
+ }
+ break;
+ default:
+ fl = p->to.offset;
+ if(p->to.sym) {
+ if(p->to.sym->type == STEXT)
+ fl += p->to.sym->value;
+ if(p->to.sym->type == SDATA)
+ fl += p->to.sym->value + INITDAT;
+ if(p->to.sym->type == SBSS)
+ fl += p->to.sym->value + INITDAT;
+ }
+
+ cast = (char*)&fl;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi1[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi2[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi4[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+void
+asmreloc(void)
+{
+ Prog *p;
+ Sym *s1, *s2;
+ int c1, c2, c3;
+ long v;
+
+ if(HEADTYPE != 4)
+ return;
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ s1 = p->to.sym;
+ if(s1 == S)
+ continue;
+ c1 = 'D';
+ c3 = p->from.displace;
+ s2 = p->from.sym;
+ v = s2->value + INITDAT;
+ switch(s1->type) {
+ default:
+ diag("unknown reloc %d", s1->type);
+ continue;
+ case STEXT:
+ c2 = 'T';
+ break;
+
+ case SDATA:
+ c2 = 'D';
+ break;
+
+ case SBSS:
+ c2 = 'B';
+ break;
+ }
+ CPUT(c1);
+ CPUT(c2);
+ CPUT(c3);
+ lput(v);
+ if(debug['a'])
+ Bprint(&bso, "r %c%c%d %.8lux %s $%s\n",
+ c1, c2, c3, v, s2->name, s1->name);
+ relocsize += 7;
+ }
+}
+
+int
+gnuxi(Ieee *d, int i, int c)
+{
+ char *p;
+ long l;
+
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ return 0;
+
+ /*
+ * 2301 vax
+ * 0123 68k
+ */
+ case 4:
+ l = ieeedtof(d);
+ p = (char*)&l;
+ i = gnuxi8[i+4];
+ break;
+
+ /*
+ * 67452301 vax
+ * 45670123 68k
+ */
+ case 8:
+ p = (char*)d;
+ i = gnuxi8[i];
+ break;
+ }
+ return p[i];
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/utils/1l/l.h b/utils/1l/l.h
new file mode 100644
index 00000000..de8d48ff
--- /dev/null
+++ b/utils/1l/l.h
@@ -0,0 +1,268 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../2c/2.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext?curtext->from.sym->name:noname)
+#define CPUT(c)\
+ { *cbp++ = c;\
+ if(--cbc <= 0)\
+ cflush(); }
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+
+struct Adr
+{
+ short type;
+ uchar field;
+ union
+ {
+ struct
+ {
+ long u0displace;
+ long u0offset;
+ } s0;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+};
+
+#define displace u0.s0.u0displace
+#define offset u0.s0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0stkoff;
+ Prog *u0forwd;
+ } u0;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ long pc;
+ long line;
+ short as;
+ uchar mark; /* work on these */
+ uchar back;
+};
+
+#define stkoff u0.u0stkoff
+#define forwd u0.u0forwd
+
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ long value;
+ Sym* link;
+};
+struct Optab
+{
+ short as;
+ short fas;
+ short srcsp;
+ short dstsp;
+ ushort optype;
+ ushort opcode0;
+ ushort opcode1;
+ ushort opcode2;
+ ushort opcode3;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SAUTO,
+ SPARAM,
+ SFILE,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 4,
+ STRINGSZ = 200,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ A6OFFSET = 32766,
+};
+
+EXTERN union
+{
+ struct
+ {
+ char obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+EXTERN long HEADR;
+EXTERN long HEADTYPE;
+EXTERN long INITDAT;
+EXTERN long INITRND;
+EXTERN long INITTEXT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN long casepc;
+EXTERN int cbc;
+EXTERN char* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN Prog* prog_divsl;
+EXTERN Prog* prog_divul;
+EXTERN Prog* prog_mull;
+EXTERN Prog* prog_ccr;
+EXTERN char fnuxi8[8];
+EXTERN char gnuxi8[8];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN long relocsize;
+EXTERN long ndata;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long nsymbol;
+EXTERN char* noname;
+EXTERN short* op;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN char simple[I_MASK];
+EXTERN char special[I_MASK];
+EXTERN long spsize;
+EXTERN Sym* symlist;
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN Prog zprg;
+
+extern Optab optab[];
+extern char mmsize[];
+extern char* anames[];
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+int Xconv(Fmt*);
+void addhist(long, int);
+int andsize(Prog*, Adr*);
+void asmb(void);
+int asmea(Prog*, Adr*);
+void asmins(Prog*);
+void asmlc(void);
+void asmsp(void);
+void asmsym(void);
+void asmreloc(void);
+long atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void cflush(void);
+Prog* copyp(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+long entryvalue(void);
+void errorexit(void);
+int find1(long, int);
+int find2(long, int);
+void follow(void);
+void gethunk(void);
+int gnuxi(Ieee*, int, int);
+void histtoauto(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void initmuldiv1(void);
+void initmuldiv2(void);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void main(int, char*[]);
+void mkfwd(void);
+void* mysbrk(ulong);
+void nuxiinit(void);
+void objfile(char*);
+void patch(void);
+Prog* prg(void);
+Prog* nprg(Prog*);
+int relinv(int);
+long reuse(Prog*, Sym*);
+long rnd(long, long);
+void s16put(char*);
+void span(void);
+void undef(void);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+int zaddr(uchar*, Adr*, Sym*[]);
diff --git a/utils/1l/list.c b/utils/1l/list.c
new file mode 100644
index 00000000..f02c3efa
--- /dev/null
+++ b/utils/1l/list.c
@@ -0,0 +1,334 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+}
+
+static Prog *bigP;
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[20];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ sprint(str, "(%ld) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ if(p->from.field) {
+ sprint(s, ",%d,%d", p->to.field, p->from.field);
+ strcat(str, s);
+ }
+ bigP = P;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+
+ return fmtstrcpy(fp, anames[va_arg(fp->args, int)]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i, j;
+ long d;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ j = i & I_MASK;
+ if(j) {
+ a->type = i & D_MASK;
+ d = a->offset;
+ a->offset = 0;
+ switch(j) {
+ case I_INDINC:
+ sprint(str, "(%D)+", a);
+ break;
+
+ case I_INDDEC:
+ sprint(str, "-(%D)", a);
+ break;
+
+ case I_INDIR:
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_ADDR:
+ a->offset = d;
+ sprint(str, "$%D", a);
+ break;
+ }
+ a->type = i;
+ a->offset = d;
+ goto out;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ sprint(str, "%lux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ sprint(str, "%lux", bigP->pcond->pc);
+ else
+ sprint(str, "%ld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<%d>+%ld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_STACK:
+ sprint(str, "TOS+%ld", a->offset);
+ break;
+
+ case D_QUICK:
+ sprint(str, "$Q%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ goto out;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->scon);
+ goto out;
+ }
+ if(a->displace) {
+ sprint(s, "/%ld", a->displace);
+ strcat(str, s);
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_R0 && r < D_R0+NREG)
+ sprint(str, "R%d", r-D_R0);
+ else
+ if(r >= D_A0 && r < D_A0+NREG)
+ sprint(str, "A%d", r-D_A0);
+ else
+ if(r >= D_F0 && r < D_F0+NREG)
+ sprint(str, "F%d", r-D_F0);
+ else
+ switch(r) {
+
+ default:
+ sprint(str, "gok(%d)", r);
+ break;
+
+ case D_NONE:
+ sprint(str, "NONE");
+ break;
+
+ case D_TOS:
+ sprint(str, "TOS");
+ break;
+
+ case D_CCR:
+ sprint(str, "CCR");
+ break;
+
+ case D_SR:
+ sprint(str, "SR");
+ break;
+
+ case D_SFC:
+ sprint(str, "SFC");
+ break;
+
+ case D_DFC:
+ sprint(str, "DFC");
+ break;
+
+ case D_CACR:
+ sprint(str, "CACR");
+ break;
+
+ case D_USP:
+ sprint(str, "USP");
+ break;
+
+ case D_VBR:
+ sprint(str, "VBR");
+ break;
+
+ case D_CAAR:
+ sprint(str, "CAAR");
+ break;
+
+ case D_MSP:
+ sprint(str, "MSP");
+ break;
+
+ case D_ISP:
+ sprint(str, "ISP");
+ break;
+
+ case D_FPCR:
+ sprint(str, "FPCR");
+ break;
+
+ case D_FPSR:
+ sprint(str, "FPSR");
+ break;
+
+ case D_FPIAR:
+ sprint(str, "FPIAR");
+ break;
+
+ case D_TREE:
+ sprint(str, "TREE");
+ break;
+
+ case D_TC:
+ sprint(str, "TC");
+ break;
+
+ case D_ITT0:
+ sprint(str, "ITT0");
+ break;
+
+ case D_ITT1:
+ sprint(str, "ITT1");
+ break;
+
+ case D_DTT0:
+ sprint(str, "DTT0");
+ break;
+
+ case D_DTT1:
+ sprint(str, "DTT1");
+ break;
+
+ case D_MMUSR:
+ sprint(str, "MMUSR");
+ break;
+ case D_URP:
+ sprint(str, "URP");
+ break;
+
+ case D_SRP:
+ sprint(str, "SRP");
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/1l/mkfile b/utils/1l/mkfile
new file mode 100644
index 00000000..aafa5a70
--- /dev/null
+++ b/utils/1l/mkfile
@@ -0,0 +1,32 @@
+<../../mkconfig
+
+TARG=1l
+OFILES=\
+ asm.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ list.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../2c/2.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9
+BIN=$ROOT/$OBJDIR/bin
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I ../include
+
+enam.$O: ../2c/enam.c
+ $CC $CFLAGS ../2c/enam.c
+
+%.1: %.s
+ 1a $stem.s
+
+%.1: %.c
+ 1c -w $stem.c
diff --git a/utils/1l/obj.c b/utils/1l/obj.c
new file mode 100644
index 00000000..379a9ffb
--- /dev/null
+++ b/utils/1l/obj.c
@@ -0,0 +1,1380 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char symname[] = SYMDEF;
+char thechar = '1';
+char *thestring = "68000";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is garbage unix
+ * -H1 -T0x80020000 -R4 is garbage format
+ * -H2 -T8224 -R8192 is plan9 format
+ * -H3 -Tx -Rx is next boot
+ * -H4 -T0 -D0 is pilot relocatable
+ */
+
+void
+main(int argc, char *argv[])
+{
+ int i, c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = "1.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0) {
+ diag("usage: 1l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 2;
+ if(debug['B'])
+ HEADTYPE = 2;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ if(INITDAT != -1 && INITRND == -1)
+ INITRND = 0;
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option %d", HEADTYPE);
+ errorexit();
+
+ case 0: /* this is garbage */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* plan9 boot data goes into text */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 8224;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 8224;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192;
+ break;
+ case 3: /* next boot */
+ HEADR = 28+124+192+24;
+ if(INITTEXT == -1)
+ INITTEXT = 0x04002000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192L;
+ break;
+ case 4: /* preprocess pilot */
+ HEADR = 36L;
+ if(INITTEXT == -1)
+ INITTEXT = 0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
+ }
+
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.to = zprg.from;
+
+ memset(special, 0, sizeof(special));
+ special[D_CCR] = 1;
+ special[D_SR] = 1;
+ special[D_SFC] = 1;
+ special[D_CACR] = 1;
+ special[D_USP] = 1;
+ special[D_VBR] = 1;
+ special[D_CAAR] = 1;
+ special[D_MSP] = 1;
+ special[D_ISP] = 1;
+ special[D_DFC] = 1;
+ special[D_FPCR] = 1;
+ special[D_FPSR] = 1;
+ special[D_FPIAR] = 1;
+ special[D_TC] = 1;
+ special[D_ITT0] = 1;
+ special[D_ITT1] = 1;
+ special[D_DTT0] = 1;
+ special[D_DTT1] = 1;
+ special[D_MMUSR] = 1;
+ special[D_URP] = 1;
+ special[D_SRP] = 1;
+ memset(simple, 0177, sizeof(simple));
+ for(i=0; i<8; i++) {
+ simple[D_R0+i] = i;
+ simple[D_F0+i] = i+0100;
+ simple[D_A0+i] = i+010;
+ simple[D_A0+I_INDIR+i] = i+020;
+ simple[D_A0+I_INDINC+i] = i+030;
+ simple[D_A0+I_INDDEC+i] = i+040;
+ }
+ nuxiinit();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s", outfile);
+ errorexit();
+ }
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ initmuldiv1();
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ errorexit();
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ initmuldiv2();
+ follow();
+ dodata();
+ dostkoff();
+ span();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld data statements\n", ndata);
+ Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ sprint(name, "/%s/lib/lib", thestring);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int c, t, i;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ t = p[0];
+
+ /*
+ * first try the high-time formats
+ */
+ if(t == 0) {
+ a->type = p[1];
+ return 2;
+ }
+ if(t == T_OFFSET) {
+ a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
+ a->type = p[5];
+ return 6;
+ }
+ if(t == (T_OFFSET|T_SYM)) {
+ a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
+ s = h[p[5]];
+ a->sym = s;
+ a->type = p[6];
+ c = 7;
+ goto dosym;
+ }
+ if(t == T_SYM) {
+ s = h[p[1]];
+ a->sym = s;
+ a->type = p[2];
+ c = 3;
+ goto dosym;
+ }
+ if(t == (T_INDEX|T_OFFSET|T_SYM)) {
+ a->displace = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
+ a->offset = p[8] | (p[9]<<8) | (p[10]<<16) | (p[11]<<24);
+ s = h[p[12]];
+ a->sym = s;
+ a->type = p[13];
+ c = 14;
+ goto dosym;
+ }
+
+ /*
+ * now do it the hard way
+ */
+ c = 1;
+ if(t & T_FIELD) {
+ a->field = p[c] | (p[c+1]<<8);
+ c += 2;
+ }
+ if(t & T_INDEX) {
+ a->displace = p[c+3] | (p[c+4]<<8) | (p[c+5]<<16) | (p[c+6]<<24);
+ c += 7;
+ }
+ if(t & T_OFFSET) {
+ a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ c += 4;
+ }
+ if(t & T_SYM) {
+ a->sym = h[p[c]];
+ c += 1;
+ }
+ if(t & T_FCONST) {
+ a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
+ c += 8;
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ for(i=0; i<NSNAME; i++)
+ a->scon[i] = p[c+i];
+ c += NSNAME;
+ a->type = D_SCONST;
+ } else
+ if(t & T_TYPE) {
+ a->type = p[c] | (p[c+1]<<8);
+ c += 2;
+ } else {
+ a->type = p[c];
+ c++;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+
+dosym:
+ t = a->type & D_MASK;
+ if(t != D_AUTO && t != D_PARAM)
+ return c;
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ Prog *p;
+ Sym *h[NSYM], *s;
+ int v, o, r;
+ long ipc, lv;
+ double dv;
+ uchar *bloc, *bsize, *stop;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0] | (bloc[1] << 8);
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .%c file\n", thechar);
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[2]; /* type */
+ o = bloc[3]; /* sym */
+ bloc += 4;
+ c -= 4;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+ p->back = 2;
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ goto loop;
+
+ case ADATA:
+ p->link = datap;
+ datap = p;
+ ndata++;
+ goto loop;
+
+ case AGOK:
+ diag("%s: unknown opcode in %s", pn, TNAME);
+ pc++;
+ goto loop;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ curtext = p;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ s = p->from.sym;
+ if(s->type != 0 && s->type != SXREF)
+ diag("%s: redefinition: %s", pn, s->name);
+ s->type = STEXT;
+ s->value = p->pc;
+ pc++;
+ p->pcond = P;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->pcond = p;
+ etextp = p;
+ goto loop;
+
+ case AJSR:
+ p->as = ABSR;
+
+ case ABSR:
+ if(p->to.type != D_EXTERN && p->to.type != D_STATIC)
+ p->as = AJSR;
+ goto casdef;
+
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv >= -128 && lv < 128)
+ if(p->to.type >= D_R0 && p->to.type < D_R0+8) {
+ p->from.type = D_QUICK;
+ goto casdef;
+ }
+
+ if(lv >= -0x7fff && lv <= 0x7fff)
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ if(p->as == AMOVL)
+ p->as = AMOVW;
+ goto casdef;
+
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv < 0) {
+ lv = -lv;
+ p->from.offset = lv;
+ if(p->as == AADDB)
+ p->as = ASUBB;
+ else
+ if(p->as == AADDW)
+ p->as = ASUBW;
+ else
+ if(p->as == AADDL)
+ p->as = ASUBL;
+ }
+ if(lv > 0)
+ if(lv <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv < 0) {
+ lv = -lv;
+ p->from.offset = lv;
+ if(p->as == ASUBB)
+ p->as = AADDB;
+ else
+ if(p->as == ASUBW)
+ p->as = AADDW;
+ else
+ if(p->as == ASUBL)
+ p->as = AADDL;
+ }
+ if(lv > 0)
+ if(lv <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case AROTRB:
+ case AROTRL:
+ case AROTRW:
+ case AROTLB:
+ case AROTLL:
+ case AROTLW:
+
+ case AASLB:
+ case AASLL:
+ case AASLW:
+ case AASRB:
+ case AASRL:
+ case AASRW:
+ case ALSLB:
+ case ALSLL:
+ case ALSLW:
+ case ALSRB:
+ case ALSRL:
+ case ALSRW:
+ if(p->from.type == D_CONST)
+ if(p->from.offset > 0)
+ if(p->from.offset <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case ATSTL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8) {
+ p->as = ACMPW;
+ p->from = p->to;
+ p->to.type = D_CONST;
+ p->to.offset = 0;
+ }
+ goto casdef;
+
+ case ACMPL:
+ if(p->to.type != D_CONST)
+ goto casdef;
+ lv = p->to.offset;
+ if(lv >= -0x7fff && lv <= 0x7fff)
+ if(p->from.type >= D_A0 && p->from.type < D_A0+8)
+ p->as = ACMPW;
+ goto casdef;
+
+ case ACLRL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8) {
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(p->from.type == D_FCONST)
+ if(optab[p->as].fas != AXXX) {
+ dv = ieeedtod(&p->from.ieee);
+ if(dv >= -(1L<<30) && dv <= (1L<<30)) {
+ lv = dv;
+ if(lv == dv) {
+ p->as = optab[p->as].fas;
+ p->from.type = D_CONST;
+ p->from.offset = lv;
+ p->from.displace = 0;
+ }
+ }
+ }
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ goto loop;
+ }
+ goto loop;
+
+eof:
+ diag("%s: truncated object file in %s", pn, TNAME);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int l, c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ nsymbol++;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+Prog*
+nprg(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->stkoff = p->stkoff;
+ q->link = p->link;
+ p->link = q;
+ return q;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->as = AADDL;
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ q->from.type = D_CONST;
+ q->from.offset = 1;
+ q->to.type = D_EXTERN;
+ q->to.sym = s;
+ q->to.offset = n*4 + 4;
+
+ q = prg();
+ q->as = ADATA;
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.offset = n*4;
+ q->from.displace = 4;
+ q->to.type = D_EXTERN;
+ q->to.sym = p->from.sym;
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->as = ADATA;
+ q->link = datap;
+ datap = q;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.displace = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->from.displace = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->from.displace = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.displace != 0) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARTS) {
+ /*
+ * RTS
+ */
+ q = prg();
+ q->as = ARTS;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BSR profout
+ */
+ p->as = ABSR;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+long
+reuse(Prog *r, Sym *s)
+{
+ Prog *p;
+
+
+ if(r == P)
+ return 0;
+ for(p = datap; p != r; p = p->link)
+ if(p->to.sym == s)
+ return p->from.offset;
+ return 0;
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x01020304L, i+1);
+ if(i >= 2)
+ inuxi2[i-2] = c;
+ if(i >= 3)
+ inuxi1[i-3] = c;
+ inuxi4[i] = c;
+ fnuxi8[i] = c+4;
+ fnuxi8[i+4] = c;
+ c = find2(0x01020304L, i+1);
+ gnuxi8[i] = c+4;
+ gnuxi8[i+4] = c;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\n[fg]nuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", gnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+int
+find2(long l, int c)
+{
+ short *p;
+ int i;
+
+ p = (short*)&l;
+ for(i=0; i<4; i+=2) {
+ if(((*p >> 8) & 0xff) == c)
+ return i;
+ if((*p++ & 0xff) == c)
+ return i+1;
+ }
+ return 0;
+}
+
+long
+ieeedtof(Ieee *e)
+{
+ int exp;
+ long v;
+
+ if(e->h == 0)
+ return 0;
+ exp = (e->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (e->h & 0xfffffL) << 3;
+ v |= (e->l >> 29) & 0x7L;
+ if((e->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= e->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
diff --git a/utils/1l/optab.c b/utils/1l/optab.c
new file mode 100644
index 00000000..2109b478
--- /dev/null
+++ b/utils/1l/optab.c
@@ -0,0 +1,444 @@
+#include "l.h"
+
+#define X1 0
+#define X2 0
+#define X3 0
+#define C 0xf200
+
+Optab optab[] =
+/* as, fas, srcsp, dstsp, optype, opcode */
+{
+ { AXXX },
+ { AABCD, AXXX, X1, X2, X3, 0x4e71 },
+ { AADDB, AXXX, 2, 0, 3, 0xd000, 0x5000, 0, 0x0600 },
+ { AADDL, AXXX, 4, 0, 3, 0xd080, 0x5080, 0xd1c0, 0x0680 },
+ { AADDW, AXXX, 2, 0, 3, 0xd040, 0x5040, 0xd0c0, 0x0640 },
+ { AADDXB },
+ { AADDXL },
+ { AADDXW },
+ { AADJSP },
+ { AANDB, AXXX, 2, 0, 9, 0xc000, 0xc100, 0x0200 },
+ { AANDL, AXXX, 4, 0, 9, 0xc080, 0xc180, 0x0280 },
+ { AANDW, AXXX, 2, 0, 9, 0xc040, 0xc140, 0x0240 },
+ { AASLB, AXXX, 0, 2, 12, 0xe100 },
+ { AASLL, AXXX, 0, 4, 12, 0xe180 },
+ { AASLW, AXXX, 0, 2, 12, 0xe140 },
+ { AASRB, AXXX, 0, 2, 12, 0xe000 },
+ { AASRL, AXXX, 0, 4, 12, 0xe080 },
+ { AASRW, AXXX, 0, 2, 12, 0xe040 },
+ { ABCASE },
+ { ABCC, AXXX, 0, 0, 1, 0x6400 },
+ { ABCHG, AXXX, 2, 2, 27, 0x0140, 0x0840 },
+ { ABCLR, AXXX, 2, 2, 27, 0x0180, 0x0880 },
+ { ABCS, AXXX, 0, 0, 1, 0x6500 },
+ { ABEQ, AXXX, 0, 0, 1, 0x6700 },
+ { ABFCHG },
+ { ABFCLR },
+ { ABFEXTS },
+ { ABFEXTU },
+ { ABFFFO },
+ { ABFINS },
+ { ABFSET },
+ { ABFTST },
+ { ABGE, AXXX, 0, 0, 1, 0x6c00 },
+ { ABGT, AXXX, 0, 0, 1, 0x6e00 },
+ { ABHI, AXXX, 0, 0, 1, 0x6200 },
+ { ABKPT },
+ { ABLE, AXXX, 0, 0, 1, 0x6f00 },
+ { ABLS, AXXX, 0, 0, 1, 0x6300 },
+ { ABLT, AXXX, 0, 0, 1, 0x6d00 },
+ { ABMI, AXXX, 0, 0, 1, 0x6b00 },
+ { ABNE, AXXX, 0, 0, 1, 0x6600 },
+ { ABPL, AXXX, 0, 0, 1, 0x6a00 },
+ { ABRA, AXXX, 0, 0, 1, 0x6000, 0x4ec0 },
+ { ABSET, AXXX, 2, 2, 27, 0x01c0, 0x08c0 },
+ { ABSR, AXXX, 0, 0, 1, 0x6100, 0x4e80 },
+ { ABTST, AXXX, 2, 2, 27, 0x0100, 0x0800 },
+ { ABVC, AXXX, 0, 0, 1, 0x6800 },
+ { ABVS, AXXX, 0, 0, 1, 0x6900 },
+ { ACALLM },
+ { ACAS2B },
+ { ACAS2L },
+ { ACAS2W },
+ { ACASB },
+ { ACASEW },
+ { ACASL },
+ { ACASW },
+ { ACHK2B },
+ { ACHK2L },
+ { ACHK2W },
+ { ACHKL, AXXX, 4, 4, 26, 0x4100 },
+ { ACHKW, AXXX, 2, 2, 26, 0x4180 },
+ { ACLRB, AXXX, 0, -2, 5, 0x4200 },
+ { ACLRL, AXXX, 0, -4, 5, 0x4280 },
+ { ACLRW, AXXX, 0, -2, 5, 0x4240 },
+ { ACMP2B },
+ { ACMP2L },
+ { ACMP2W },
+ { ACMPB, AXXX, 2, 2, 7, 0xb000, 0, 0x0c00, 0xb108 },
+ { ACMPL, AXXX, 4, 4, 7, 0xb080, 0xb100, 0x0c80, 0xb188 },
+ { ACMPW, AXXX, 2, 2, 7, 0xb040, 0xb080, 0x0c40, 0xb148 },
+ { ADATA },
+ { ADBCC, AXXX, 0, 0, 15, 0x54c8 },
+ { ADBCS, AXXX, 0, 0, 15, 0x55c8 },
+ { ADBEQ, AXXX, 0, 0, 15, 0x57c8 },
+ { ADBF, AXXX, 0, 0, 15, 0x51c8 },
+ { ADBGE, AXXX, 0, 0, 15, 0x5cc8 },
+ { ADBGT, AXXX, 0, 0, 15, 0x5ec8 },
+ { ADBHI, AXXX, 0, 0, 15, 0x52c8 },
+ { ADBLE, AXXX, 0, 0, 15, 0x5fc8 },
+ { ADBLS, AXXX, 0, 0, 15, 0x53c8 },
+ { ADBLT, AXXX, 0, 0, 15, 0x5dc8 },
+ { ADBMI, AXXX, 0, 0, 15, 0x5bc8 },
+ { ADBNE, AXXX, 0, 0, 15, 0x56c8 },
+ { ADBPL, AXXX, 0, 0, 15, 0x5ac8 },
+ { ADBT, AXXX, 0, 0, 15, 0x50c8 },
+ { ADBVC, AXXX, 0, 0, 15, 0x58c8 },
+ { ADBVS, AXXX, 0, 0, 15, 0x59c8 },
+ { ADIVSL, AXXX, 4, 0, 14, 0x4c40, 0x0800 },
+ { ADIVSW, AXXX, 2, 0, 13, 0x81c0 },
+ { ADIVUL, AXXX, 4, 0, 14, 0x4c40, 0x0000 },
+ { ADIVUW, AXXX, 2, 0, 13, 0x80c0 },
+ { AEND },
+ { AEORB, AXXX, 2, 0, 10, 0xb100, 0x0a00 },
+ { AEORL, AXXX, 4, 0, 10, 0xb180, 0x0a80 },
+ { AEORW, AXXX, 2, 0, 10, 0xb140, 0x0a40 },
+ { AEXG },
+ { AEXTBL },
+ { AEXTBW, AXXX, 0, 0, 11, 0x4880 },
+ { AEXTWL, AXXX, 0, 0, 11, 0x48c0 },
+ { AFABSB, AXXX, 2, 0, 17, C, 0x0018, 0x5818 },
+ { AFABSD, AFABSL, 8, 0, 17, C, 0x0018, 0x5418 },
+ { AFABSF, AFABSL, 4, 0, 17, C, 0x0018, 0x4418 },
+ { AFABSL, AXXX, 4, 0, 17, C, 0x0018, 0x4018 },
+ { AFABSW, AXXX, 2, 0, 17, C, 0x0018, 0x5018 },
+ { AFACOSB, AXXX, 2, 0, 17, C, 0x001c, 0x581c },
+ { AFACOSD, AFACOSL, 8, 0, 17, C, 0x001c, 0x541c },
+ { AFACOSF, AFACOSL, 4, 0, 17, C, 0x001c, 0x441c },
+ { AFACOSL, AXXX, 4, 0, 17, C, 0x001c, 0x401c },
+ { AFACOSW, AXXX, 2, 0, 17, C, 0x001c, 0x501c },
+ { AFADDB, AXXX, 2, 0, 17, C, 0x0022, 0x5822 },
+ { AFADDD, AFADDL, 8, 0, 17, C, 0x0022, 0x5422 },
+ { AFADDF, AFADDL, 4, 0, 17, C, 0x0022, 0x4422 },
+ { AFADDL, AXXX, 4, 0, 17, C, 0x0022, 0x4022 },
+ { AFADDW, AXXX, 2, 0, 17, C, 0x0022, 0x5022 },
+ { AFASINB, AXXX, 2, 0, 17, C, 0x000c, 0x580c },
+ { AFASIND, AFASINL, 8, 0, 17, C, 0x000c, 0x540c },
+ { AFASINF, AFASINL, 4, 0, 17, C, 0x000c, 0x440c },
+ { AFASINL, AXXX, 4, 0, 17, C, 0x000c, 0x400c },
+ { AFASINW, AXXX, 2, 0, 17, C, 0x000c, 0x500c },
+ { AFATANB, AXXX, 2, 0, 17, C, 0x000a, 0x580a },
+ { AFATAND, AFATANL, 8, 0, 17, C, 0x000a, 0x540a },
+ { AFATANF, AFATANL, 4, 0, 17, C, 0x000a, 0x440a },
+ { AFATANHB, AXXX, 2, 0, 17, C, 0x000d, 0x580d },
+ { AFATANHD, AFATANHL, 8, 0, 17, C, 0x000d, 0x540d },
+ { AFATANHF, AFATANHL, 4, 0, 17, C, 0x000d, 0x440d },
+ { AFATANHL, AXXX, 4, 0, 17, C, 0x000d, 0x400d },
+ { AFATANHW, AXXX, 2, 0, 17, C, 0x000d, 0x500d },
+ { AFATANL, AXXX, 4, 0, 17, C, 0x000a, 0x400a },
+ { AFATANW, AXXX, 2, 0, 17, C, 0x000a, 0x500a },
+ { AFBEQ, AXXX, 0, 0, 18, C+0x81 },
+ { AFBF, AXXX, 0, 0, 18, C+0x8f },
+ { AFBGE, AXXX, 0, 0, 18, C+0x93 },
+ { AFBGT, AXXX, 0, 0, 18, C+0x92 },
+ { AFBLE, AXXX, 0, 0, 18, C+0x95 },
+ { AFBLT, AXXX, 0, 0, 18, C+0x94 },
+ { AFBNE, AXXX, 0, 0, 18, C+0x8e },
+ { AFBT, AXXX, 0, 0, 18, C+0x80 },
+ { AFCMPB, AXXX, 0, 2, 22, C, 0x0038, 0x5838 },
+ { AFCMPD, AFCMPL, 0, 8, 22, C, 0x0038, 0x5438 },
+ { AFCMPF, AFCMPL, 0, 4, 22, C, 0x0038, 0x4438 },
+ { AFCMPL, AXXX, 0, 4, 22, C, 0x0038, 0x4038 },
+ { AFCMPW, AXXX, 0, 2, 22, C, 0x0038, 0x5038 },
+ { AFCOSB, AXXX, 2, 0, 17, C, 0x001d, 0x581d },
+ { AFCOSD, AFCOSL, 8, 0, 17, C, 0x001d, 0x541d },
+ { AFCOSF, AFCOSL, 4, 0, 17, C, 0x001d, 0x441d },
+ { AFCOSHB, AXXX, 2, 0, 17, C, 0x0019, 0x5819 },
+ { AFCOSHD, AFCOSHL, 8, 0, 17, C, 0x0019, 0x5419 },
+ { AFCOSHF, AFCOSHL, 4, 0, 17, C, 0x0019, 0x4419 },
+ { AFCOSHL, AXXX, 4, 0, 17, C, 0x0019, 0x4019 },
+ { AFCOSHW, AXXX, 2, 0, 17, C, 0x0019, 0x5019 },
+ { AFCOSL, AXXX, 4, 0, 17, C, 0x001d, 0x401d },
+ { AFCOSW, AXXX, 2, 0, 17, C, 0x001d, 0x501d },
+ { AFDBEQ, AXXX, 0, 0, 19, C+0x48, 0x01 },
+ { AFDBF, AXXX, 0, 0, 19, C+0x48, 0x0f },
+ { AFDBGE, AXXX, 0, 0, 19, C+0x48, 0x13 },
+ { AFDBGT, AXXX, 0, 0, 19, C+0x48, 0x12 },
+ { AFDBLE, AXXX, 0, 0, 19, C+0x48, 0x15 },
+ { AFDBLT, AXXX, 0, 0, 19, C+0x48, 0x14 },
+ { AFDBNE, AXXX, 0, 0, 19, C+0x48, 0x0e },
+ { AFDBT, AXXX, 0, 0, 19, C+0x48, 0x00 },
+ { AFDIVB, AXXX, 2, 0, 17, C, 0x0020, 0x5820 },
+ { AFDIVD, AFDIVL, 8, 0, 17, C, 0x0020, 0x5420 },
+ { AFDIVF, AFDIVL, 4, 0, 17, C, 0x0020, 0x4420 },
+ { AFDIVL, AXXX, 4, 0, 17, C, 0x0020, 0x4020 },
+ { AFDIVW, AXXX, 2, 0, 17, C, 0x0020, 0x5020 },
+ { AFETOXB, AXXX, 2, 0, 17, C, 0x0010, 0x5810 },
+ { AFETOXD, AFETOXL, 8, 0, 17, C, 0x0010, 0x5410 },
+ { AFETOXF, AFETOXL, 4, 0, 17, C, 0x0010, 0x4410 },
+ { AFETOXL, AXXX, 4, 0, 17, C, 0x0010, 0x4010 },
+ { AFETOXM1B, AXXX, 2, 0, 17, C, 0x0008, 0x5808 },
+ { AFETOXM1D, AFETOXM1L, 8, 0, 17, C, 0x0008, 0x5408 },
+ { AFETOXM1F, AFETOXM1L, 4, 0, 17, C, 0x0008, 0x4408 },
+ { AFETOXM1L, AXXX, 4, 0, 17, C, 0x0008, 0x4008 },
+ { AFETOXM1W, AXXX, 2, 0, 17, C, 0x0008, 0x5008 },
+ { AFETOXW, AXXX, 2, 0, 17, C, 0x0010, 0x5010 },
+ { AFGETEXPB, AXXX, 2, 0, 17, C, 0x001e, 0x581e },
+ { AFGETEXPD, AFGETEXPL, 8, 0, 17, C, 0x001e, 0x541e },
+ { AFGETEXPF, AFGETEXPL, 4, 0, 17, C, 0x001e, 0x441e },
+ { AFGETEXPL, AXXX, 4, 0, 17, C, 0x001e, 0x401e },
+ { AFGETEXPW, AXXX, 2, 0, 17, C, 0x001e, 0x501e },
+ { AFGETMANB, AXXX, 2, 0, 17, C, 0x001f, 0x581f },
+ { AFGETMAND, AFGETMANL, 8, 0, 17, C, 0x001f, 0x541f },
+ { AFGETMANF, AFGETMANL, 4, 0, 17, C, 0x001f, 0x441f },
+ { AFGETMANL, AXXX, 4, 0, 17, C, 0x001f, 0x401f },
+ { AFGETMANW, AXXX, 2, 0, 17, C, 0x001f, 0x501f },
+ { AFINTB, AXXX, 2, 0, 17, C, 0x0001, 0x5801 },
+ { AFINTD, AFINTL, 8, 0, 17, C, 0x0001, 0x5401 },
+ { AFINTF, AFINTL, 4, 0, 17, C, 0x0001, 0x4401 },
+ { AFINTL, AXXX, 4, 0, 17, C, 0x0001, 0x4001 },
+ { AFINTRZB, AXXX, 2, 0, 17, C, 0x0003, 0x5803 },
+ { AFINTRZD, AFINTRZL, 8, 0, 17, C, 0x0003, 0x5403 },
+ { AFINTRZF, AFINTRZL, 4, 0, 17, C, 0x0003, 0x4403 },
+ { AFINTRZL, AXXX, 4, 0, 17, C, 0x0003, 0x4003 },
+ { AFINTRZW, AXXX, 2, 0, 17, C, 0x0003, 0x5003 },
+ { AFINTW, AXXX, 2, 0, 17, C, 0x0001, 0x5001 },
+ { AFLOG10B, AXXX, 2, 0, 17, C, 0x0015, 0x5815 },
+ { AFLOG10D, AFLOG10L, 8, 0, 17, C, 0x0015, 0x5415 },
+ { AFLOG10F, AFLOG10L, 4, 0, 17, C, 0x0015, 0x4415 },
+ { AFLOG10L, AXXX, 4, 0, 17, C, 0x0015, 0x4015 },
+ { AFLOG10W, AXXX, 2, 0, 17, C, 0x0015, 0x5015 },
+ { AFLOG2B, AXXX, 2, 0, 17, C, 0x0016, 0x5816 },
+ { AFLOG2D, AFLOG2L, 8, 0, 17, C, 0x0016, 0x5416 },
+ { AFLOG2F, AFLOG2L, 4, 0, 17, C, 0x0016, 0x4416 },
+ { AFLOG2L, AXXX, 4, 0, 17, C, 0x0016, 0x4016 },
+ { AFLOG2W, AXXX, 2, 0, 17, C, 0x0016, 0x5016 },
+ { AFLOGNB, AXXX, 2, 0, 17, C, 0x0014, 0x5814 },
+ { AFLOGND, AFLOGNL, 8, 0, 17, C, 0x0014, 0x5414 },
+ { AFLOGNF, AFLOGNL, 4, 0, 17, C, 0x0014, 0x4414 },
+ { AFLOGNL, AXXX, 4, 0, 17, C, 0x0014, 0x4014 },
+ { AFLOGNP1B, AXXX, 2, 0, 17, C, 0x0006, 0x5806 },
+ { AFLOGNP1D, AFLOGNP1L, 8, 0, 17, C, 0x0006, 0x5406 },
+ { AFLOGNP1F, AFLOGNP1L, 4, 0, 17, C, 0x0006, 0x4406 },
+ { AFLOGNP1L, AXXX, 4, 0, 17, C, 0x0006, 0x4006 },
+ { AFLOGNP1W, AXXX, 2, 0, 17, C, 0x0006, 0x5006 },
+ { AFLOGNW, AXXX, 2, 0, 17, C, 0x0014, 0x5014 },
+ { AFMODB, AXXX, 2, 0, 17, C, 0x0021, 0x5821 },
+ { AFMODD, AFMODL, 8, 0, 17, C, 0x0021, 0x5421 },
+ { AFMODF, AFMODL, 4, 0, 17, C, 0x0021, 0x4421 },
+ { AFMODL, AXXX, 4, 0, 17, C, 0x0021, 0x4021 },
+ { AFMODW, AXXX, 2, 0, 17, C, 0x0021, 0x5021 },
+ { AFMOVEB, AXXX, 2, -2, 16, C, 0x0000, 0x7800, 0x5800 },
+ { AFMOVED, AFMOVEL, 8, -8, 16, C, 0x0000, 0x7400, 0x5400 },
+ { AFMOVEF, AFMOVEL, 4, -4, 16, C, 0x0000, 0x6400, 0x4400 },
+ { AFMOVEL, AXXX, 4, -4, 16, C, 0x0000, 0x6000, 0x4000 },
+ { AFMOVEM, AXXX, 2, 2, 28, C },
+ { AFMOVEMC, AXXX, 2, 2, 29, C },
+ { AFMOVEW, AXXX, 2, -2, 16, C, 0x0000, 0x7000, 0x5000 },
+ { AFMULB, AXXX, 2, 0, 17, C, 0x0023, 0x5823 },
+ { AFMULD, AFMULL, 8, 0, 17, C, 0x0023, 0x5423 },
+ { AFMULF, AFMULL, 4, 0, 17, C, 0x0023, 0x4423 },
+ { AFMULL, AXXX, 4, 0, 17, C, 0x0023, 0x4023 },
+ { AFMULW, AXXX, 2, 0, 17, C, 0x0023, 0x5023 },
+ { AFNEGB, AXXX, 2, 0, 21, C, 0x001a, 0x581a },
+ { AFNEGD, AFNEGL, 8, 0, 21, C, 0x001a, 0x541a },
+ { AFNEGF, AFNEGL, 4, 0, 21, C, 0x001a, 0x441a },
+ { AFNEGL, AXXX, 4, 0, 21, C, 0x001a, 0x401a },
+ { AFNEGW, AXXX, 2, 0, 21, C, 0x001a, 0x501a },
+ { AFREMB, AXXX, 2, 0, 17, C, 0x0025, 0x5825 },
+ { AFREMD, AFREML, 8, 0, 17, C, 0x0025, 0x5425 },
+ { AFREMF, AFREML, 4, 0, 17, C, 0x0025, 0x4425 },
+ { AFREML, AXXX, 4, 0, 17, C, 0x0025, 0x4025 },
+ { AFREMW, AXXX, 2, 0, 17, C, 0x0025, 0x5025 },
+ { AFRESTORE, AXXX, 0, 2, 5, C+0x0140 },
+ { AFSAVE, AXXX, 0, 2, 5, C+0x0100 },
+ { AFSCALEB, AXXX, 2, 0, 17, C, 0x0026, 0x5826 },
+ { AFSCALED, AFSCALEL, 8, 0, 17, C, 0x0026, 0x5426 },
+ { AFSCALEF, AFSCALEL, 4, 0, 17, C, 0x0026, 0x4426 },
+ { AFSCALEL, AXXX, 4, 0, 17, C, 0x0026, 0x4026 },
+ { AFSCALEW, AXXX, 2, 0, 17, C, 0x0026, 0x5026 },
+ { AFSEQ, AXXX, X1, X2, X3, 0xffff },
+ { AFSF, AXXX, 4, X2, X3, 0xffff },
+ { AFSGE, AXXX, X1, X2, X3, 0xffff },
+ { AFSGT, AXXX, X1, X2, X3, 0xffff },
+ { AFSINB, AXXX, 2, 0, 17, C, 0x000e, 0x580e },
+ { AFSIND, AFSINL, 8, 0, 17, C, 0x000e, 0x540e },
+ { AFSINF, AFSINL, 4, 0, 17, C, 0x000e, 0x440e },
+ { AFSINHB, AXXX, 2, 0, 17, C, 0x0002, 0x5802 },
+ { AFSINHD, AFSINHL, 8, 0, 17, C, 0x0002, 0x5402 },
+ { AFSINHF, AFSINHL, 4, 0, 17, C, 0x0002, 0x4402 },
+ { AFSINHL, AXXX, 4, 0, 17, C, 0x0002, 0x4002 },
+ { AFSINHW, AXXX, 2, 0, 17, C, 0x0002, 0x5002 },
+ { AFSINL, AXXX, 4, 0, 17, C, 0x000e, 0x400e },
+ { AFSINW, AXXX, 2, 0, 17, C, 0x000e, 0x500e },
+ { AFSLE, AXXX, X1, X2, X3, 0xffff },
+ { AFSLT, AXXX, X1, X2, X3, 0xffff },
+ { AFSNE, AXXX, X1, X2, X3, 0xffff },
+ { AFSQRTB, AXXX, 2, 0, 17, C, 0x0004, 0x5804 },
+ { AFSQRTD, AFSQRTL, 8, 0, 17, C, 0x0004, 0x5404 },
+ { AFSQRTF, AFSQRTL, 4, 0, 17, C, 0x0004, 0x4404 },
+ { AFSQRTL, AXXX, 4, 0, 17, C, 0x0004, 0x4004 },
+ { AFSQRTW, AXXX, 2, 0, 17, C, 0x0004, 0x5004 },
+ { AFST, AXXX, X1, X2, X3, 0xffff },
+ { AFSUBB, AXXX, 2, 0, 17, C, 0x0028, 0x5828 },
+ { AFSUBD, AFSUBL, 8, 0, 17, C, 0x0028, 0x5428 },
+ { AFSUBF, AFSUBL, 4, 0, 17, C, 0x0028, 0x4428 },
+ { AFSUBL, AXXX, 4, 0, 17, C, 0x0028, 0x4028 },
+ { AFSUBW, AXXX, 2, 0, 17, C, 0x0028, 0x5028 },
+ { AFTANB, AXXX, 2, 0, 17, C, 0x000f, 0x580f },
+ { AFTAND, AFTANL, 8, 0, 17, C, 0x000f, 0x540f },
+ { AFTANF, AFTANL, 4, 0, 17, C, 0x000f, 0x440f },
+ { AFTANHB, AXXX, 2, 0, 17, C, 0x0009, 0x5809 },
+ { AFTANHD, AFTANHL, 8, 0, 17, C, 0x0009, 0x5409 },
+ { AFTANHF, AFTANHL, 4, 0, 17, C, 0x0009, 0x4409 },
+ { AFTANHL, AXXX, 4, 0, 17, C, 0x0009, 0x4009 },
+ { AFTANHW, AXXX, 2, 0, 17, C, 0x0009, 0x5009 },
+ { AFTANL, AXXX, 4, 0, 17, C, 0x000f, 0x400f },
+ { AFTANW, AXXX, 2, 0, 17, C, 0x000f, 0x500f },
+ { AFTENTOXB, AXXX, 2, 0, 17, C, 0x0012, 0x5812 },
+ { AFTENTOXD, AFTENTOXL, 8, 0, 17, C, 0x0012, 0x5412 },
+ { AFTENTOXF, AFTENTOXL, 4, 0, 17, C, 0x0012, 0x4412 },
+ { AFTENTOXL, AXXX, 4, 0, 17, C, 0x0012, 0x4012 },
+ { AFTENTOXW, AXXX, 2, 0, 17, C, 0x0012, 0x5012 },
+ { AFTSTB, AXXX, 0, 2, 20, C, 0x003a, 0x583a },
+ { AFTSTD, AFTSTL, 0, 8, 20, C, 0x003a, 0x543a },
+ { AFTSTF, AFTSTL, 0, 4, 20, C, 0x003a, 0x443a },
+ { AFTSTL, AXXX, 0, 4, 20, C, 0x003a, 0x403a },
+ { AFTSTW, AXXX, 0, 2, 20, C, 0x003a, 0x503a },
+ { AFTWOTOXB, AXXX, 2, 0, 17, C, 0x0011, 0x5811 },
+ { AFTWOTOXD, AFTWOTOXL, 8, 0, 17, C, 0x0011, 0x5411 },
+ { AFTWOTOXF, AFTWOTOXL, 4, 0, 17, C, 0x0011, 0x4411 },
+ { AFTWOTOXL, AXXX, 4, 0, 17, C, 0x0011, 0x4011 },
+ { AFTWOTOXW, AXXX, 2, 0, 17, C, 0x0011, 0x5011 },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AILLEG, AXXX, 0, 0, 4, 0x4efc },
+ { AINSTR },
+ { AJMP, AXXX, 0, 0, 5, 0x4ec0 },
+ { AJSR, AXXX, 0, 0, 5, 0x4e80 },
+ { ALEA, AXXX, 0, 0, 6, 0x41c0 },
+ { ALINKL },
+ { ALINKW },
+ { ALOCATE },
+ { ALONG, AXXX, 0, 4, 23 },
+ { ALSLB, AXXX, 0, 2, 12, 0xe108 },
+ { ALSLL, AXXX, 0, 4, 12, 0xe188 },
+ { ALSLW, AXXX, 0, 2, 12, 0xe148 },
+ { ALSRB, AXXX, 0, 2, 12, 0xe008 },
+ { ALSRL, AXXX, 0, 4, 12, 0xe088 },
+ { ALSRW, AXXX, 0, 2, 12, 0xe048 },
+ { AMOVB, AXXX, 2, -2, 2, 0x1000, 0x7000 },
+ { AMOVEM, AXXX, 2, 2, 25, 0x48c0 },
+ { AMOVEPL },
+ { AMOVEPW },
+ { AMOVESB },
+ { AMOVESL },
+ { AMOVESW, },
+ { AMOVL, AXXX, 4, -4, 2, 0x2000, 0x7000 },
+ { AMOVW, AXXX, 2, -2, 2, 0x3000, 0x7000 },
+ { AMULSL, AXXX, 4, 0, 14, 0x4c00, 0x0800 },
+ { AMULSW, AXXX, 2, 0, 13, 0xc1c0 },
+ { AMULUL, AXXX, 4, 0, 14, 0x4c00, 0x0000 },
+ { AMULUW, AXXX, 2, 0, 13, 0xc0c0 },
+ { ANAME },
+ { ANBCD },
+ { ANEGB, AXXX, 0, 0, 5, 0x4400 },
+ { ANEGL, AXXX, 0, 0, 5, 0x4480 },
+ { ANEGW, AXXX, 0, 0, 5, 0x4440 },
+ { ANEGXB },
+ { ANEGXL },
+ { ANEGXW },
+ { ANOP },
+ { ANOTB, AXXX, 0, 0, 5, 0x4600 },
+ { ANOTL, AXXX, 0, 0, 5, 0x4680 },
+ { ANOTW, AXXX, 0, 0, 5, 0x4640 },
+ { AORB, AXXX, 2, 0, 9, 0x8000, 0x8100, 0x0000 },
+ { AORL, AXXX, 4, 0, 9, 0x8080, 0x8180, 0x0080 },
+ { AORW, AXXX, 2, 0, 9, 0x8040, 0x8140, 0x0040 },
+ { APACK },
+ { APEA, AXXX, 0, 0, 5, 0x4840 },
+ { ARESET },
+ { AROTLB, AXXX, 0, 2, 12, 0xe118 },
+ { AROTLL, AXXX, 0, 4, 12, 0xe198 },
+ { AROTLW, AXXX, 0, 2, 12, 0xe158 },
+ { AROTRB, AXXX, 0, 2, 12, 0xe018 },
+ { AROTRL, AXXX, 0, 4, 12, 0xe098 },
+ { AROTRW, AXXX, 0, 2, 12, 0xe058 },
+ { AROXLB },
+ { AROXLL },
+ { AROXLW },
+ { AROXRB },
+ { AROXRL },
+ { AROXRW },
+ { ARTD },
+ { ARTE, AXXX, 0, 0, 4, 0x4e73 },
+ { ARTM },
+ { ARTR },
+ { ARTS, AXXX, 0, 0, 4, 0x4e75 },
+ { ASBCD },
+ { ASCC },
+ { ASCS },
+ { ASEQ },
+ { ASF },
+ { ASGE },
+ { ASGT },
+ { ASHI },
+ { ASLE },
+ { ASLS },
+ { ASLT },
+ { ASMI },
+ { ASNE },
+ { ASPL },
+ { AST },
+ { ASTOP },
+ { ASUBB, AXXX, 2, 0, 3, 0x9000, 0x5100, 0, 0x0400 },
+ { ASUBL, AXXX, 4, 0, 3, 0x9080, 0x5180, 0x91c0, 0x0480 },
+ { ASUBW, AXXX, 2, 0, 3, 0x9040, 0x5140, 0x90c0, 0x0440 },
+ { ASUBXB },
+ { ASUBXL },
+ { ASUBXW },
+ { ASVC },
+ { ASVS },
+ { ASWAP, AXXX, 0, 0, 35, 0x4840 },
+ { ASYS, AXXX, 0, 2, 8, 0x4e40 },
+ { ATAS, AXXX, 0, 2, 5, 0x4ac0 },
+ { ATEXT },
+ { ATRAP, AXXX, 0, 0, 30, 0x4e40 },
+ { ATRAPCC },
+ { ATRAPCS },
+ { ATRAPEQ },
+ { ATRAPF },
+ { ATRAPGE },
+ { ATRAPGT },
+ { ATRAPHI },
+ { ATRAPLE },
+ { ATRAPLS },
+ { ATRAPLT },
+ { ATRAPMI },
+ { ATRAPNE },
+ { ATRAPPL },
+ { ATRAPT },
+ { ATRAPV },
+ { ATRAPVC },
+ { ATRAPVS },
+ { ATSTB, AXXX, 0, 2, 5, 0x4a00 },
+ { ATSTL, AXXX, 0, 4, 5, 0x4a80 },
+ { ATSTW, AXXX, 0, 2, 5, 0x4a40 },
+ { AUNLK },
+ { AUNPK },
+ { AWORD, AXXX, 0, 2, 23 },
+ { AXXX }
+};
+
+char mmsize[] =
+{
+ /* 0 */ 0, 2, 2, 2, 2,
+ /* 5 */ 2, 2, 2, 4, 2,
+ /* 10 */ 2, 2, 2, 2, 4,
+ /* 15 */ 4, 4, 4, 4, 6,
+ /* 20 */ 4, 4, 4, 0, 4,
+ /* 25 */ 2, 2, 2, 2, 2,
+ /* 30 */ 2, 4, 4, 0, 4,
+ /* 35 */ 2, 0, 0, 0, 0,
+};
diff --git a/utils/1l/pass.c b/utils/1l/pass.c
new file mode 100644
index 00000000..9ab22626
--- /dev/null
+++ b/utils/1l/pass.c
@@ -0,0 +1,673 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i;
+ Sym *s;
+ Prog *p;
+ long t, u;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ t = p->from.offset + p->from.displace;
+ if(t > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ /* allocate small guys */
+ datsize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA)
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t == 0) {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ t = rnd(t, 4);;
+ s->value = t;
+ if(t > MINSIZ)
+ continue;
+ s->value = datsize;
+ datsize += t;
+ s->type = SDATA1;
+ }
+
+ /* allocate the rest of the data */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA) {
+ if(s->type == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ t = s->value;
+ s->value = datsize;
+ datsize += t;
+ }
+
+ if(debug['j']) {
+ /*
+ * pad data with bss that fits up to next
+ * 8k boundary, then push data to 8k
+ */
+ u = rnd(datsize, 8192);
+ u -= datsize;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t > u)
+ continue;
+ u -= t;
+ s->value = datsize;
+ s->type = SDATA;
+ datsize += t;
+ }
+ datsize += u;
+ }
+
+ /* now the bss */
+ bsssize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ s->value = bsssize + datsize;
+ bsssize += t;
+ }
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+}
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != ABRA)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+ Prog *p;
+ long o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+ lastp->link = P;
+ firstp = firstp->link;
+ o = 0; /* set */
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+
+ p->stkoff = -1; /* initialization for stkoff */
+ if(p->as == ATEXT) {
+ p->stkoff = 0;
+ o = p->to.offset;
+ continue;
+ }
+ if(p->as == AADJSP && p->from.offset == 0) {
+ p->stkoff = o;
+ continue;
+ }
+ }
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == ABRA)
+ if((q = p->pcond) != P) {
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /* copy up to 4 instructions to avoid branch */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == P)
+ break;
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == ABRA || a == ARTS || a == ARTE)
+ break;
+ if(q->pcond == P || q->pcond->mark)
+ continue;
+ if(a == ABSR || a == ADBF)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ lastp->link = q;
+ lastp = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = prg();
+ q->as = ABRA;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark = 1;
+ lastp->link = p;
+ lastp = p;
+ a = p->as;
+ if(a == ARTS || a == ABRA || a == ARTE)
+ return;
+ if(p->pcond != P)
+ if(a != ABSR) {
+ q = brchain(p->link);
+ if(q != P && q->mark)
+ if(a != ADBF) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABLE: return ABGT;
+ case ABLS: return ABHI;
+ case ABLT: return ABGE;
+ case ABMI: return ABPL;
+ case ABGE: return ABLT;
+ case ABPL: return ABMI;
+ case ABGT: return ABLE;
+ case ABHI: return ABLS;
+ case ABCS: return ABCC;
+ case ABCC: return ABCS;
+ case AFBEQ: return AFBNE;
+ case AFBF: return AFBT;
+ case AFBGE: return AFBLT;
+ case AFBGT: return AFBLE;
+ case AFBLE: return AFBGT;
+ case AFBLT: return AFBGE;
+ case AFBNE: return AFBEQ;
+ case AFBT: return AFBF;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ return a;
+}
+
+void
+patch(void)
+{
+ long c;
+ Prog *p, *q;
+ Sym *s;
+ long vexit;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if((p->as == ABSR || p->as == ARTS) && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s in %s", s->name, TNAME);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range in %s\n%P", TNAME, p);
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ long dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != ABRA)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+void
+dostkoff(void)
+{
+ Prog *p, *q, *qq;
+ long s, t;
+ int a;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f stkoff\n", cputime());
+ Bflush(&bso);
+ s = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ s = p->to.offset;
+ if(s == 0)
+ continue;
+ p = nprg(p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = s;
+ p->stkoff = 0;
+ continue;
+ }
+ t = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as == ATEXT)
+ break;
+ if(q->stkoff >= 0)
+ if(q->stkoff != s)
+ diag("stack offset %ld is %ld sb %ld in %s\n%P",
+ q->pc, q->stkoff, s, q, TNAME, p);
+ q->stkoff = s;
+ if(t++ > 100) {
+ diag("loop in stack offset 1: %P", p);
+ break;
+ }
+ }
+ o = &optab[p->as];
+ if(p->to.type == D_TOS)
+ s -= o->dstsp;
+ if(p->from.type == D_TOS)
+ s -= o->srcsp;
+ if(p->as == AADJSP)
+ s += p->from.offset;
+ if(p->as == APEA)
+ s += 4;
+ t = 0;
+ for(q = p->link; q != P; q = q->pcond) {
+ if(q->as == ATEXT) {
+ q = P;
+ break;
+ }
+ if(q->stkoff >= 0)
+ break;
+ if(t++ > 100) {
+ diag("loop in stack offset 2: %P", p);
+ break;
+ }
+ }
+ if(q == P || q->stkoff == s)
+ continue;
+ if(p->as == ABRA || p->as == ARTS || p->as == ARTE) {
+ s = q->stkoff;
+ continue;
+ }
+ t = q->stkoff - s;
+ s = q->stkoff;
+ p = nprg(p);
+ p->as = AADJSP;
+ p->stkoff = s - t;
+ p->from.type = D_CONST;
+ p->from.offset = t;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f rewrite\n", cputime());
+ Bflush(&bso);
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ a = p->from.type & D_MASK;
+ if(a == D_AUTO)
+ p->from.offset += p->stkoff;
+ if(a == D_PARAM)
+ p->from.offset += p->stkoff + 4;
+ a = p->to.type & D_MASK;
+ if(a == D_AUTO)
+ p->to.offset += p->stkoff;
+ if(a == D_PARAM)
+ p->to.offset += p->stkoff + 4;
+ switch(p->as) {
+ default:
+ continue;
+
+ case AMOVW:
+ if(p->from.type != D_CCR)
+ continue;
+ a = p->to.type;
+ if((a < D_R0 || a > D_R0+7) && a != D_TOS)
+ diag("bad dest for MOVCC %P", p);
+ p->as = ALEA;
+ p->from.type = I_INDIR|(D_A0+7);
+ p->from.offset = -2;
+ p->to.type = D_A0+7;
+
+ p = nprg(p);
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = prog_ccr;
+ p->to.sym = prog_ccr->from.sym;
+
+ if(a != D_TOS) {
+ p = nprg(p);
+ p->as = AMOVW;
+ p->from.type = D_TOS;
+ p->to.type = a;
+ }
+ continue;
+
+ case AEXTBL:
+ a = p->to.type;
+ if(a < D_R0 || a > D_R0+7)
+ diag("bad dest for EXTB");
+ p->as = AEXTBW;
+
+ p = nprg(p);
+ p->as = AEXTWL;
+ p->to.type = a;
+ continue;
+
+ case AMULSL:
+ case AMULUL:
+ qq = prog_mull;
+ goto mdcom;
+ case ADIVSL:
+ qq = prog_divsl;
+ goto mdcom;
+ case ADIVUL:
+ qq = prog_divul;
+ mdcom:
+ if(debug['m'])
+ continue;
+ a = p->to.type;
+ if(a < D_R0 || a > D_R0+7)
+ diag("bad dest for mul/div");
+ p->as = AMOVL;
+ p->to.type = D_TOS;
+
+ p = nprg(p);
+ p->as = AMOVL;
+ p->from.type = a;
+ p->to.type = D_TOS;
+
+ p = nprg(p);
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = qq;
+ p->to.sym = qq->from.sym;
+
+ p = nprg(p);
+ p->as = AMOVL;
+ p->from.type = D_TOS;
+ p->to.type = a;
+
+ p = nprg(p);
+ p->as = AMOVL;
+ p->from.type = D_TOS;
+ p->to.type = a+1;
+ if(qq == prog_mull)
+ p->to.type = a;
+ continue;
+
+ case ARTS:
+ break;
+ }
+ if(p->stkoff == 0)
+ continue;
+
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -p->stkoff;
+
+ p = nprg(p);
+ p->as = ARTS;
+ p->stkoff = 0;
+ }
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+void
+initmuldiv1(void)
+{
+ lookup("_mull", 0)->type = SXREF;
+ lookup("_divsl", 0)->type = SXREF;
+ lookup("_divul", 0)->type = SXREF;
+ lookup("_ccr", 0)->type = SXREF;
+}
+
+void
+initmuldiv2(void)
+{
+ Sym *s1, *s2, *s3, *s4;
+ Prog *p;
+
+ if(prog_mull != P)
+ return;
+ s1 = lookup("_mull", 0);
+ s2 = lookup("_divsl", 0);
+ s3 = lookup("_divul", 0);
+ s4 = lookup("_ccr", 0);
+ for(p = firstp; p != P; p = p->link)
+ if(p->as == ATEXT) {
+ if(p->from.sym == s1)
+ prog_mull = p;
+ if(p->from.sym == s2)
+ prog_divsl = p;
+ if(p->from.sym == s3)
+ prog_divul = p;
+ if(p->from.sym == s4)
+ prog_ccr = p;
+ }
+ if(prog_mull == P) {
+ diag("undefined: %s", s1->name);
+ prog_mull = curtext;
+ }
+ if(prog_divsl == P) {
+ diag("undefined: %s", s2->name);
+ prog_divsl = curtext;
+ }
+ if(prog_divul == P) {
+ diag("undefined: %s", s3->name);
+ prog_divul = curtext;
+ }
+ if(prog_ccr == P) {
+ diag("undefined: %s", s4->name);
+ prog_ccr = curtext;
+ }
+}
diff --git a/utils/1l/span.c b/utils/1l/span.c
new file mode 100644
index 00000000..d8baa362
--- /dev/null
+++ b/utils/1l/span.c
@@ -0,0 +1,515 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ long v, c, idat;
+ Optab *o;
+ int m, n;
+
+ xdefine("etext", STEXT, 0L);
+ xdefine("a6base", STEXT, 0L);
+ idat = INITDAT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ n = 0;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_A0+7;
+ v = -p->from.offset;
+ p->from.offset = v;
+ if((v < -8 && v >= -32768L) || (v > 8 && v < 32768L)) {
+ p->as = ALEA;
+ p->from.type = I_INDIR | (D_A0+7);
+ continue;
+ }
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v >= 0 && v <= 8)
+ p->from.type = D_QUICK;
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+ n = 0;
+
+start:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ o = &optab[p->as];
+ p->pc = c;
+ m = mmsize[o->optype];
+ if(m == 0) {
+ if(p->as == AWORD)
+ m = 2;
+ if(p->as == ALONG)
+ m = 4;
+ p->mark = m;
+ c += m;
+ continue;
+ }
+ if(p->from.type != D_NONE)
+ m += andsize(p, &p->from);
+ if(p->to.type == D_BRANCH) {
+ if(p->pcond == P)
+ p->pcond = p;
+ c += m;
+ if(m == 2)
+ m |= 0100;
+ p->mark = m;
+ continue;
+ }
+ if(p->to.type != D_NONE)
+ m += andsize(p, &p->to);
+ p->mark = m;
+ c += m;
+ }
+
+loop:
+ n++;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span %d\n", cputime(), n);
+ Bflush(&bso);
+ if(n > 60) {
+ diag("span must be looping");
+ errorexit();
+ }
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if((m = p->mark) & 0100) {
+ q = p->pcond;
+ v = q->pc - 2;
+ if(p->back)
+ v -= c;
+ else
+ v -= p->pc;
+ p->pc = c;
+ if(v < -32768L || v >= 32768L) {
+ c += 6; /* only jsr and jmp can do this */
+ } else
+ if(v < -128 || v >= 128)
+ c += 4;
+ else
+ if(v == 0) {
+ c += 4;
+ p->mark = 4;
+ } else
+ c += 2;
+ continue;
+ }
+ p->pc = c;
+ c += m;
+ }
+ if(c != textsize) {
+ textsize = c;
+ goto loop;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(INITDAT != idat) {
+ idat = INITDAT;
+ goto start;
+ }
+ xdefine("etext", STEXT, c);
+ xdefine("a6base", STEXT, INITDAT+A6OFFSET);
+ if(debug['v'])
+ Bprint(&bso, "etext = %lux\n", c);
+ Bflush(&bso);
+ for(p = textp; p != P; p = p->pcond)
+ p->from.sym->value = p->pc;
+ textsize = c - INITTEXT;
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+ if(s->type == STEXT && s->value == 0)
+ s->value = v;
+}
+
+int
+andsize(Prog *p, Adr *ap)
+{
+ int t, n;
+ long v;
+ Optab *o;
+
+ t = ap->type;
+ n = simple[t];
+ if(n != 0177) {
+ v = ap->offset;
+ if(v == 0)
+ return 0;
+ if((n&070) != 020) /* D_INDIR */
+ return 0;
+ if(v == 0)
+ return 0;
+ return 2;
+ }
+ if((t&I_MASK) == I_ADDR)
+ t = D_CONST;
+ switch(t) {
+
+ default:
+ return 0;
+
+ case D_STACK:
+ case D_AUTO:
+ case D_PARAM:
+ v = ap->offset;
+ if(v == 0)
+ return 0;
+ return 2;
+
+ case I_INDIR|D_CONST:
+ v = ap->offset;
+ if(v < -32768L || v >= 32768L)
+ return 4;
+ return 2;
+
+ case D_STATIC:
+ case D_EXTERN:
+ if(ap->sym->type == STEXT) {
+ if(HEADTYPE == 4)
+ return 2;
+ return 4;
+ }
+ v = ap->sym->value + ap->offset - A6OFFSET;
+ if(v == 0)
+ return 0;
+ if(v < -32768L || v >= 32768L)
+ return 4;
+ return 2;
+
+ case D_CONST:
+ case D_FCONST:
+ o = &optab[p->as];
+ if(ap == &(p->from))
+ return o->srcsp;
+ return o->dstsp;
+
+ case D_CCR:
+ case D_SR:
+ if(p->as == AMOVW)
+ return 0;
+ return 2;
+
+ case D_USP:
+ t = p->from.type;
+ if(t >= D_A0 && t <= D_A0+8)
+ return 0;
+ t = p->to.type;
+ if(t >= D_A0 && t <= D_A0+8)
+ return 0;
+
+ case D_SFC:
+ case D_DFC:
+ case D_CACR:
+ case D_VBR:
+ case D_CAAR:
+ case D_MSP:
+ case D_ISP:
+ case D_FPCR:
+ case D_FPSR:
+ case D_FPIAR:
+ case D_TC:
+ case D_ITT0:
+ case D_ITT1:
+ case D_DTT0:
+ case D_DTT1:
+ case D_MMUSR:
+ case D_URP:
+ case D_SRP:
+ return 2;
+ }
+}
+
+void
+putsymb(Sym *s, int t, long v)
+{
+ int i, f;
+ char *n;
+
+ n = s->name;
+ if(t == 'f')
+ n++;
+ lput(v);
+ if(s->version)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(n[0]);
+ for(i=1; n[i] != 0 || n[i+1] != 0; i += 2) {
+ CPUT(n[i]);
+ CPUT(n[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; n[i]; i++)
+ CPUT(n[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; n[i] != 0 || n[i+1] != 0; i+=2) {
+ f = ((n[i]&0xff) << 8) | (n[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(s->version)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, n, s->version);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, n);
+ }
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s, 'T', s->value);
+ s = lookup("a6base", 0);
+ if(s->type == STEXT)
+ putsymb(s, 'D', s->value);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SDATA:
+ putsymb(s, 'D', s->value+INITDAT);
+ continue;
+
+ case SBSS:
+ putsymb(s, 'B', s->value+INITDAT);
+ continue;
+
+ case SFILE:
+ putsymb(s, 'f', s->value);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->pcond) {
+ s = p->from.sym;
+ if(s->type != STEXT)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym, 'z', a->aoffset);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym, 'Z', a->aoffset);
+
+ putsymb(s, 'T', s->value);
+
+ /* auto and param after */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym, 'a', -a->aoffset);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym, 'p', a->aoffset);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+#define MINLC 2
+void
+asmsp(void)
+{
+ long oldpc, oldsp;
+ Prog *p;
+ int s;
+ long v;
+
+ oldpc = INITTEXT;
+ oldsp = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->stkoff == oldsp || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['G'])
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ continue;
+ }
+ if(debug['G'])
+ Bprint(&bso, "\t\t%6ld", spsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['G'])
+ Bprint(&bso, " pc+%d*2(%d)", s, s+128);
+ v -= s;
+ spsize++;
+ }
+ v = p->stkoff - oldsp;
+ oldsp = p->stkoff;
+ oldpc = p->pc + MINLC;
+ if(v & 3 || v > 64L*4L || v < -64L*4L) {
+ CPUT(0); /* 0 vvvv +sp */
+ lput(v);
+ if(debug['G']) {
+ if(v > 0)
+ Bprint(&bso, " sp+%ld*1(%d,%ld)\n",
+ v, 0, v);
+ else
+ Bprint(&bso, " sp%ld*1(%d,%ld)\n",
+ v, 0, v);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ spsize += 5;
+ continue;
+ }
+ s = v/4;
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +sp */
+ if(debug['G']) {
+ Bprint(&bso, " sp+%d*4(%d)\n", s, 0+s);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -sp */
+ if(debug['G']) {
+ Bprint(&bso, " sp%d*4(%d)\n", s, 64-s);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ }
+ spsize++;
+ }
+ while(spsize & 1) {
+ s = 129;
+ CPUT(s);
+ spsize++;
+ }
+ if(debug['v'] || debug['G'])
+ Bprint(&bso, "stsize = %ld\n", spsize);
+ Bflush(&bso);
+}
+
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
diff --git a/utils/2a/a.h b/utils/2a/a.h
new file mode 100644
index 00000000..7f9987b0
--- /dev/null
+++ b/utils/2a/a.h
@@ -0,0 +1,200 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../2c/2.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Ref Ref;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Addr Addr;
+typedef struct Gen2 Gen2;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ Ref* ref;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct Ref
+{
+ int class;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Addr
+{
+ Sym* sym;
+ long offset;
+ short type;
+};
+struct Gen
+{
+ Addr s0;
+ double dval;
+ char sval[8];
+ long displace;
+ short type;
+ short index;
+ short scale;
+ short field;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen2*);
+void outhist(void);
+void zaddr(Gen*, int);
+void zname(char*, int, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/2a/a.y b/utils/2a/a.y
new file mode 100644
index 00000000..2a5d5c96
--- /dev/null
+++ b/utils/2a/a.y
@@ -0,0 +1,540 @@
+%{
+#include "a.h"
+%}
+%union {
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Addr addr;
+ Gen gen;
+ Gen2 gen2;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA LTYPEB
+%token <lval> LCONST LSP LSB LFP LPC LTOS LAREG LDREG LFREG LWID
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr scale type pointer reg offset
+%type <addr> name areg xreg
+%type <gen> gen rel
+%type <gen2> noaddr gengen dstgen spec1 spec2 spec3 srcgen dstrel genrel
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+ LNAME '=' expr
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LTYPE1 gengen { outcode($1, &$2); }
+| LTYPE2 noaddr { outcode($1, &$2); }
+| LTYPE3 dstgen { outcode($1, &$2); }
+| LTYPE4 spec1 { outcode($1, &$2); }
+| LTYPE5 srcgen { outcode($1, &$2); }
+| LTYPE6 dstrel { outcode($1, &$2); }
+| LTYPE7 genrel { outcode($1, &$2); }
+| LTYPE8 dstgen { outcode($1, &$2); }
+| LTYPE8 gengen { outcode($1, &$2); }
+| LTYPE9 noaddr { outcode($1, &$2); }
+| LTYPE9 dstgen { outcode($1, &$2); }
+| LTYPEA spec2 { outcode($1, &$2); }
+| LTYPEB spec3 { outcode($1, &$2); }
+
+noaddr:
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| ','
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+
+srcgen:
+ gen
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| gen ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+dstgen:
+ gen
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+| ',' gen
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+
+gengen:
+ gen ',' gen
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+dstrel:
+ rel
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+| ',' rel
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+
+genrel:
+ gen ',' rel
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec1: /* DATA opcode */
+ gen '/' con ',' gen
+ {
+ $1.displace = $3;
+ $$.from = $1;
+ $$.to = $5;
+ }
+
+spec2: /* bit field opcodes */
+ gen ',' gen ',' con ',' con
+ {
+ $1.field = $7;
+ $3.field = $5;
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+spec3: /* TEXT opcode */
+ gengen
+| gen ',' con ',' gen
+ {
+ $1.displace = $3;
+ $$.from = $1;
+ $$.to = $5;
+ }
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.s0.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.s0.sym = $1;
+ $$.s0.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.s0.sym = $1;
+ $$.s0.offset = $1->value + $2;
+ }
+
+gen:
+ type
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.s0.offset = $2;
+ }
+| '$' name
+ {
+ $$ = nullgen;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $2;
+ }
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ $$.type = $2.type | I_ADDR;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+| LTOS '+' con
+ {
+ $$ = nullgen;
+ $$.type = D_STACK;
+ $$.s0.offset = $3;
+ }
+| LTOS '-' con
+ {
+ $$ = nullgen;
+ $$.type = D_STACK;
+ $$.s0.offset = -$3;
+ }
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST | I_INDIR;
+ $$.s0.offset = $1;
+ }
+| '-' '(' LAREG ')'
+ {
+ $$ = nullgen;
+ $$.type = $3 | I_INDDEC;
+ }
+| '(' LAREG ')' '+'
+ {
+ $$ = nullgen;
+ $$.type = $2 | I_INDINC;
+ }
+| areg
+ {
+ $$ = nullgen;
+ $$.type = $1.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $1;
+ }
+ if(($$.type & D_MASK) == D_NONE) {
+ $$.index = D_NONE | I_INDEX1;
+ $$.scale = 0;
+ $$.displace = 0;
+ }
+ }
+| areg xreg
+ {
+ $$ = nullgen;
+ $$.type = $1.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $1;
+ }
+ $$.index = $2.type | I_INDEX1;
+ $$.scale = $2.offset;
+ }
+| '(' areg ')' xreg
+ {
+ $$ = nullgen;
+ $$.type = $2.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $2;
+ }
+ $$.index = $4.type | I_INDEX2;
+ $$.scale = $4.offset;
+ $$.displace = 0;
+ }
+| con '(' areg ')' xreg
+ {
+ $$ = nullgen;
+ $$.type = $3.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $3;
+ }
+ $$.index = $5.type | I_INDEX2;
+ $$.scale = $5.offset;
+ $$.displace = $1;
+ }
+| '(' areg ')'
+ {
+ $$ = nullgen;
+ $$.type = $2.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $2;
+ }
+ $$.index = D_NONE | I_INDEX3;
+ $$.scale = 0;
+ $$.displace = 0;
+ }
+| con '(' areg ')'
+ {
+ $$ = nullgen;
+ $$.type = $3.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $3;
+ }
+ $$.index = D_NONE | I_INDEX3;
+ $$.scale = 0;
+ $$.displace = $1;
+ }
+| '(' areg xreg ')'
+ {
+ $$ = nullgen;
+ $$.type = $2.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $2;
+ }
+ $$.index = $3.type | I_INDEX3;
+ $$.scale = $3.offset;
+ $$.displace = 0;
+ }
+| con '(' areg xreg ')'
+ {
+ $$ = nullgen;
+ $$.type = $3.type;
+ {
+ Addr *a;
+ a = &$$.s0;
+ *a = $3;
+ }
+ $$.index = $4.type | I_INDEX3;
+ $$.scale = $4.offset;
+ $$.displace = $1;
+ }
+
+type:
+ reg
+| LFREG
+
+xreg:
+ /*
+ * .W*1 0
+ * .W*2 1
+ * .W*4 2
+ * .W*8 3
+ * .L*1 4
+ * .L*2 5
+ * .L*4 6
+ * .L*8 7
+ */
+ '(' reg LWID scale ')'
+ {
+ $$.type = $2;
+ $$.offset = $3+$4;
+ $$.sym = S;
+ }
+
+reg:
+ LAREG
+| LDREG
+| LTOS
+
+scale:
+ '*' con
+ {
+ switch($2) {
+ case 1:
+ $$ = 0;
+ break;
+
+ case 2:
+ $$ = 1;
+ break;
+
+ default:
+ yyerror("bad scale: %ld", $2);
+
+ case 4:
+ $$ = 2;
+ break;
+
+ case 8:
+ $$ = 3;
+ break;
+ }
+ }
+
+areg:
+ '(' LAREG ')'
+ {
+ $$.type = $2 | I_INDIR;
+ $$.sym = S;
+ $$.offset = 0;
+ }
+| con '(' LAREG ')'
+ {
+ $$.type = $3 | I_INDIR;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| '(' ')'
+ {
+ $$.type = D_NONE | I_INDIR;
+ $$.sym = S;
+ $$.offset = 0;
+ }
+| con '(' ')'
+ {
+ $$.type = D_NONE | I_INDIR;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| name
+
+name:
+ LNAME offset '(' pointer ')'
+ {
+ $$.type = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$.type = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/2a/l.s b/utils/2a/l.s
new file mode 100644
index 00000000..6f3cca3a
--- /dev/null
+++ b/utils/2a/l.s
@@ -0,0 +1,479 @@
+
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 8192 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 13 /* log(BY2PG) */
+#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
+#define ICACHESIZE 0
+#define MB4 (4*1024*1024) /* Lots of things are 4Mb in size */
+
+#define MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ (60) /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+
+/*
+ * SR bits
+ */
+#define SUPER 0x2000
+#define SPL(n) (n<<8)
+
+/*
+ * CACR
+ */
+#define CCLEAR 0x08
+#define CENABLE 0x01
+
+/*
+ * Magic registers (unused in current system)
+ */
+
+#define MACH A5 /* A5 is m-> */
+#define USER A4 /* A4 is u-> */
+
+/*
+ * Fundamental addresses
+ */
+
+#define USERADDR 0x80000000
+/* assuming we're in a syscall, this is the address of the Ureg structure */
+#define UREGVARSZ (23*BY2WD) /* size of variable part of Ureg */
+#define UREGADDR (USERADDR+BY2PG-(UREGVARSZ+2+4+2+(8+8+1+1)*BY2WD))
+
+/*
+ * Devices poked during bootstrap
+ */
+#define TACADDR 0x40600000
+#define MOUSE 0x40200000
+
+/*
+ * MMU
+ */
+
+#define VAMASK 0xCFFFFFFF /* clear balu bits in address */
+#define KUSEG 0x00000000
+#define KSEG 0x80000000
+
+/*
+ * MMU entries
+ */
+#define PTEVALID (1<<13)
+#define PTEWRITE 0
+#define PTERONLY (1<<14)
+#define PTEKERNEL (1<<15)
+#define PTEUNCACHED 0
+#define INVALIDPTE 0
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 16
+
+#define PPN(pa) ((pa>>13)&0x1FFF)
+
+#define KMAP ((unsigned long *)0xD0000000)
+#define UMAP ((unsigned long *)0x50000000)
+
+/*
+ * Virtual addresses
+ */
+#define VTAG(va) ((va>>22)&0x03F)
+#define VPN(va) ((va>>13)&0x1FF)
+
+#define PARAM ((char*)0x40500000)
+#define TLBFLUSH_ 0x01
+
+/*
+ * Address spaces
+ */
+
+#define UZERO KUSEG /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define TSTKTOP 0x10000000 /* end of new stack in sysexec */
+#define TSTKSIZ 100
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define KZERO KSEG /* base of kernel address space */
+#define KTZERO (KZERO+BY2PG) /* first address in kernel text */
+#define USTKSIZE (4*1024*1024) /* size of user stack */
+
+#define MACHSIZE 4096
+
+
+#define isphys(p) ((((ulong)(p))&0xF0000000) == KSEG)
+#define DBMAGIC 0xBADC0C0A
+
+/*
+ * Boot first processor
+ */
+TEXT start(SB), $-4
+
+ MOVW $(SUPER|SPL(7)), SR
+ MOVL $a6base(SB), A6
+ MOVL $0, R0
+ MOVL R0, CACR
+ MOVL R0, TACADDR /* zero tac counter (cause an intr?) */
+
+ MOVL $mach0(SB), A0
+ MOVL A0, m(SB)
+ MOVL $0, 0(A0)
+ MOVL A0, A7
+ ADDL $(MACHSIZE-4), A7 /* start stack under machine struct */
+ MOVL $0, u(SB)
+
+ MOVL $vectors(SB), A0
+ MOVL A0, VBR
+
+ BSR main(SB)
+ /* never returns */
+dead:
+ BRA dead
+
+/*
+ * Take first processor into user mode. Leave enough room on the stack
+ * for a full-sized Ureg (including long bus error format) to fit
+ */
+
+TEXT touser(SB), $-4
+
+ MOVL $(USERADDR+BY2PG-UREGVARSZ), A7
+ MOVW $0, -(A7)
+ MOVL $(UTZERO+32), -(A7) /* header is in text */
+ MOVW $0, -(A7)
+ MOVL $(USTKTOP-6*BY2WD), A0 /* MAXSYSARG=6 */
+ MOVL A0, USP
+ MOVW $(SUPER|SPL(0)), SR
+ MOVL $8, R0
+ MOVL R0, CACR
+ RTE
+
+TEXT firmware(SB), $0
+
+ MOVL $0x40000090, A0
+ JMP (A0)
+
+TEXT splhi(SB), $0
+
+ MOVL m(SB), A0
+ MOVL (A7), 4(A0)
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(7)), SR
+ RTS
+
+TEXT splduart(SB), $0
+
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(5)), SR
+ RTS
+
+TEXT spllo(SB), $0
+
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(0)), SR
+ RTS
+
+TEXT splx(SB), $0
+
+ MOVL sr+0(FP), R0
+ MOVW R0, SR
+ RTS
+
+TEXT spldone(SB), $0
+
+ RTS
+
+TEXT spl1(SB), $0
+
+ MOVL $0, R0
+ MOVW SR, R0
+ MOVW $(SUPER|SPL(1)), SR
+ RTS
+
+TEXT flushcpucache(SB), $0
+
+ MOVL $(CCLEAR|CENABLE), R0
+ MOVL R0, CACR
+ RTS
+
+TEXT cacrtrap(SB), $0 /* user entry point to control cache, e.g. flush */
+
+ MOVL R0, CACR
+ RTE
+
+TEXT setlabel(SB), $0
+
+ MOVL sr+0(FP), A0
+ MOVL A7, (A0)+ /* stack pointer */
+ MOVL (A7), (A0)+ /* pc of caller */
+ MOVW SR, (A0)+ /* status register */
+ CLRL R0 /* ret 0 => not returning */
+ RTS
+
+TEXT gotolabel(SB), $0
+
+ MOVL p+0(FP), A0
+ MOVW $(SUPER|SPL(7)), SR
+ MOVL (A0)+, A7 /* stack pointer */
+ MOVL (A0)+, (A7) /* pc; stuff into stack frame */
+ MOVW (A0)+, R0 /* status register */
+ MOVW R0, SR
+ MOVL $1, R0 /* ret 1 => returning */
+ RTS
+
+/*
+ * Test and set, as a subroutine
+ */
+
+TEXT tas(SB), $0
+
+ MOVL $0, R0
+ MOVL a+0(FP), A0
+ TAS (A0)
+ BEQ tas_1
+ MOVL $1, R0
+tas_1:
+ RTS
+
+/*
+ * Floating point
+ */
+
+TEXT fpsave(SB), $0
+
+ FSAVE (fp+0(FP))
+ RTS
+
+TEXT fprestore(SB), $0
+
+ FRESTORE (fp+0(FP))
+ RTS
+
+TEXT fpregsave(SB), $0
+
+ FMOVEM $0xFF, (3*4)(fr+0(FP))
+ FMOVEMC $0x7, (fr+0(FP))
+ RTS
+
+TEXT fpregrestore(SB), $0
+
+ FMOVEMC (fr+0(FP)), $0x7
+ FMOVEM (3*4)(fr+0(FP)), $0xFF
+ RTS
+
+TEXT fpcr(SB), $0
+
+ MOVL new+0(FP), R1
+ MOVL FPCR, R0
+ MOVL R1, FPCR
+ RTS
+
+
+TEXT rfnote(SB), $0
+
+ MOVL uregp+0(FP), A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1+1)*BY2WD), A7
+ RTE
+
+TEXT illegal(SB), $0
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR trap(SB)
+ ADDL $4, A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+TEXT systrap(SB), $0
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVL A6, ((8+6)*BY2WD)(A7)
+ MOVL R0, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR syscall(SB)
+ MOVL ((1+8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVL ((1+8+6)*BY2WD)(A7), A6
+ ADDL $((1+8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+TEXT buserror(SB), $0
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ PEA ((8+8+1+3)*BY2WD)(A7)
+ PEA 4(A7)
+ BSR fault68020(SB)
+ ADDL $8, A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+TEXT tacintr(SB), $0 /* level 1 */
+
+ MOVL R0, -(A7)
+ MOVL TACADDR, R0
+ MOVL (A7)+, R0
+ RTE
+
+TEXT portintr(SB), $0 /* level 2 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR devportintr(SB)
+ BRA retintr
+
+TEXT dkintr(SB), $0 /* level 3 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR inconintr(SB)
+ BRA retintr
+
+TEXT mouseintr(SB), $0 /* level 4 */
+
+ MOVEM $0x80C2, -(A7) /* D0, A0, A1, A6 */
+ MOVL $a6base(SB), A6
+ MOVL $15, R0 /* mask off hex switch */
+ ANDB MOUSE,R0 /* clears quadrature interrupt */
+ LEA mousetab(SB)(R0.W*8), A0
+ LEA mouse(SB), A1
+ MOVL (A0)+, R0
+ ADDL R0, (A1)+ /* dx */
+ MOVL (A0), R0
+ ADDL R0, (A1)+ /* dy */
+ ADDL $1, (A1) /* track */
+ MOVEM (A7)+, $0x4301
+ RTE
+
+TEXT uartintr(SB), $0 /* level 5 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR duartintr(SB)
+ BRA retintr
+
+TEXT syncintr(SB), $0 /* level 6 */
+
+ MOVL $DBMAGIC, -(A7)
+ SUBL $((8+8+1)*BY2WD), A7
+ MOVEM $0x7FFF, (A7)
+ MOVL $a6base(SB), A6
+ MOVL USP, A0
+ MOVL A0, ((8+8)*BY2WD)(A7)
+ MOVL A7, -(A7)
+ BSR clock(SB)
+ /* fall through */
+retintr:
+ BSR mousetry(SB)
+ ADDL $4, A7
+ MOVL ((8+8)*BY2WD)(A7), A0
+ MOVL A0, USP
+ MOVEM (A7), $0x7FFF
+ ADDL $((8+8+1)*BY2WD+BY2WD), A7
+ RTE
+
+GLOBL duarttimer+0(SB),$4
+
+TEXT duartreadtimer+0(SB), $0
+ MOVW SR, R1 /* spl7() */
+ MOVW $0x2700, SR
+ MOVL $0x40100000, A0
+ CLRL R0
+ TSTB 15(A0) /* stop timer */
+ MOVW 6(A0), R0 /* read hi,lo */
+ TSTB 14(A0) /* restart timer */
+ NOTW R0 /* timer counts down from 0xffff */
+ ADDL duarttimer(SB), R0
+ MOVL R0, duarttimer(SB)
+ MOVW R1, SR
+ RTS
+
+GLOBL mousetab(SB), $128
+DATA mousetab+ 0(SB)/4, -1 /* x down, */
+DATA mousetab+ 4(SB)/4, 1 /* y up */
+DATA mousetab+ 8(SB)/4, 0 /* x - */
+DATA mousetab+ 12(SB)/4, 1 /* y up */
+DATA mousetab+ 16(SB)/4, 1 /* x up */
+DATA mousetab+ 20(SB)/4, 1 /* y up */
+DATA mousetab+ 24(SB)/4, 0 /* x - */
+DATA mousetab+ 28(SB)/4, 1 /* y up */
+DATA mousetab+ 32(SB)/4, -1 /* x down */
+DATA mousetab+ 36(SB)/4, 0 /* y - */
+DATA mousetab+ 40(SB)/4, 0 /* x - */
+DATA mousetab+ 44(SB)/4, 0 /* y - */
+DATA mousetab+ 48(SB)/4, 1 /* x up, */
+DATA mousetab+ 52(SB)/4, 0 /* y - */
+DATA mousetab+ 56(SB)/4, 0 /* x - */
+DATA mousetab+ 60(SB)/4, 0 /* y - */
+DATA mousetab+ 64(SB)/4, -1 /* x down */
+DATA mousetab+ 68(SB)/4, -1 /* y down */
+DATA mousetab+ 72(SB)/4, 0 /* x - */
+DATA mousetab+ 76(SB)/4, -1 /* y down */
+DATA mousetab+ 80(SB)/4, 1 /* x up */
+DATA mousetab+ 84(SB)/4, -1 /* y down */
+DATA mousetab+ 88(SB)/4, 0 /* x - */
+DATA mousetab+ 92(SB)/4, -1 /* y down */
+DATA mousetab+ 96(SB)/4, -1 /* x down */
+DATA mousetab+100(SB)/4, 0 /* y - */
+DATA mousetab+104(SB)/4, 0 /* x - */
+DATA mousetab+108(SB)/4, 0 /* y - */
+DATA mousetab+112(SB)/4, 1 /* x up */
+DATA mousetab+116(SB)/4, 0 /* y - */
+DATA mousetab+120(SB)/4, 0 /* x - */
+DATA mousetab+124(SB)/4, 0 /* y - */
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL u(SB), $4
+GLOBL m(SB), $4
diff --git a/utils/2a/lex.c b/utils/2a/lex.c
new file mode 100644
index 00000000..93ba0e2a
--- /dev/null
+++ b/utils/2a/lex.c
@@ -0,0 +1,935 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = '2';
+ thestring = "68020";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+ "TOS", LTOS, D_TOS,
+ "CCR", LTOS, D_CCR,
+ "SR", LTOS, D_SR,
+ "SFC", LTOS, D_SFC,
+ "DFC", LTOS, D_DFC,
+ "CACR", LTOS, D_CACR,
+ "USP", LTOS, D_USP,
+ "VBR", LTOS, D_VBR,
+ "CAAR", LTOS, D_CAAR,
+ "MSP", LTOS, D_MSP,
+ "ISP", LTOS, D_ISP,
+ "FPCR", LTOS, D_FPCR,
+ "FPSR", LTOS, D_FPSR,
+ "FPIAR", LTOS, D_FPIAR,
+ "TC", LTOS, D_TC,
+ "ITT0", LTOS, D_ITT0,
+ "ITT1", LTOS, D_ITT1,
+ "DTT0", LTOS, D_DTT0,
+ "DTT1", LTOS, D_DTT1,
+ "MMUSR", LTOS, D_MMUSR,
+ "URP", LTOS, D_URP,
+ "SRP", LTOS, D_SRP,
+
+ "R0", LDREG, D_R0+0,
+ "R1", LDREG, D_R0+1,
+ "R2", LDREG, D_R0+2,
+ "R3", LDREG, D_R0+3,
+ "R4", LDREG, D_R0+4,
+ "R5", LDREG, D_R0+5,
+ "R6", LDREG, D_R0+6,
+ "R7", LDREG, D_R0+7,
+
+ ".W", LWID, 0,
+ ".L", LWID, 4,
+
+ "A0", LAREG, D_A0+0,
+ "A1", LAREG, D_A0+1,
+ "A2", LAREG, D_A0+2,
+ "A3", LAREG, D_A0+3,
+ "A4", LAREG, D_A0+4,
+ "A5", LAREG, D_A0+5,
+ "A6", LAREG, D_A0+6,
+ "A7", LAREG, D_A0+7,
+
+ "F0", LFREG, D_F0+0,
+ "F1", LFREG, D_F0+1,
+ "F2", LFREG, D_F0+2,
+ "F3", LFREG, D_F0+3,
+ "F4", LFREG, D_F0+4,
+ "F5", LFREG, D_F0+5,
+ "F6", LFREG, D_F0+6,
+ "F7", LFREG, D_F0+7,
+
+ "ABCD", LTYPE1, AABCD,
+ "ADDB", LTYPE1, AADDB,
+ "ADDL", LTYPE1, AADDL,
+ "ADDW", LTYPE1, AADDW,
+ "ADDXB", LTYPE1, AADDXB,
+ "ADDXL", LTYPE1, AADDXL,
+ "ADDXW", LTYPE1, AADDXW,
+ "ADJSP", LTYPE5, AADJSP,
+ "ANDB", LTYPE1, AANDB,
+ "ANDL", LTYPE1, AANDL,
+ "ANDW", LTYPE1, AANDW,
+ "ASLB", LTYPE1, AASLB,
+ "ASLL", LTYPE1, AASLL,
+ "ASLW", LTYPE1, AASLW,
+ "ASRB", LTYPE1, AASRB,
+ "ASRL", LTYPE1, AASRL,
+ "ASRW", LTYPE1, AASRW,
+ "BCASE", LTYPE7, ABCASE,
+ "BCC", LTYPE6, ABCC,
+ "BCHG", LTYPE1, ABCHG,
+ "BCLR", LTYPE1, ABCLR,
+ "BCS", LTYPE6, ABCS,
+ "BEQ", LTYPE6, ABEQ,
+ "BFCHG", LTYPEA, ABFCHG,
+ "BFCLR", LTYPEA, ABFCLR,
+ "BFEXTS", LTYPEA, ABFEXTS,
+ "BFEXTU", LTYPEA, ABFEXTU,
+ "BFFFO", LTYPEA, ABFFFO,
+ "BFINS", LTYPEA, ABFINS,
+ "BFSET", LTYPEA, ABFSET,
+ "BFTST", LTYPEA, ABFTST,
+ "BGE", LTYPE6, ABGE,
+ "BGT", LTYPE6, ABGT,
+ "BHI", LTYPE6, ABHI,
+ "BKPT", LTYPE1, ABKPT,
+ "BLE", LTYPE6, ABLE,
+ "BLS", LTYPE6, ABLS,
+ "BLT", LTYPE6, ABLT,
+ "BMI", LTYPE6, ABMI,
+ "BNE", LTYPE6, ABNE,
+ "BPL", LTYPE6, ABPL,
+ "BRA", LTYPE6, ABRA,
+ "BSET", LTYPE1, ABSET,
+ "BSR", LTYPE3, ABSR,
+ "BTST", LTYPE1, ABTST,
+ "BVC", LTYPE6, ABVC,
+ "BVS", LTYPE6, ABVS,
+ "CALLM", LTYPE1, ACALLM,
+ "CAS2B", LTYPE1, ACAS2B,
+ "CAS2L", LTYPE1, ACAS2L,
+ "CAS2W", LTYPE1, ACAS2W,
+ "CASB", LTYPE1, ACASB,
+ "CASEW", LTYPE2, ACASEW,
+ "CASL", LTYPE1, ACASL,
+ "CASW", LTYPE1, ACASW,
+ "CHK2B", LTYPE1, ACHK2B,
+ "CHK2L", LTYPE1, ACHK2L,
+ "CHK2W", LTYPE1, ACHK2W,
+ "CHKL", LTYPE1, ACHKL,
+ "CHKW", LTYPE1, ACHKW,
+ "CLRB", LTYPE3, ACLRB,
+ "CLRL", LTYPE3, ACLRL,
+ "CLRW", LTYPE3, ACLRW,
+ "CMP2B", LTYPE1, ACMP2B,
+ "CMP2L", LTYPE1, ACMP2L,
+ "CMP2W", LTYPE1, ACMP2W,
+ "CMPB", LTYPE1, ACMPB,
+ "CMPL", LTYPE1, ACMPL,
+ "CMPW", LTYPE1, ACMPW,
+ "DATA", LTYPE4, ADATA,
+ "DBCC", LTYPE7, ADBCC,
+ "DBCS", LTYPE7, ADBCS,
+ "DBEQ", LTYPE7, ADBEQ,
+ "DBF", LTYPE7, ADBF,
+ "DBGE", LTYPE7, ADBGE,
+ "DBGT", LTYPE7, ADBGT,
+ "DBHI", LTYPE7, ADBHI,
+ "DBLE", LTYPE7, ADBLE,
+ "DBLS", LTYPE7, ADBLS,
+ "DBLT", LTYPE7, ADBLT,
+ "DBMI", LTYPE7, ADBMI,
+ "DBNE", LTYPE7, ADBNE,
+ "DBPL", LTYPE7, ADBPL,
+ "DBT", LTYPE7, ADBT,
+ "DBVC", LTYPE7, ADBVC,
+ "DBVS", LTYPE7, ADBVS,
+ "DIVSL", LTYPE1, ADIVSL,
+ "DIVSW", LTYPE1, ADIVSW,
+ "DIVUL", LTYPE1, ADIVUL,
+ "DIVUW", LTYPE1, ADIVUW,
+ "END", LTYPE2, AEND,
+ "EORB", LTYPE1, AEORB,
+ "EORL", LTYPE1, AEORL,
+ "EORW", LTYPE1, AEORW,
+ "EXG", LTYPE1, AEXG,
+ "EXTBL", LTYPE3, AEXTBL,
+ "EXTBW", LTYPE3, AEXTBW,
+ "EXTWL", LTYPE3, AEXTWL,
+ "FABSB", LTYPE1, AFABSB,
+ "FABSD", LTYPE1, AFABSD,
+ "FABSF", LTYPE1, AFABSF,
+ "FABSL", LTYPE1, AFABSL,
+ "FABSW", LTYPE1, AFABSW,
+ "FACOSB", LTYPE1, AFACOSB,
+ "FACOSD", LTYPE1, AFACOSD,
+ "FACOSF", LTYPE1, AFACOSF,
+ "FACOSL", LTYPE1, AFACOSL,
+ "FACOSW", LTYPE1, AFACOSW,
+ "FADDB", LTYPE1, AFADDB,
+ "FADDD", LTYPE1, AFADDD,
+ "FADDF", LTYPE1, AFADDF,
+ "FADDL", LTYPE1, AFADDL,
+ "FADDW", LTYPE1, AFADDW,
+ "FASINB", LTYPE1, AFASINB,
+ "FASIND", LTYPE1, AFASIND,
+ "FASINF", LTYPE1, AFASINF,
+ "FASINL", LTYPE1, AFASINL,
+ "FASINW", LTYPE1, AFASINW,
+ "FATANB", LTYPE1, AFATANB,
+ "FATAND", LTYPE1, AFATAND,
+ "FATANF", LTYPE1, AFATANF,
+ "FATANHB", LTYPE1, AFATANHB,
+ "FATANHD", LTYPE1, AFATANHD,
+ "FATANHF", LTYPE1, AFATANHF,
+ "FATANHL", LTYPE1, AFATANHL,
+ "FATANHW", LTYPE1, AFATANHW,
+ "FATANL", LTYPE1, AFATANL,
+ "FATANW", LTYPE1, AFATANW,
+ "FBEQ", LTYPE6, AFBEQ,
+ "FBF", LTYPE6, AFBF,
+ "FBGE", LTYPE6, AFBGE,
+ "FBGT", LTYPE6, AFBGT,
+ "FBLE", LTYPE6, AFBLE,
+ "FBLT", LTYPE6, AFBLT,
+ "FBNE", LTYPE6, AFBNE,
+ "FBT", LTYPE6, AFBT,
+ "FCMPB", LTYPE1, AFCMPB,
+ "FCMPD", LTYPE1, AFCMPD,
+ "FCMPF", LTYPE1, AFCMPF,
+ "FCMPL", LTYPE1, AFCMPL,
+ "FCMPW", LTYPE1, AFCMPW,
+ "FCOSB", LTYPE1, AFCOSB,
+ "FCOSD", LTYPE1, AFCOSD,
+ "FCOSF", LTYPE1, AFCOSF,
+ "FCOSHB", LTYPE1, AFCOSHB,
+ "FCOSHD", LTYPE1, AFCOSHD,
+ "FCOSHF", LTYPE1, AFCOSHF,
+ "FCOSHL", LTYPE1, AFCOSHL,
+ "FCOSHW", LTYPE1, AFCOSHW,
+ "FCOSL", LTYPE1, AFCOSL,
+ "FCOSW", LTYPE1, AFCOSW,
+ "FDBEQ", LTYPE7, AFDBEQ,
+ "FDBF", LTYPE7, AFDBF,
+ "FDBGE", LTYPE7, AFDBGE,
+ "FDBGT", LTYPE7, AFDBGT,
+ "FDBLE", LTYPE7, AFDBLE,
+ "FDBLT", LTYPE7, AFDBLT,
+ "FDBNE", LTYPE7, AFDBNE,
+ "FDBT", LTYPE7, AFDBT,
+ "FDIVB", LTYPE1, AFDIVB,
+ "FDIVD", LTYPE1, AFDIVD,
+ "FDIVF", LTYPE1, AFDIVF,
+ "FDIVL", LTYPE1, AFDIVL,
+ "FDIVW", LTYPE1, AFDIVW,
+ "FETOXB", LTYPE1, AFETOXB,
+ "FETOXD", LTYPE1, AFETOXD,
+ "FETOXF", LTYPE1, AFETOXF,
+ "FETOXL", LTYPE1, AFETOXL,
+ "FETOXM1B", LTYPE1, AFETOXM1B,
+ "FETOXM1D", LTYPE1, AFETOXM1D,
+ "FETOXM1F", LTYPE1, AFETOXM1F,
+ "FETOXM1L", LTYPE1, AFETOXM1L,
+ "FETOXM1W", LTYPE1, AFETOXM1W,
+ "FETOXW", LTYPE1, AFETOXW,
+ "FGETEXPB", LTYPE1, AFGETEXPB,
+ "FGETEXPD", LTYPE1, AFGETEXPD,
+ "FGETEXPF", LTYPE1, AFGETEXPF,
+ "FGETEXPL", LTYPE1, AFGETEXPL,
+ "FGETEXPW", LTYPE1, AFGETEXPW,
+ "FGETMANB", LTYPE1, AFGETMANB,
+ "FGETMAND", LTYPE1, AFGETMAND,
+ "FGETMANF", LTYPE1, AFGETMANF,
+ "FGETMANL", LTYPE1, AFGETMANL,
+ "FGETMANW", LTYPE1, AFGETMANW,
+ "FINTB", LTYPE1, AFINTB,
+ "FINTD", LTYPE1, AFINTD,
+ "FINTF", LTYPE1, AFINTF,
+ "FINTL", LTYPE1, AFINTL,
+ "FINTRZB", LTYPE1, AFINTRZB,
+ "FINTRZD", LTYPE1, AFINTRZD,
+ "FINTRZF", LTYPE1, AFINTRZF,
+ "FINTRZL", LTYPE1, AFINTRZL,
+ "FINTRZW", LTYPE1, AFINTRZW,
+ "FINTW", LTYPE1, AFINTW,
+ "FLOG10B", LTYPE1, AFLOG10B,
+ "FLOG10D", LTYPE1, AFLOG10D,
+ "FLOG10F", LTYPE1, AFLOG10F,
+ "FLOG10L", LTYPE1, AFLOG10L,
+ "FLOG10W", LTYPE1, AFLOG10W,
+ "FLOG2B", LTYPE1, AFLOG2B,
+ "FLOG2D", LTYPE1, AFLOG2D,
+ "FLOG2F", LTYPE1, AFLOG2F,
+ "FLOG2L", LTYPE1, AFLOG2L,
+ "FLOG2W", LTYPE1, AFLOG2W,
+ "FLOGNB", LTYPE1, AFLOGNB,
+ "FLOGND", LTYPE1, AFLOGND,
+ "FLOGNF", LTYPE1, AFLOGNF,
+ "FLOGNL", LTYPE1, AFLOGNL,
+ "FLOGNP1B", LTYPE1, AFLOGNP1B,
+ "FLOGNP1D", LTYPE1, AFLOGNP1D,
+ "FLOGNP1F", LTYPE1, AFLOGNP1F,
+ "FLOGNP1L", LTYPE1, AFLOGNP1L,
+ "FLOGNP1W", LTYPE1, AFLOGNP1W,
+ "FLOGNW", LTYPE1, AFLOGNW,
+ "FMODB", LTYPE1, AFMODB,
+ "FMODD", LTYPE1, AFMODD,
+ "FMODF", LTYPE1, AFMODF,
+ "FMODL", LTYPE1, AFMODL,
+ "FMODW", LTYPE1, AFMODW,
+ "FMOVEB", LTYPE1, AFMOVEB,
+ "FMOVED", LTYPE1, AFMOVED,
+ "FMOVEF", LTYPE1, AFMOVEF,
+ "FMOVEL", LTYPE1, AFMOVEL,
+ "FMOVEW", LTYPE1, AFMOVEW,
+ "FMULB", LTYPE1, AFMULB,
+ "FMULD", LTYPE1, AFMULD,
+ "FMULF", LTYPE1, AFMULF,
+ "FMULL", LTYPE1, AFMULL,
+ "FMULW", LTYPE1, AFMULW,
+ "FNEGB", LTYPE8, AFNEGB,
+ "FNEGD", LTYPE8, AFNEGD,
+ "FNEGF", LTYPE8, AFNEGF,
+ "FNEGL", LTYPE8, AFNEGL,
+ "FNEGW", LTYPE8, AFNEGW,
+ "FREMB", LTYPE1, AFREMB,
+ "FREMD", LTYPE1, AFREMD,
+ "FREMF", LTYPE1, AFREMF,
+ "FREML", LTYPE1, AFREML,
+ "FREMW", LTYPE1, AFREMW,
+ "FSCALEB", LTYPE1, AFSCALEB,
+ "FSCALED", LTYPE1, AFSCALED,
+ "FSCALEF", LTYPE1, AFSCALEF,
+ "FSCALEL", LTYPE1, AFSCALEL,
+ "FSCALEW", LTYPE1, AFSCALEW,
+ "FSEQ", LTYPE1, AFSEQ,
+ "FSF", LTYPE1, AFSF,
+ "FSGE", LTYPE1, AFSGE,
+ "FSGT", LTYPE1, AFSGT,
+ "FSINB", LTYPE1, AFSINB,
+ "FSIND", LTYPE1, AFSIND,
+ "FSINF", LTYPE1, AFSINF,
+ "FSINHB", LTYPE1, AFSINHB,
+ "FSINHD", LTYPE1, AFSINHD,
+ "FSINHF", LTYPE1, AFSINHF,
+ "FSINHL", LTYPE1, AFSINHL,
+ "FSINHW", LTYPE1, AFSINHW,
+ "FSINL", LTYPE1, AFSINL,
+ "FSINW", LTYPE1, AFSINW,
+ "FSLE", LTYPE1, AFSLE,
+ "FSLT", LTYPE1, AFSLT,
+ "FSNE", LTYPE1, AFSNE,
+ "FSQRTB", LTYPE1, AFSQRTB,
+ "FSQRTD", LTYPE1, AFSQRTD,
+ "FSQRTF", LTYPE1, AFSQRTF,
+ "FSQRTL", LTYPE1, AFSQRTL,
+ "FSQRTW", LTYPE1, AFSQRTW,
+ "FST", LTYPE1, AFST,
+ "FSUBB", LTYPE1, AFSUBB,
+ "FSUBD", LTYPE1, AFSUBD,
+ "FSUBF", LTYPE1, AFSUBF,
+ "FSUBL", LTYPE1, AFSUBL,
+ "FSUBW", LTYPE1, AFSUBW,
+ "FTANB", LTYPE1, AFTANB,
+ "FTAND", LTYPE1, AFTAND,
+ "FTANF", LTYPE1, AFTANF,
+ "FTANHB", LTYPE1, AFTANHB,
+ "FTANHD", LTYPE1, AFTANHD,
+ "FTANHF", LTYPE1, AFTANHF,
+ "FTANHL", LTYPE1, AFTANHL,
+ "FTANHW", LTYPE1, AFTANHW,
+ "FTANL", LTYPE1, AFTANL,
+ "FTANW", LTYPE1, AFTANW,
+ "FTENTOXB", LTYPE1, AFTENTOXB,
+ "FTENTOXD", LTYPE1, AFTENTOXD,
+ "FTENTOXF", LTYPE1, AFTENTOXF,
+ "FTENTOXL", LTYPE1, AFTENTOXL,
+ "FTENTOXW", LTYPE1, AFTENTOXW,
+ "FTSTB", LTYPE1, AFTSTB,
+ "FTSTD", LTYPE1, AFTSTD,
+ "FTSTF", LTYPE1, AFTSTF,
+ "FTSTL", LTYPE1, AFTSTL,
+ "FTSTW", LTYPE1, AFTSTW,
+ "FTWOTOXB", LTYPE1, AFTWOTOXB,
+ "FTWOTOXD", LTYPE1, AFTWOTOXD,
+ "FTWOTOXF", LTYPE1, AFTWOTOXF,
+ "FTWOTOXL", LTYPE1, AFTWOTOXL,
+ "FTWOTOXW", LTYPE1, AFTWOTOXW,
+ "FMOVEM", LTYPE1, AFMOVEM,
+ "FMOVEMC", LTYPE1, AFMOVEMC,
+ "FRESTORE", LTYPE3, AFRESTORE,
+ "FSAVE", LTYPE3, AFSAVE,
+ "GLOBL", LTYPE1, AGLOBL,
+ "GOK", LTYPE2, AGOK,
+ "HISTORY", LTYPE2, AHISTORY,
+ "ILLEG", LTYPE2, AILLEG,
+ "INSTR", LTYPE3, AINSTR,
+ "JMP", LTYPE3, AJMP,
+ "JSR", LTYPE3, AJSR,
+ "LEA", LTYPE1, ALEA,
+ "LINKL", LTYPE1, ALINKL,
+ "LINKW", LTYPE1, ALINKW,
+ "LOCATE", LTYPE1, ALOCATE,
+ "LONG", LTYPE3, ALONG,
+ "LSLB", LTYPE1, ALSLB,
+ "LSLL", LTYPE1, ALSLL,
+ "LSLW", LTYPE1, ALSLW,
+ "LSRB", LTYPE1, ALSRB,
+ "LSRL", LTYPE1, ALSRL,
+ "LSRW", LTYPE1, ALSRW,
+ "MOVB", LTYPE1, AMOVB,
+ "MOVEM", LTYPE1, AMOVEM,
+ "MOVEPL", LTYPE1, AMOVEPL,
+ "MOVEPW", LTYPE1, AMOVEPW,
+ "MOVESB", LTYPE1, AMOVESB,
+ "MOVESL", LTYPE1, AMOVESL,
+ "MOVESW", LTYPE1, AMOVESW,
+ "MOVL", LTYPE1, AMOVL,
+ "MOVW", LTYPE1, AMOVW,
+ "MULSL", LTYPE1, AMULSL,
+ "MULSW", LTYPE1, AMULSW,
+ "MULUL", LTYPE1, AMULUL,
+ "MULUW", LTYPE1, AMULUW,
+ "NAME", LTYPE1, ANAME,
+ "NBCD", LTYPE3, ANBCD,
+ "NEGB", LTYPE3, ANEGB,
+ "NEGL", LTYPE3, ANEGL,
+ "NEGW", LTYPE3, ANEGW,
+ "NEGXB", LTYPE3, ANEGXB,
+ "NEGXL", LTYPE3, ANEGXL,
+ "NEGXW", LTYPE3, ANEGXW,
+ "NOP", LTYPE9, ANOP,
+ "NOTB", LTYPE3, ANOTB,
+ "NOTL", LTYPE3, ANOTL,
+ "NOTW", LTYPE3, ANOTW,
+ "ORB", LTYPE1, AORB,
+ "ORL", LTYPE1, AORL,
+ "ORW", LTYPE1, AORW,
+ "PACK", LTYPE1, APACK,
+ "PEA", LTYPE3, APEA,
+ "RESET", LTYPE2, ARESET,
+ "ROTLB", LTYPE1, AROTLB,
+ "ROTLL", LTYPE1, AROTLL,
+ "ROTLW", LTYPE1, AROTLW,
+ "ROTRB", LTYPE1, AROTRB,
+ "ROTRL", LTYPE1, AROTRL,
+ "ROTRW", LTYPE1, AROTRW,
+ "ROXLB", LTYPE1, AROXLB,
+ "ROXLL", LTYPE1, AROXLL,
+ "ROXLW", LTYPE1, AROXLW,
+ "ROXRB", LTYPE1, AROXRB,
+ "ROXRL", LTYPE1, AROXRL,
+ "ROXRW", LTYPE1, AROXRW,
+ "RTD", LTYPE3, ARTD,
+ "RTE", LTYPE2, ARTE,
+ "RTM", LTYPE3, ARTM,
+ "RTR", LTYPE2, ARTR,
+ "RTS", LTYPE2, ARTS,
+ "SBCD", LTYPE1, ASBCD,
+ "SCC", LTYPE3, ASCC,
+ "SCS", LTYPE3, ASCS,
+ "SEQ", LTYPE3, ASEQ,
+ "SF", LTYPE3, ASF,
+ "SGE", LTYPE3, ASGE,
+ "SGT", LTYPE3, ASGT,
+ "SHI", LTYPE3, ASHI,
+ "SLE", LTYPE3, ASLE,
+ "SLS", LTYPE3, ASLS,
+ "SLT", LTYPE3, ASLT,
+ "SMI", LTYPE3, ASMI,
+ "SNE", LTYPE3, ASNE,
+ "SPL", LTYPE3, ASPL,
+ "ST", LTYPE3, AST,
+ "STOP", LTYPE3, ASTOP,
+ "SUBB", LTYPE1, ASUBB,
+ "SUBL", LTYPE1, ASUBL,
+ "SUBW", LTYPE1, ASUBW,
+ "SUBXB", LTYPE1, ASUBXB,
+ "SUBXL", LTYPE1, ASUBXL,
+ "SUBXW", LTYPE1, ASUBXW,
+ "SVC", LTYPE2, ASVC,
+ "SVS", LTYPE2, ASVS,
+ "SWAP", LTYPE3, ASWAP,
+ "SYS", LTYPE2, ASYS,
+ "TAS", LTYPE3, ATAS,
+ "TEXT", LTYPEB, ATEXT,
+ "TRAP", LTYPE3, ATRAP,
+ "TRAPCC", LTYPE2, ATRAPCC,
+ "TRAPCS", LTYPE2, ATRAPCS,
+ "TRAPEQ", LTYPE2, ATRAPEQ,
+ "TRAPF", LTYPE2, ATRAPF,
+ "TRAPGE", LTYPE2, ATRAPGE,
+ "TRAPGT", LTYPE2, ATRAPGT,
+ "TRAPHI", LTYPE2, ATRAPHI,
+ "TRAPLE", LTYPE2, ATRAPLE,
+ "TRAPLS", LTYPE2, ATRAPLS,
+ "TRAPLT", LTYPE2, ATRAPLT,
+ "TRAPMI", LTYPE2, ATRAPMI,
+ "TRAPNE", LTYPE2, ATRAPNE,
+ "TRAPPL", LTYPE2, ATRAPPL,
+ "TRAPT", LTYPE2, ATRAPT,
+ "TRAPV", LTYPE2, ATRAPV,
+ "TRAPVC", LTYPE2, ATRAPVC,
+ "TRAPVS", LTYPE2, ATRAPVS,
+ "TSTB", LTYPE3, ATSTB,
+ "TSTL", LTYPE3, ATSTL,
+ "TSTW", LTYPE3, ATSTW,
+ "UNLK", LTYPE3, AUNLK,
+ "UNPK", LTYPE1, AUNPK,
+ "WORD", LTYPE3, AWORD,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.s0.sym = S;
+ nullgen.s0.offset = 0;
+ nullgen.type = D_NONE;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+ nullgen.displace = 0;
+ nullgen.type = D_NONE;
+ nullgen.index = D_NONE;
+ nullgen.scale = 0;
+ nullgen.field = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+ Gen2 g2;
+
+ g2.from = nullgen;
+ g2.to = nullgen;
+ outcode(AEND, &g2);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME); /* as */
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->field)
+ t |= T_FIELD;
+ if(a->index != D_NONE || a->displace != 0)
+ t |= T_INDEX;
+ if(a->s0.offset != 0)
+ t |= T_OFFSET;
+ if(s != 0)
+ t |= T_SYM;
+
+ if(a->type == D_FCONST)
+ t |= T_FCONST;
+ else
+ if(a->type == D_SCONST)
+ t |= T_SCONST;
+ else
+ if(a->type & ~0xff)
+ t |= T_TYPE;
+ Bputc(&obuf, t);
+
+ if(t & T_FIELD) { /* implies field */
+ i = a->field;
+ Bputc(&obuf, i);
+ Bputc(&obuf, i>>8);
+ }
+ if(t & T_INDEX) { /* implies index, scale, displace */
+ i = a->index;
+ Bputc(&obuf, i);
+ Bputc(&obuf, i>>8);
+ Bputc(&obuf, a->scale);
+ l = a->displace;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->s0.offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(&obuf, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ l = e.h;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ return;
+ }
+ i = a->type;
+ Bputc(&obuf, i);
+ if(t & T_TYPE)
+ Bputc(&obuf, i>>8);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+
+jackpot:
+ sf = 0;
+ s = g2->from.s0.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g2->from.type & D_MASK;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->to.s0.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->to.type & D_MASK;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, a>>8);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(&g2->from, sf);
+ zaddr(&g2->to, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.s0.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, AHISTORY>>8);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/2a/mkfile b/utils/2a/mkfile
new file mode 100644
index 00000000..2cf27e17
--- /dev/null
+++ b/utils/2a/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=2a
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../2c/2.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/2c/2.out.h b/utils/2c/2.out.h
new file mode 100644
index 00000000..0cf36f82
--- /dev/null
+++ b/utils/2c/2.out.h
@@ -0,0 +1,523 @@
+#define NSYM 50
+#define NSNAME 8
+
+/* R0 is return */
+#define REGEXT 7
+/* A7 is sp A6 is sb */
+#define AREGEXT 5
+/* F0 is ret */
+#define FREGEXT 7
+
+enum as
+{
+ AXXX = 0,
+ AABCD,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADDXB,
+ AADDXL,
+ AADDXW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AASLB,
+ AASLL,
+ AASLW,
+ AASRB,
+ AASRL,
+ AASRW,
+ ABCASE,
+ ABCC,
+ ABCHG,
+ ABCLR,
+ ABCS,
+ ABEQ,
+ ABFCHG,
+ ABFCLR,
+ ABFEXTS,
+ ABFEXTU,
+ ABFFFO,
+ ABFINS,
+ ABFSET,
+ ABFTST,
+ ABGE,
+ ABGT,
+ ABHI,
+ ABKPT,
+ ABLE,
+ ABLS,
+ ABLT,
+ ABMI,
+ ABNE,
+ ABPL,
+ ABRA,
+ ABSET,
+ ABSR,
+ ABTST,
+ ABVC,
+ ABVS,
+ ACALLM,
+ ACAS2B,
+ ACAS2L,
+ ACAS2W,
+ ACASB,
+ ACASEW,
+ ACASL,
+ ACASW,
+ ACHK2B,
+ ACHK2L,
+ ACHK2W,
+ ACHKL,
+ ACHKW,
+ ACLRB,
+ ACLRL,
+ ACLRW,
+ ACMP2B,
+ ACMP2L,
+ ACMP2W,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ADATA,
+ ADBCC,
+ ADBCS,
+ ADBEQ,
+ ADBF,
+ ADBGE,
+ ADBGT,
+ ADBHI,
+ ADBLE,
+ ADBLS,
+ ADBLT,
+ ADBMI,
+ ADBNE,
+ ADBPL,
+ ADBT,
+ ADBVC,
+ ADBVS,
+ ADIVSL,
+ ADIVSW,
+ ADIVUL,
+ ADIVUW,
+ AEND,
+ AEORB,
+ AEORL,
+ AEORW,
+ AEXG,
+ AEXTBL,
+ AEXTBW,
+ AEXTWL,
+ AFABSB,
+ AFABSD,
+ AFABSF,
+ AFABSL,
+ AFABSW,
+ AFACOSB,
+ AFACOSD,
+ AFACOSF,
+ AFACOSL,
+ AFACOSW,
+ AFADDB,
+ AFADDD,
+ AFADDF,
+ AFADDL,
+ AFADDW,
+ AFASINB,
+ AFASIND,
+ AFASINF,
+ AFASINL,
+ AFASINW,
+ AFATANB,
+ AFATAND,
+ AFATANF,
+ AFATANHB,
+ AFATANHD,
+ AFATANHF,
+ AFATANHL,
+ AFATANHW,
+ AFATANL,
+ AFATANW,
+ AFBEQ,
+ AFBF,
+ AFBGE,
+ AFBGT,
+ AFBLE,
+ AFBLT,
+ AFBNE,
+ AFBT,
+ AFCMPB,
+ AFCMPD,
+ AFCMPF,
+ AFCMPL,
+ AFCMPW,
+ AFCOSB,
+ AFCOSD,
+ AFCOSF,
+ AFCOSHB,
+ AFCOSHD,
+ AFCOSHF,
+ AFCOSHL,
+ AFCOSHW,
+ AFCOSL,
+ AFCOSW,
+ AFDBEQ,
+ AFDBF,
+ AFDBGE,
+ AFDBGT,
+ AFDBLE,
+ AFDBLT,
+ AFDBNE,
+ AFDBT,
+ AFDIVB,
+ AFDIVD,
+ AFDIVF,
+ AFDIVL,
+ AFDIVW,
+ AFETOXB,
+ AFETOXD,
+ AFETOXF,
+ AFETOXL,
+ AFETOXM1B,
+ AFETOXM1D,
+ AFETOXM1F,
+ AFETOXM1L,
+ AFETOXM1W,
+ AFETOXW,
+ AFGETEXPB,
+ AFGETEXPD,
+ AFGETEXPF,
+ AFGETEXPL,
+ AFGETEXPW,
+ AFGETMANB,
+ AFGETMAND,
+ AFGETMANF,
+ AFGETMANL,
+ AFGETMANW,
+ AFINTB,
+ AFINTD,
+ AFINTF,
+ AFINTL,
+ AFINTRZB,
+ AFINTRZD,
+ AFINTRZF,
+ AFINTRZL,
+ AFINTRZW,
+ AFINTW,
+ AFLOG10B,
+ AFLOG10D,
+ AFLOG10F,
+ AFLOG10L,
+ AFLOG10W,
+ AFLOG2B,
+ AFLOG2D,
+ AFLOG2F,
+ AFLOG2L,
+ AFLOG2W,
+ AFLOGNB,
+ AFLOGND,
+ AFLOGNF,
+ AFLOGNL,
+ AFLOGNP1B,
+ AFLOGNP1D,
+ AFLOGNP1F,
+ AFLOGNP1L,
+ AFLOGNP1W,
+ AFLOGNW,
+ AFMODB,
+ AFMODD,
+ AFMODF,
+ AFMODL,
+ AFMODW,
+ AFMOVEB,
+ AFMOVED,
+ AFMOVEF,
+ AFMOVEL,
+ AFMOVEM,
+ AFMOVEMC,
+ AFMOVEW,
+ AFMULB,
+ AFMULD,
+ AFMULF,
+ AFMULL,
+ AFMULW,
+ AFNEGB,
+ AFNEGD,
+ AFNEGF,
+ AFNEGL,
+ AFNEGW,
+ AFREMB,
+ AFREMD,
+ AFREMF,
+ AFREML,
+ AFREMW,
+ AFRESTORE,
+ AFSAVE,
+ AFSCALEB,
+ AFSCALED,
+ AFSCALEF,
+ AFSCALEL,
+ AFSCALEW,
+ AFSEQ,
+ AFSF,
+ AFSGE,
+ AFSGT,
+ AFSINB,
+ AFSIND,
+ AFSINF,
+ AFSINHB,
+ AFSINHD,
+ AFSINHF,
+ AFSINHL,
+ AFSINHW,
+ AFSINL,
+ AFSINW,
+ AFSLE,
+ AFSLT,
+ AFSNE,
+ AFSQRTB,
+ AFSQRTD,
+ AFSQRTF,
+ AFSQRTL,
+ AFSQRTW,
+ AFST,
+ AFSUBB,
+ AFSUBD,
+ AFSUBF,
+ AFSUBL,
+ AFSUBW,
+ AFTANB,
+ AFTAND,
+ AFTANF,
+ AFTANHB,
+ AFTANHD,
+ AFTANHF,
+ AFTANHL,
+ AFTANHW,
+ AFTANL,
+ AFTANW,
+ AFTENTOXB,
+ AFTENTOXD,
+ AFTENTOXF,
+ AFTENTOXL,
+ AFTENTOXW,
+ AFTSTB,
+ AFTSTD,
+ AFTSTF,
+ AFTSTL,
+ AFTSTW,
+ AFTWOTOXB,
+ AFTWOTOXD,
+ AFTWOTOXF,
+ AFTWOTOXL,
+ AFTWOTOXW,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AILLEG,
+ AINSTR,
+ AJMP,
+ AJSR,
+ ALEA,
+ ALINKL,
+ ALINKW,
+ ALOCATE,
+ ALONG,
+ ALSLB,
+ ALSLL,
+ ALSLW,
+ ALSRB,
+ ALSRL,
+ ALSRW,
+ AMOVB,
+ AMOVEM,
+ AMOVEPL,
+ AMOVEPW,
+ AMOVESB,
+ AMOVESL,
+ AMOVESW,
+ AMOVL,
+ AMOVW,
+ AMULSL,
+ AMULSW,
+ AMULUL,
+ AMULUW,
+ ANAME,
+ ANBCD,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANEGXB,
+ ANEGXL,
+ ANEGXW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ APACK,
+ APEA,
+ ARESET,
+ AROTLB,
+ AROTLL,
+ AROTLW,
+ AROTRB,
+ AROTRL,
+ AROTRW,
+ AROXLB,
+ AROXLL,
+ AROXLW,
+ AROXRB,
+ AROXRL,
+ AROXRW,
+ ARTD,
+ ARTE,
+ ARTM,
+ ARTR,
+ ARTS,
+ ASBCD,
+ ASCC,
+ ASCS,
+ ASEQ,
+ ASF,
+ ASGE,
+ ASGT,
+ ASHI,
+ ASLE,
+ ASLS,
+ ASLT,
+ ASMI,
+ ASNE,
+ ASPL,
+ AST,
+ ASTOP,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASUBXB,
+ ASUBXL,
+ ASUBXW,
+ ASVC,
+ ASVS,
+ ASWAP,
+ ASYS,
+ ATAS,
+ ATEXT,
+ ATRAP,
+ ATRAPCC,
+ ATRAPCS,
+ ATRAPEQ,
+ ATRAPF,
+ ATRAPGE,
+ ATRAPGT,
+ ATRAPHI,
+ ATRAPLE,
+ ATRAPLS,
+ ATRAPLT,
+ ATRAPMI,
+ ATRAPNE,
+ ATRAPPL,
+ ATRAPT,
+ ATRAPV,
+ ATRAPVC,
+ ATRAPVS,
+ ATSTB,
+ ATSTL,
+ ATSTW,
+ AUNLK,
+ AUNPK,
+ AWORD,
+ ASIGNAME,
+
+ ALAST
+};
+
+enum
+{
+ NREG = 8,
+
+ D_R0 = 0,
+ D_A0 = NREG,
+ D_F0 = D_A0+NREG,
+ D_NONE = D_F0+NREG,
+ D_TOS,
+ D_BRANCH,
+ D_STACK,
+ D_TREE,
+ D_EXTERN,
+ D_STATIC,
+ D_AUTO,
+ D_PARAM,
+ D_CONST,
+ D_FCONST,
+ D_QUICK,
+
+ D_CCR,
+ D_SR,
+ D_SFC,
+ D_CACR,
+ D_USP,
+ D_VBR,
+ D_CAAR,
+ D_MSP,
+ D_ISP,
+ D_DFC,
+ D_FPCR,
+ D_FPSR,
+ D_FPIAR,
+ D_SCONST,
+ D_FILE,
+
+ D_TC, /* new for 68040 */
+ D_ITT0,
+ D_ITT1,
+ D_DTT0,
+ D_DTT1,
+ D_MMUSR,
+ D_URP,
+ D_SRP,
+
+ D_FILE1,
+
+ D_MASK = 63/(D_SRP>=63?0:1),
+
+ I_DIR = (D_MASK+1)*0,
+ I_INDINC = (D_MASK+1)*1,
+ I_INDDEC = (D_MASK+1)*2,
+ I_INDIR = (D_MASK+1)*3,
+ I_ADDR = (D_MASK+1)*4,
+
+ I_INDEX1 = (D_MASK+1)*1,
+ I_INDEX2 = (D_MASK+1)*2,
+ I_INDEX3 = (D_MASK+1)*3,
+
+ I_MASK = (D_MASK+1)*7,
+
+ T_FIELD = 1<<0,
+ T_INDEX = 1<<1,
+ T_TYPE = 1<<2,
+ T_OFFSET = 1<<3,
+ T_FCONST = 1<<4,
+ T_SYM = 1<<5,
+ T_SCONST = 1<<6
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/2c/Update b/utils/2c/Update
new file mode 100644
index 00000000..65024dfe
--- /dev/null
+++ b/utils/2c/Update
@@ -0,0 +1,7 @@
+ if(n->op == ONAME) {
+< if(o == OSET)
+< gopcode(OTST, tint, D_NONE, Z, D_TREE, n);
+< else
+< gopcode(OTST, tint, D_TREE, n, D_NONE, Z);
+< p->as = ANOP;
+< }
diff --git a/utils/2c/cgen.c b/utils/2c/cgen.c
new file mode 100644
index 00000000..3c1d4b3d
--- /dev/null
+++ b/utils/2c/cgen.c
@@ -0,0 +1,1404 @@
+#include "gc.h"
+
+void
+cgen(Node *n, int result, Node *nn)
+{
+ Node *l, *r, nod;
+ int lg, rg, xg, yg, g, o;
+ long v;
+ Prog *p1;
+
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, result, nn, n->type->width);
+ return;
+ }
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "cgen");
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(result == D_NONE) {
+ if(nn == Z)
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n->type, nn->type, D_TREE, n, result, nn);
+ return;
+ }
+
+ v = 0; /* set */
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ /*
+ * recursive use of result
+ */
+ if(result == D_NONE)
+ if(l->addable > INDEXED)
+ if(l->complex < FNX) {
+ cgen(r, D_TREE, l);
+ break;
+ }
+
+ /*
+ * function calls on both sides
+ */
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ adjsp(v - argoff);
+ gmove(r->type, l->type, D_TOS, r, lg, l);
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+
+ rg = D_TREE;
+ lg = D_TREE;
+ if(r->complex >= l->complex) {
+ /*
+ * right side before left
+ */
+ if(result != D_NONE) {
+ rg = regalloc(n->type, result);
+ cgen(r, rg, n);
+ } else
+ if(r->complex >= FNX || r->addable < INDEXED) {
+ rg = regalloc(r->type, result);
+ cgen(r, rg, r);
+ }
+ if(l->addable < INDEXED) {
+ lg = regaddr(lg);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ } else {
+ /*
+ * left before right
+ */
+ if(l->complex >= FNX || l->addable < INDEXED) {
+ lg = regaddr(lg);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(result != D_NONE) {
+ rg = regalloc(n->type, result);
+ cgen(r, rg, n);
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(r->type, result);
+ cgen(r, rg, r);
+ }
+ }
+ if(result != D_NONE) {
+ gmove(n->type, l->type, rg, r, lg, l);
+ gmove(n->type, nn->type, rg, r, result, nn);
+ } else
+ gmove(r->type, l->type, rg, r, lg, l);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ bitas:
+ n = l->left;
+ rg = regalloc(tfield, result);
+ if(l->complex >= r->complex) {
+ lg = regaddr(D_NONE);
+ lcgen(n, lg, Z);
+ lg |= I_INDIR;
+ cgen(r, rg, r);
+ } else {
+ cgen(r, rg, r);
+ lg = regaddr(D_NONE);
+ lcgen(n, lg, Z);
+ lg |= I_INDIR;
+ }
+ g = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, g, l);
+ bitstore(l, rg, lg, g, result, nn);
+ break;
+
+ case OBIT:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ g = bitload(n, D_NONE, D_NONE, result, nn);
+ gopcode(OAS, nn->type, g, n, result, nn);
+ regfree(g);
+ break;
+
+ case ODOT:
+ sugen(l, D_TREE, nodrat, l->type->width);
+ if(result != D_NONE) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += r->vconst;
+ nod.type = n->type;
+ cgen(&nod, result, nn);
+ }
+ break;
+
+ case OASLDIV:
+ case OASLMOD:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ if(l->complex >= FNX || r->complex >= FNX) {
+ rg = D_TOS;
+ cgen(r, rg, r);
+ v = argoff;
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ lg = D_TREE;
+ if(!simplv(l)) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z); /* destroys register optimization */
+ lg |= I_INDIR;
+ }
+ g = regpair(result);
+ gmove(l->type, n->type, lg, l, g, n);
+ if(rg == D_TOS)
+ adjsp(v - argoff);
+ gopcode(o, n->type, rg, r, g, n);
+ if(o == OASLMOD || o == OASMOD)
+ gmove(n->type, l->type, g+1, n, lg, l);
+ else
+ gmove(n->type, l->type, g, n, lg, l);
+ if(result != D_NONE)
+ if(o == OASLMOD || o == OASMOD)
+ gmove(n->type, nn->type, g+1, n, result, nn);
+ else
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ regfree(g+1);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ if(r->op != OCONST) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ gopcode(o, l->type, rg, r, D_TREE, l);
+ regfree(rg);
+ break;
+
+ case OASADD:
+ case OASSUB:
+ if(l->op == OBIT ||
+ l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ v = vconst(r);
+ if(v > 0 && v <= 8) {
+ gopcode(o, n->type, D_TREE, r, D_TREE, l);
+ break;
+ }
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ gopcode(o, n->type, rg, r, D_TREE, l);
+ regfree(rg);
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ if(l->op == OBIT ||
+ l->complex >= FNX ||
+ l->addable < INDEXED ||
+ result != D_NONE ||
+ typefd[n->type->etype])
+ goto asbinop;
+ rg = D_TREE;
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ lg = regalloc(n->type, D_NONE);
+ cgen(l, lg, l);
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, n->type, lg, l, D_TREE, l);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ asbinop:
+ if(l->op == OBIT)
+ goto asbitop;
+ rg = D_TREE;
+ if(l->complex >= FNX || r->complex >= FNX) {
+ rg = D_TOS;
+ cgen(r, rg, r);
+ v = argoff;
+ } else
+ if(r->addable < INDEXED) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ } else {
+ if(o == OASLSHR || o == OASASHR || o == OASASHL) {
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ }
+ }
+ lg = D_TREE;
+ if(!simplv(l)) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z); /* destroys register optimization */
+ lg |= I_INDIR;
+ }
+ g = regalloc(n->type, result);
+ gmove(l->type, n->type, lg, l, g, n);
+ if(rg == D_TOS)
+ adjsp(v - argoff);
+ if(o == OASXOR)
+ if(rg == D_TREE) {
+ rg = regalloc(n->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL)
+ if(rg == D_TOS) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(n->type, n->type, D_TOS, n, rg, n);
+ }
+ gopcode(o, n->type, rg, r, g, n);
+ gmove(n->type, l->type, g, n, lg, l);
+ if(result != D_NONE)
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ asbitop:
+ rg = regaddr(D_NONE);
+ lg = regalloc(tfield, D_NONE);
+ if(l->complex >= r->complex) {
+ g = bitload(l, lg, rg, result, nn);
+ xg = regalloc(r->type, D_NONE);
+ cgen(r, xg, nn);
+ } else {
+ xg = regalloc(r->type, D_NONE);
+ cgen(r, xg, nn);
+ g = bitload(l, lg, rg, result, nn);
+ }
+
+ if(!typefd[n->type->etype]) {
+ if(o == OASLDIV || o == OASDIV) {
+ yg = regpair(result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg, n, g, l);
+ regfree(yg);
+ regfree(yg+1);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ if(o == OASLMOD || o == OASMOD) {
+ yg = regpair(result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg+1, n, g, l);
+ regfree(yg);
+ regfree(yg+1);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ }
+
+ yg = regalloc(n->type, result);
+ gmove(tfield, n->type, g, l, yg, n);
+ gopcode(o, n->type, xg, r, yg, n);
+ gmove(n->type, tfield, yg, n, g, l);
+ regfree(yg);
+
+ regfree(xg);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+
+ case OCAST:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = result;
+ if(l->complex >= FNX)
+ lg = regret(l->type);
+ lg = eval(l, lg);
+ if(nocast(l->type, n->type)) {
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ if(nocast(n->type, nn->type)) {
+ gmove(l->type, n->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ rg = regalloc(n->type, result);
+ gmove(l->type, n->type, lg, l, rg, n);
+ gmove(n->type, nn->type, rg, n, result, nn);
+ regfree(rg);
+ regfree(lg);
+ break;
+
+ case OCOND:
+ doinc(l, PRE);
+ boolgen(l, 1, D_NONE, Z, l);
+ p1 = p;
+
+ inargs++;
+ doinc(r->left, PRE);
+ cgen(r->left, result, nn);
+ doinc(r->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ cgen(r->right, result, nn);
+ doinc(r->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OIND:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = nodalloc(types[TIND], result, &nod);
+ nod.lineno = n->lineno;
+ if(l->op == OADD) {
+ if(l->left->op == OCONST) {
+ nod.xoffset += l->left->vconst;
+ l = l->right;
+ } else
+ if(l->right->op == OCONST) {
+ nod.xoffset += l->right->vconst;
+ l = l->left;
+ }
+ }
+ cgen(l, lg, l);
+ gmove(n->type, nn->type, D_TREE, &nod, result, nn);
+ regfree(lg);
+ break;
+
+ case OFUNC:
+ v = argoff;
+ inargs++;
+ gargs(r);
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ inargs--;
+ doinc(r, POST);
+ doinc(l, POST);
+ gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
+ regfree(lg);
+ if(inargs)
+ adjsp(v - argoff);
+ if(result != D_NONE) {
+ lg = regret(n->type);
+ gmove(n->type, nn->type, lg, n, result, nn);
+ }
+ break;
+
+ case OLDIV:
+ case OLMOD:
+ case ODIV:
+ case OMOD:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto binop;
+ if(r->addable >= INDEXED && r->complex < FNX) {
+ lg = regpair(result);
+ cgen(l, lg, l);
+ rg = D_TREE;
+ } else {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regpair(result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ rg = D_TOS;
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ if(o == OMOD || o == OLMOD)
+ gmove(l->type, nn->type, lg+1, l, result, nn);
+ else
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(lg+1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ if(l->op == OCONST)
+ if(mulcon(r, l, result, nn))
+ break;
+ if(r->op == OCONST)
+ if(mulcon(l, r, result, nn))
+ break;
+ if(debug['M'])
+ print("%L multiply\n", n->lineno);
+ goto binop;
+
+ case OAND:
+ if(r->op == OCONST)
+ if(typeil[n->type->etype])
+ if(l->op == OCAST) {
+ if(typec[l->left->type->etype])
+ if(!(r->vconst & ~0xff)) {
+ l = l->left;
+ goto binop;
+ }
+ if(typeh[l->left->type->etype])
+ if(!(r->vconst & ~0xffff)) {
+ l = l->left;
+ goto binop;
+ }
+ }
+ goto binop;
+
+ case OADD:
+ if(result == D_TOS)
+ if(r->addable >= INDEXED)
+ if(l->op == OCONST)
+ if(typeil[l->type->etype]) {
+ v = l->vconst;
+ if(v > -32768 && v < 32768) {
+ rg = regaddr(D_NONE);
+ gmove(r->type, r->type, D_TREE, r, rg, r);
+ gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r);
+ p->to.offset = v;
+ p->to.type |= I_INDIR;
+ regfree(rg);
+ break;
+ }
+ }
+
+ case OSUB:
+ if(result == D_TOS)
+ if(l->addable >= INDEXED)
+ if(r->op == OCONST)
+ if(typeil[r->type->etype]) {
+ v = r->vconst;
+ if(v > -32768 && v < 32768) {
+ if(n->op == OSUB)
+ v = -v;
+ lg = regaddr(D_NONE);
+ gmove(l->type, l->type, D_TREE, l, lg, l);
+ gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l);
+ p->to.offset = v;
+ p->to.type |= I_INDIR;
+ regfree(lg);
+ break;
+ }
+ }
+ goto binop;
+
+ case OOR:
+ case OXOR:
+ binop:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ if(o == OXOR) {
+ rg = regalloc(r->type, D_NONE);
+ gmove(r->type, r->type, D_TOS, r, rg, r);
+ gopcode(o, n->type, rg, r, lg, l);
+ regfree(rg);
+ } else
+ gopcode(o, n->type, D_TOS, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OADDR && (o == OADD || o == OSUB))
+ lg = regaddr(result);
+ else
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ rg = eval(r, D_NONE);
+ } else {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ }
+ if(o == OXOR) {
+ if(rg == D_TREE) {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ }
+ if(rg == D_TOS) {
+ rg = regalloc(r->type, D_NONE);
+ gmove(r->type, r->type, D_TOS, r, rg, r);
+ }
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case OASHL:
+ if(r->op == OCONST)
+ if(shlcon(l, r, result, nn))
+ break;
+ case OLSHR:
+ case OASHR:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+
+ if(l->complex >= FNX && r->complex >= FNX) {
+ cgen(r, D_TOS, r);
+ v = argoff;
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ adjsp(v - argoff);
+ rg = regalloc(r->type, D_NONE);
+ gopcode(OAS, r->type, D_TOS, r, rg, r);
+ gopcode(n->op, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ v = vconst(r);
+ if(v <= 0 || v > 8) {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ } else
+ rg = eval(r, D_NONE);
+ } else {
+ rg = regalloc(r->type, D_NONE);
+ cgen(r, rg, r);
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ }
+ gopcode(o, n->type, rg, r, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ regfree(rg);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ lg = regalloc(l->type, result);
+ cgen(l, lg, l);
+ gopcode(o, l->type, D_NONE, Z, lg, l);
+ gmove(n->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+
+ case OADDR:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ if(l->op == OINDEX && l->scale == 4 && result != D_TOS) {
+ /* index scaled by 1, add is better */
+ nod = *l;
+ nod.op = OADD;
+ nod.addable = 0;
+ cgen(&nod, result, nn);
+ break;
+ }
+ lcgen(l, result, nn);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(result == D_NONE) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, result, nn, Z);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, result, nn, Z);
+ if(result == D_NONE)
+ patch(p, pc);
+ break;
+
+ case OCOMMA:
+ cgen(l, D_NONE, l);
+ doinc(l, POST);
+ doinc(r, PRE);
+ cgen(r, result, nn);
+ break;
+
+ case ONOT:
+ if(result == D_NONE) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, result, nn, Z);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ if(typefd[n->type->etype]) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, rg, l);
+ gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
+ gmove(l->type, l->type, rg, l, lg, l);
+ regfree(rg);
+ } else {
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
+ }
+ regfree(lg);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(D_NONE);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ if(typefd[n->type->etype]) {
+ rg = regalloc(n->type, D_NONE);
+ gmove(l->type, l->type, lg, l, rg, l);
+ gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
+ gmove(l->type, l->type, rg, l, lg, l);
+ regfree(rg);
+ } else {
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
+ }
+ if(result != D_NONE)
+ gmove(l->type, nn->type, lg, l, result, nn);
+ regfree(lg);
+ break;
+
+ bitinc:
+ rg = regaddr(D_NONE);
+ lg = regalloc(tfield, D_NONE);
+ if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) {
+ g = bitload(l, lg, rg, D_NONE, nn);
+ if(nn != Z)
+ gmove(l->type, nn->type, g, l, result, nn);
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), g, n);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+ g = bitload(l, lg, rg, result, nn);
+ if(v < 0)
+ gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
+ else
+ gopcode(o, n->type, D_CONST, nodconst(v), g, n);
+ if(result != D_NONE)
+ gmove(l->type, nn->type, g, l, result, nn);
+ bitstore(l, g, rg, lg, D_NONE, nn);
+ break;
+ }
+}
+
+void
+lcgen(Node *n, int result, Node *nn)
+{
+ Node rn;
+ Prog *p1;
+ int lg;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "lcgen");
+ }
+ if(nn == Z) {
+ nn = &rn;
+ nn->type = types[TIND];
+ }
+ switch(n->op) {
+ case OCOMMA:
+ cgen(n->left, D_NONE, n->left);
+ doinc(n->left, POST);
+ doinc(n->right, PRE);
+ lcgen(n->right, result, nn);
+ break;
+
+ case OCOND:
+ doinc(n->left, PRE);
+ boolgen(n->left, 1, D_NONE, Z, n->left);
+ p1 = p;
+
+ inargs++;
+ doinc(n->right->left, PRE);
+ lcgen(n->right->left, result, nn);
+ doinc(n->right->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(n->right->right, PRE);
+ lcgen(n->right->right, result, nn);
+ doinc(n->right->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OIND:
+ if(n->addable >= INDEXED) {
+ if(result >= D_A0 && result < D_A0+NREG) {
+ gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
+ break;
+ }
+ if(result == D_TOS) {
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
+ break;
+ }
+ }
+ cgen(n->left, result, nn);
+ break;
+
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ if(result >= D_A0 && result < D_A0+NREG) {
+ gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
+ break;
+ }
+ if(result == D_TOS) {
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
+ break;
+ }
+ lg = regaddr(result);
+ gopcode(OADDR, types[TLONG], D_TREE, n, lg, nn);
+ gopcode(OAS, nn->type, lg, nn, result, nn);
+ regfree(lg);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ boolgen(n, true, D_NONE, Z, Z);
+}
+
+void
+boolgen(Node *n, int true, int result, Node *nn, Node *post)
+{
+ Prog *p1, *p2;
+ Node *l, *r;
+ int lg, rg, fp, o;
+ long v;
+
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R\n", result);
+ prtree(n, "boolgen");
+ }
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ lg = eval(n, result);
+ if(lg >= D_A0 && lg < D_A0+NREG) {
+ rg = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], lg, n, rg, Z);
+ regfree(rg);
+ } else
+ gopcode(OTST, n->type, D_NONE, Z, lg, n);
+ regfree(lg);
+ o = ONE;
+ fp = typefd[n->type->etype];
+ goto genbool;
+
+ case OCONST:
+ fp = vconst(n);
+ if(!true)
+ fp = !fp;
+ gbranch(OGOTO);
+ if(fp) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case ONOT:
+ boolgen(l, !true, result, nn, post);
+ break;
+
+ case OCOND:
+ doinc(l, PRE);
+ boolgen(l, 1, D_NONE, Z, l);
+ p1 = p;
+
+ inargs++;
+ doinc(r->left, PRE);
+ boolgen(r->left, true, result, nn, r->left);
+ if(result != D_NONE) {
+ doinc(r->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ boolgen(r->right, !true, result, nn, r->right);
+ doinc(r->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+ }
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(r->right, PRE);
+ boolgen(r->right, !true, result, nn, r->right);
+ patch(p2, pc);
+ p2 = p;
+ if(doinc(post, POST|TEST)) {
+ lg = regalloc(types[TSHORT], D_NONE);
+ gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
+ doinc(post, POST);
+ gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
+ regfree(lg);
+ }
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ doinc(l, PRE);
+ boolgen(l, true, D_NONE, Z, l);
+ p1 = p;
+ inargs++;
+ doinc(r, PRE);
+ boolgen(r, !true, D_NONE, Z, r);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ doinc(l, PRE);
+ boolgen(l, !true, D_NONE, Z, l);
+ p1 = p;
+ inargs++;
+ doinc(r, PRE);
+ boolgen(r, !true, D_NONE, Z, r);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ inargs--;
+ goto com;
+
+ case OEQ:
+ case ONE:
+ if(vconst(l) == 0) {
+ if(n->op == ONE) {
+ boolgen(r, true, result, nn, post);
+ break;
+ }
+ boolgen(r, !true, result, nn, post);
+ break;
+ }
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ fp = typefd[r->type->etype];
+ if(l->op == OCONST) {
+ v = vconst(l);
+ if(v == 0) { /* tst instruction */
+ o = invrel[relindex(n->op)];
+ rg = eval(r, result);
+ gopcode(OTST, r->type, D_NONE, Z, rg, r);
+ regfree(rg);
+ goto genbool;
+ }
+ if(!fp) { /* cmpi and movq, saves about .5% both time and space */
+ if(v < 128 && v >= -128 &&
+ ewidth[r->type->etype] == SZ_LONG) {
+ rg = eval(r, result);
+ lg = regalloc(l->type, D_NONE);
+ cgen(l, lg, l);
+ o = n->op;
+ gopcode(o, l->type, lg, l, rg, r);
+ regfree(lg);
+ regfree(rg);
+ goto genbool;
+ }
+ o = invrel[relindex(n->op)];
+ rg = eval(r, result);
+ gopcode(o, r->type, rg, r, D_TREE, l);
+ regfree(rg);
+ goto genbool;
+ }
+ }
+ lg = D_TOS;
+ if(r->complex < FNX)
+ lg = regalloc(l->type, lg);
+ cgen(l, lg, l);
+ v = argoff;
+ rg = eval(r, result);
+ if(lg == D_TOS) {
+ adjsp(v - argoff);
+ lg = regalloc(l->type, lg);
+ gopcode(OAS, l->type, D_TOS, l, lg, l);
+ }
+ o = n->op;
+ gopcode(o, l->type, lg, l, rg, r);
+ regfree(lg);
+ regfree(rg);
+
+ genbool:
+ if(true)
+ o = comrel[relindex(o)];
+ if(doinc(post, POST|TEST)) {
+ lg = regalloc(types[TSHORT], D_NONE);
+ gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
+ doinc(post, POST);
+ gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
+ regfree(lg);
+ }
+ gbranch(o);
+ if(fp)
+ fpbranch();
+
+ com:
+ if(result == D_NONE)
+ break;
+ p1 = p;
+ gopcode(OAS, nn->type, D_CONST, nodconst(1), result, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nn->type, D_CONST, nodconst(0), result, nn);
+ patch(p2, pc);
+ break;
+ }
+}
+
+void
+sugen(Node *n, int result, Node *nn, long w)
+{
+ long s, v, o;
+ int lg, rg, ng;
+ Prog *p1;
+ Node *l, *r, nod;
+ Type *t;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ if(result == D_TREE)
+ prtree(nn, "result");
+ else
+ print("result = %R width = %ld\n", result, w);
+ prtree(n, "sugen");
+ }
+ s = argoff;
+ if(result == D_TREE) {
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ }
+
+ if(n->addable >= INDEXED && n->op != OCONST)
+ goto copy;
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in sugen: %O", n->op);
+ break;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(result == D_NONE) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ lg = regaddr(D_NONE);
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ if(result == D_TREE) {
+ lcgen(nn, lg, Z);
+ } else
+ diag(n, "unknown su result: %R", result);
+
+ gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst>>32)),
+ lg|I_INDINC, n);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst)),
+ lg|I_INDINC, n);
+ regfree(lg);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, D_TREE, nodrat, l->type->width);
+ if(result != D_NONE) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += r->vconst;
+ nod.type = n->type;
+ sugen(&nod, result, nn, w);
+ }
+ break;
+
+ case OIND:
+ if(result == D_NONE) {
+ nullwarn(n->left, Z);
+ break;
+ }
+ goto copy;
+
+ case OSTRUCT:
+ lg = nodalloc(types[TIND], result, &nod);
+ nod.lineno = n->lineno;
+ if(result == D_TREE)
+ lcgen(nn, lg, Z);
+ else
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ diag(n, "unknown su result: %R", result);
+ o = 0;
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ nod.type = t;
+ if(l->complex < FNX) {
+ nod.xoffset = 0;
+ if(o != t->offset) {
+ gopcode(OADD, types[TIND], D_CONST,
+ nodconst(t->offset-o), lg, Z);
+ o = t->offset;
+ }
+ cgen(l, D_TREE, &nod);
+ continue;
+ }
+ nod.xoffset = t->offset - o;
+ gopcode(OAS, types[TIND], lg, Z, D_TOS, Z);
+ s = argoff;
+ if(typesuv[t->etype]) {
+ sugen(l, D_TREE, nodrat, t->width);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, D_TREE, &nod, t->width);
+ continue;
+ }
+ rg = regalloc(t, D_NONE);
+ cgen(l, rg, l);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
+ gopcode(OAS, t, rg, Z, D_TREE, &nod);
+ regfree(rg);
+ }
+ regfree(lg);
+ break;
+
+ case OAS:
+ if(result == D_NONE) {
+ sugen(n->right, D_TREE, n->left, w);
+ break;
+ }
+ sugen(n->right, D_TREE, nodrat, w); /* could do better */
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, D_TREE, n->left, w);
+ sugen(nodrat, result, nn, w);
+ break;
+
+ case OFUNC:
+ if(result == D_NONE) {
+ sugen(n, D_TREE, nodrat, w);
+ break;
+ }
+ inargs++;
+ /* prepare zero-th arg: address of result */
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ v = argoff;
+ gargs(n->right);
+ gopcode(OADDR, types[TSHORT], D_NONE, nn, result, nn);
+ p->to.type = D_STACK;
+ p->to.offset = argoff - v;
+ } else
+ if(result == D_TREE) {
+ v = argoff;
+ gargs(n->right);
+ if(nn->complex >= FNX) {
+ rg = regalloc(types[TIND], regret(types[TIND]));
+ lcgen(nn, rg, Z);
+ gopcode(OAS, types[TIND], rg, Z, D_TOS, Z);
+ regfree(rg);
+ } else
+ lcgen(nn, D_TOS, Z);
+ } else {
+ diag(n, "unknown result in FUNC sugen");
+ break;
+ }
+ argoff += types[TIND]->width;
+ l = n->left;
+ lg = D_TREE;
+ if(l->addable < INDEXED) {
+ lg = regaddr(result);
+ lcgen(l, lg, Z);
+ lg |= I_INDIR;
+ }
+ inargs--;
+ doinc(n->right, POST);
+ doinc(n->left, POST);
+ gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
+ regfree(lg);
+ if(inargs)
+ adjsp(v - argoff);
+ break;
+
+ case OCOND:
+ doinc(n->left, PRE);
+ boolgen(n->left, 1, D_NONE, Z, n->left);
+ p1 = p;
+
+ inargs++;
+ doinc(n->right->left, PRE);
+ sugen(n->right->left, result, nn, w);
+ doinc(n->right->left, POST);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+
+ doinc(n->right->right, PRE);
+ sugen(n->right->right, result, nn, w);
+ doinc(n->right->right, POST);
+ patch(p1, pc);
+ inargs--;
+ break;
+
+ case OCOMMA:
+ cgen(n->left, D_NONE, n->left);
+ doinc(n->left, POST);
+ doinc(n->right, PRE);
+ sugen(n->right, result, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(result == D_NONE)
+ return;
+ rg = regaddr(D_NONE);
+ lcgen(n, rg, Z);
+
+ lg = regaddr(D_NONE);
+ if(result == D_TOS) {
+ adjsp(s - argoff + w);
+ gopcode(OADDR, types[TIND], result, nn, lg, n);
+ } else
+ if(result == D_TREE) {
+ if(nn->complex >= FNX) {
+ gopcode(OAS, types[TIND], rg, n, D_TOS, n);
+ s = argoff;
+ lcgen(nn, lg, Z);
+ adjsp(s - argoff);
+ gopcode(OAS, types[TIND], D_TOS, n, rg, n);
+ } else
+ lcgen(nn, lg, Z);
+ } else
+ diag(n, "unknown su result: %R", result);
+
+ if(w % SZ_LONG)
+ diag(Z, "sucopy width not 0%%%d", SZ_LONG);
+ v = w / SZ_LONG;
+ if(v & 1) {
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ v--;
+ }
+ if(v > 6) {
+ ng = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(v/2-1), ng, n);
+ v = pc;
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ gbranch(OGT);
+ patch(p, v);
+ p->from.type = ng;
+ p->as = ADBF;
+ regfree(ng);
+ } else
+ while(v > 0) {
+ gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
+ v--;
+ }
+
+ regfree(lg);
+ regfree(rg);
+}
diff --git a/utils/2c/enam.c b/utils/2c/enam.c
new file mode 100644
index 00000000..be6917af
--- /dev/null
+++ b/utils/2c/enam.c
@@ -0,0 +1,425 @@
+char *anames[] =
+{
+ "XXX",
+ "ABCD",
+ "ADDB",
+ "ADDL",
+ "ADDW",
+ "ADDXB",
+ "ADDXL",
+ "ADDXW",
+ "ADJSP",
+ "ANDB",
+ "ANDL",
+ "ANDW",
+ "ASLB",
+ "ASLL",
+ "ASLW",
+ "ASRB",
+ "ASRL",
+ "ASRW",
+ "BCASE",
+ "BCC",
+ "BCHG",
+ "BCLR",
+ "BCS",
+ "BEQ",
+ "BFCHG",
+ "BFCLR",
+ "BFEXTS",
+ "BFEXTU",
+ "BFFFO",
+ "BFINS",
+ "BFSET",
+ "BFTST",
+ "BGE",
+ "BGT",
+ "BHI",
+ "BKPT",
+ "BLE",
+ "BLS",
+ "BLT",
+ "BMI",
+ "BNE",
+ "BPL",
+ "BRA",
+ "BSET",
+ "BSR",
+ "BTST",
+ "BVC",
+ "BVS",
+ "CALLM",
+ "CAS2B",
+ "CAS2L",
+ "CAS2W",
+ "CASB",
+ "CASEW",
+ "CASL",
+ "CASW",
+ "CHK2B",
+ "CHK2L",
+ "CHK2W",
+ "CHKL",
+ "CHKW",
+ "CLRB",
+ "CLRL",
+ "CLRW",
+ "CMP2B",
+ "CMP2L",
+ "CMP2W",
+ "CMPB",
+ "CMPL",
+ "CMPW",
+ "DATA",
+ "DBCC",
+ "DBCS",
+ "DBEQ",
+ "DBF",
+ "DBGE",
+ "DBGT",
+ "DBHI",
+ "DBLE",
+ "DBLS",
+ "DBLT",
+ "DBMI",
+ "DBNE",
+ "DBPL",
+ "DBT",
+ "DBVC",
+ "DBVS",
+ "DIVSL",
+ "DIVSW",
+ "DIVUL",
+ "DIVUW",
+ "END",
+ "EORB",
+ "EORL",
+ "EORW",
+ "EXG",
+ "EXTBL",
+ "EXTBW",
+ "EXTWL",
+ "FABSB",
+ "FABSD",
+ "FABSF",
+ "FABSL",
+ "FABSW",
+ "FACOSB",
+ "FACOSD",
+ "FACOSF",
+ "FACOSL",
+ "FACOSW",
+ "FADDB",
+ "FADDD",
+ "FADDF",
+ "FADDL",
+ "FADDW",
+ "FASINB",
+ "FASIND",
+ "FASINF",
+ "FASINL",
+ "FASINW",
+ "FATANB",
+ "FATAND",
+ "FATANF",
+ "FATANHB",
+ "FATANHD",
+ "FATANHF",
+ "FATANHL",
+ "FATANHW",
+ "FATANL",
+ "FATANW",
+ "FBEQ",
+ "FBF",
+ "FBGE",
+ "FBGT",
+ "FBLE",
+ "FBLT",
+ "FBNE",
+ "FBT",
+ "FCMPB",
+ "FCMPD",
+ "FCMPF",
+ "FCMPL",
+ "FCMPW",
+ "FCOSB",
+ "FCOSD",
+ "FCOSF",
+ "FCOSHB",
+ "FCOSHD",
+ "FCOSHF",
+ "FCOSHL",
+ "FCOSHW",
+ "FCOSL",
+ "FCOSW",
+ "FDBEQ",
+ "FDBF",
+ "FDBGE",
+ "FDBGT",
+ "FDBLE",
+ "FDBLT",
+ "FDBNE",
+ "FDBT",
+ "FDIVB",
+ "FDIVD",
+ "FDIVF",
+ "FDIVL",
+ "FDIVW",
+ "FETOXB",
+ "FETOXD",
+ "FETOXF",
+ "FETOXL",
+ "FETOXM1B",
+ "FETOXM1D",
+ "FETOXM1F",
+ "FETOXM1L",
+ "FETOXM1W",
+ "FETOXW",
+ "FGETEXPB",
+ "FGETEXPD",
+ "FGETEXPF",
+ "FGETEXPL",
+ "FGETEXPW",
+ "FGETMANB",
+ "FGETMAND",
+ "FGETMANF",
+ "FGETMANL",
+ "FGETMANW",
+ "FINTB",
+ "FINTD",
+ "FINTF",
+ "FINTL",
+ "FINTRZB",
+ "FINTRZD",
+ "FINTRZF",
+ "FINTRZL",
+ "FINTRZW",
+ "FINTW",
+ "FLOG10B",
+ "FLOG10D",
+ "FLOG10F",
+ "FLOG10L",
+ "FLOG10W",
+ "FLOG2B",
+ "FLOG2D",
+ "FLOG2F",
+ "FLOG2L",
+ "FLOG2W",
+ "FLOGNB",
+ "FLOGND",
+ "FLOGNF",
+ "FLOGNL",
+ "FLOGNP1B",
+ "FLOGNP1D",
+ "FLOGNP1F",
+ "FLOGNP1L",
+ "FLOGNP1W",
+ "FLOGNW",
+ "FMODB",
+ "FMODD",
+ "FMODF",
+ "FMODL",
+ "FMODW",
+ "FMOVEB",
+ "FMOVED",
+ "FMOVEF",
+ "FMOVEL",
+ "FMOVEM",
+ "FMOVEMC",
+ "FMOVEW",
+ "FMULB",
+ "FMULD",
+ "FMULF",
+ "FMULL",
+ "FMULW",
+ "FNEGB",
+ "FNEGD",
+ "FNEGF",
+ "FNEGL",
+ "FNEGW",
+ "FREMB",
+ "FREMD",
+ "FREMF",
+ "FREML",
+ "FREMW",
+ "FRESTORE",
+ "FSAVE",
+ "FSCALEB",
+ "FSCALED",
+ "FSCALEF",
+ "FSCALEL",
+ "FSCALEW",
+ "FSEQ",
+ "FSF",
+ "FSGE",
+ "FSGT",
+ "FSINB",
+ "FSIND",
+ "FSINF",
+ "FSINHB",
+ "FSINHD",
+ "FSINHF",
+ "FSINHL",
+ "FSINHW",
+ "FSINL",
+ "FSINW",
+ "FSLE",
+ "FSLT",
+ "FSNE",
+ "FSQRTB",
+ "FSQRTD",
+ "FSQRTF",
+ "FSQRTL",
+ "FSQRTW",
+ "FST",
+ "FSUBB",
+ "FSUBD",
+ "FSUBF",
+ "FSUBL",
+ "FSUBW",
+ "FTANB",
+ "FTAND",
+ "FTANF",
+ "FTANHB",
+ "FTANHD",
+ "FTANHF",
+ "FTANHL",
+ "FTANHW",
+ "FTANL",
+ "FTANW",
+ "FTENTOXB",
+ "FTENTOXD",
+ "FTENTOXF",
+ "FTENTOXL",
+ "FTENTOXW",
+ "FTSTB",
+ "FTSTD",
+ "FTSTF",
+ "FTSTL",
+ "FTSTW",
+ "FTWOTOXB",
+ "FTWOTOXD",
+ "FTWOTOXF",
+ "FTWOTOXL",
+ "FTWOTOXW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "ILLEG",
+ "INSTR",
+ "JMP",
+ "JSR",
+ "LEA",
+ "LINKL",
+ "LINKW",
+ "LOCATE",
+ "LONG",
+ "LSLB",
+ "LSLL",
+ "LSLW",
+ "LSRB",
+ "LSRL",
+ "LSRW",
+ "MOVB",
+ "MOVEM",
+ "MOVEPL",
+ "MOVEPW",
+ "MOVESB",
+ "MOVESL",
+ "MOVESW",
+ "MOVL",
+ "MOVW",
+ "MULSL",
+ "MULSW",
+ "MULUL",
+ "MULUW",
+ "NAME",
+ "NBCD",
+ "NEGB",
+ "NEGL",
+ "NEGW",
+ "NEGXB",
+ "NEGXL",
+ "NEGXW",
+ "NOP",
+ "NOTB",
+ "NOTL",
+ "NOTW",
+ "ORB",
+ "ORL",
+ "ORW",
+ "PACK",
+ "PEA",
+ "RESET",
+ "ROTLB",
+ "ROTLL",
+ "ROTLW",
+ "ROTRB",
+ "ROTRL",
+ "ROTRW",
+ "ROXLB",
+ "ROXLL",
+ "ROXLW",
+ "ROXRB",
+ "ROXRL",
+ "ROXRW",
+ "RTD",
+ "RTE",
+ "RTM",
+ "RTR",
+ "RTS",
+ "SBCD",
+ "SCC",
+ "SCS",
+ "SEQ",
+ "SF",
+ "SGE",
+ "SGT",
+ "SHI",
+ "SLE",
+ "SLS",
+ "SLT",
+ "SMI",
+ "SNE",
+ "SPL",
+ "ST",
+ "STOP",
+ "SUBB",
+ "SUBL",
+ "SUBW",
+ "SUBXB",
+ "SUBXL",
+ "SUBXW",
+ "SVC",
+ "SVS",
+ "SWAP",
+ "SYS",
+ "TAS",
+ "TEXT",
+ "TRAP",
+ "TRAPCC",
+ "TRAPCS",
+ "TRAPEQ",
+ "TRAPF",
+ "TRAPGE",
+ "TRAPGT",
+ "TRAPHI",
+ "TRAPLE",
+ "TRAPLS",
+ "TRAPLT",
+ "TRAPMI",
+ "TRAPNE",
+ "TRAPPL",
+ "TRAPT",
+ "TRAPV",
+ "TRAPVC",
+ "TRAPVS",
+ "TSTB",
+ "TSTL",
+ "TSTW",
+ "UNLK",
+ "UNPK",
+ "WORD",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/2c/gc.h b/utils/2c/gc.h
new file mode 100644
index 00000000..ab30649e
--- /dev/null
+++ b/utils/2c/gc.h
@@ -0,0 +1,357 @@
+#include "../cc/cc.h"
+#include "../2c/2.out.h"
+/*
+ * 2c/68020
+ * Motorola 68020
+ */
+
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+
+#define ALLOP OEND
+#define NRGN 300
+#define FNX 100
+#define INDEXED 9
+
+#define PRE 1
+#define POST 2
+#define TEST 4
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Txt Txt;
+typedef struct Cases Case;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Var Var;
+typedef struct Multab Multab;
+typedef struct C1 C1;
+typedef struct Index Index;
+
+struct Index
+{
+ int o0;
+ int o1;
+};
+
+EXTERN struct
+{
+ Node* regtree;
+ Node* basetree;
+ short scale;
+} idx;
+
+struct Adr
+{
+ long displace;
+ long offset;
+
+ char sval[NSNAME];
+ double dval;
+
+ Sym* sym;
+ short type;
+ short index;
+ short scale;
+ short field;
+ short etype;
+};
+#define A ((Adr*)0)
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Txt
+{
+ short movas;
+ short postext;
+ char preclr;
+};
+
+struct Cases
+{
+ long val;
+ long label;
+ uchar def;
+ Case* link;
+};
+#define C ((Case*)0)
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char type;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ ulong regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Rgn
+{
+ Reg* enter;
+ short costr;
+ short costa;
+ short varno;
+ short regno;
+};
+
+struct Multab
+{
+ short val;
+ char code[6];
+};
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 8
+#define CREF 5
+#define CTEST 2
+#define CXREF 3
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits addrs;
+EXTERN ulong regbits;
+
+#define B_INDIR (1<<0)
+#define B_ADDR (1<<1)
+EXTERN int mvbits;
+EXTERN int changer;
+EXTERN int changea;
+
+EXTERN Txt txt[NTYPE][NTYPE];
+EXTERN short opxt[ALLOP][NTYPE];
+EXTERN Txt* txtp;
+EXTERN int multabsize;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+
+EXTERN long argoff;
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN long continpc;
+EXTERN Prog* firstp;
+EXTERN Reg* firstr;
+EXTERN int inargs;
+EXTERN Prog* lastp;
+EXTERN int retok;
+EXTERN long mnstring;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN long nrathole;
+EXTERN long nstatic;
+EXTERN int nregion;
+EXTERN long nstring;
+EXTERN int nvar;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Sym* symstatic;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+EXTERN Prog zprog;
+
+EXTERN uchar regused[NREG];
+EXTERN uchar aregused[NREG];
+EXTERN uchar fregused[NREG];
+EXTERN uchar regbase[I_MASK];
+EXTERN long exregoffset;
+EXTERN long exaregoffset;
+EXTERN long exfregoffset;
+
+extern char* anames[];
+extern Multab multab[];
+
+void cgen(Node*, int, Node*);
+void lcgen(Node*, int, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, int, Node*, Node*);
+void sugen(Node*, int, Node*, long);
+
+
+void listinit(void);
+int Bconv(Fmt*);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Xconv(Fmt*);
+int Dconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int findtst(Reg*, Prog*, int);
+int setcc(Prog*, Prog*);
+int compat(Adr*, Adr*);
+int aregind(Adr*);
+int asize(int);
+int usedin(int, Adr*);
+Reg* findccr(Reg*);
+int setccr(Prog*);
+Reg* findop(Reg*, int, int, int);
+int regtyp(int);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+int copyas(Adr*, Adr*);
+int tasas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, Prog*, int);
+
+ulong RtoB(int);
+ulong AtoB(int);
+ulong FtoB(int);
+int BtoR(ulong);
+int BtoA(ulong);
+int BtoF(ulong);
+
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, ulong, int);
+void addreg(Adr*, int);
+
+void codgen(Node*, Node*);
+void gen(Node*);
+void usedset(Node*, int);
+void noretval(int);
+Node* nodconst(long);
+
+int swcmp(const void*, const void*);
+void doswit(int, Node*);
+void swit1(C1*, int, long, int, Node*);
+void cas(void);
+int bitload(Node*, int, int, int, Node*);
+void bitstore(Node*, int, int, int, int, Node*);
+long outstring(char*, long);
+int doinc(Node*, int);
+void setsp(void);
+void adjsp(long);
+int simplv(Node*);
+int eval(Node*, int);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+int nodalloc(Type*, int, Node*);
+int mulcon(Node*, Node*, int, Node*);
+int shlcon(Node*, Node*, int, Node*);
+int mulcon1(Node*, long, int, Node*);
+void nullwarn(Node*, Node*);
+
+void tindex(Type*, Type*);
+void ginit(void);
+void gclean(void);
+void oinit(int, int, int, int, int, int);
+Prog* prg(void);
+void nextpc(void);
+void gargs(Node*);
+void naddr(Node*, Adr*, int);
+int regalloc(Type*, int);
+int regaddr(int);
+int regpair(int);
+int regret(Type*);
+void regfree(int);
+void gmove(Type*, Type*, int, Node*, int, Node*);
+void gopcode(int, Type*, int, Node*, int, Node*);
+void asopt(void);
+int relindex(int);
+void gbranch(int);
+void fpbranch(void);
+void patch(Prog*, long);
+void gpseudo(int, Sym*, int, long);
+void gpseudotree(int, Sym*, Node*);
+
+void indx(Node*);
+void bcomplex(Node*);
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+#pragma varargck type "R" int
+#pragma varargck type "X" Index
diff --git a/utils/2c/list.c b/utils/2c/list.c
new file mode 100644
index 00000000..2b3cb4da
--- /dev/null
+++ b/utils/2c/list.c
@@ -0,0 +1,384 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('X', Xconv);
+ fmtinstall('B', Bconv);
+}
+
+static Index
+indexv(int i, int j)
+{
+ Index x;
+
+ x.o0 = i;
+ x.o1 = j;
+ return x;
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[20];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ sprint(str, " %A %D,%D", p->as, &p->from, &p->to);
+ if(p->from.field) {
+ sprint(s, ",%d,%d", p->to.field, p->from.field);
+ strcat(str, s);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int r;
+
+ r = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[r]);
+}
+
+int
+Xconv(Fmt *fp)
+{
+ char str[20], s[10];
+ Index x;
+ int i;
+
+ x = va_arg(fp->args, Index);
+ str[0] = 0;
+ i = x.o0 & D_MASK;
+ if(i != D_NONE) {
+ sprint(str, "(%R.", i);
+ i = x.o1;
+ sprint(s, "%c*%c)",
+ "WWWWLLLL"[i],
+ "12481248"[i]);
+ strcat(str, s);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i, j;
+ long d;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->index;
+ if(i != D_NONE) {
+ a->index = D_NONE;
+ d = a->displace;
+ j = a->scale;
+ a->displace = 0;
+ switch(i & I_MASK) {
+ default:
+ sprint(str, "???%ld(%D%X)", d, a, indexv(i, j));
+ break;
+
+ case I_INDEX1:
+ sprint(str, "%D%X", a, indexv(i, a->scale));
+ break;
+
+ case I_INDEX2:
+ if(d)
+ sprint(str, "%ld(%D)%X", d, a, indexv(i, j));
+ else
+ sprint(str, "(%D)%X", a, indexv(i, j));
+ break;
+
+ case I_INDEX3:
+ if(d)
+ sprint(str, "%ld(%D%X)", d, a, indexv(i, j));
+ else
+ sprint(str, "(%D%X)", a, indexv(i, j));
+ break;
+ }
+ a->displace = d;
+ a->index = i;
+ goto out;
+ }
+ i = a->type;
+ j = i & I_MASK;
+ if(j) {
+ a->type = i & D_MASK;
+ d = a->offset;
+ a->offset = 0;
+ switch(j) {
+ case I_INDINC:
+ sprint(str, "(%D)+", a);
+ break;
+
+ case I_INDDEC:
+ sprint(str, "-(%D)", a);
+ break;
+
+ case I_INDIR:
+ if(a->type == D_CONST)
+ sprint(str, "%ld", d);
+ else
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_ADDR:
+ a->offset = d;
+ sprint(str, "$%D", a);
+ break;
+ }
+ a->type = i;
+ a->offset = d;
+ goto out;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", a->sym->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_STACK:
+ sprint(str, "TOS+%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ goto out;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ goto out;
+ }
+ if(a->displace) {
+ sprint(s, "/%ld", a->displace);
+ strcat(str, s);
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_R0 && r < D_R0+NREG)
+ sprint(str, "R%d", r-D_R0);
+ else
+ if(r >= D_A0 && r < D_A0+NREG)
+ sprint(str, "A%d", r-D_A0);
+ else
+ if(r >= D_F0 && r < D_F0+NREG)
+ sprint(str, "F%d", r-D_F0);
+ else
+ switch(r) {
+
+ default:
+ sprint(str, "gok(%d)", r);
+ break;
+
+ case D_NONE:
+ sprint(str, "NONE");
+ break;
+
+ case D_TOS:
+ sprint(str, "TOS");
+ break;
+
+ case D_CCR:
+ sprint(str, "CCR");
+ break;
+
+ case D_SR:
+ sprint(str, "SR");
+ break;
+
+ case D_SFC:
+ sprint(str, "SFC");
+ break;
+
+ case D_DFC:
+ sprint(str, "DFC");
+ break;
+
+ case D_CACR:
+ sprint(str, "CACR");
+ break;
+
+ case D_USP:
+ sprint(str, "USP");
+ break;
+
+ case D_VBR:
+ sprint(str, "VBR");
+ break;
+
+ case D_CAAR:
+ sprint(str, "CAAR");
+ break;
+
+ case D_MSP:
+ sprint(str, "MSP");
+ break;
+
+ case D_ISP:
+ sprint(str, "ISP");
+ break;
+
+ case D_TREE:
+ sprint(str, "TREE");
+ break;
+
+ case D_FPCR:
+ sprint(str, "FPCR");
+ break;
+
+ case D_FPSR:
+ sprint(str, "FPSR");
+ break;
+
+ case D_FPIAR:
+ sprint(str, "FPIAR");
+ break;
+
+ case D_TC:
+ sprint(str, "TC");
+ break;
+
+ case D_ITT0:
+ sprint(str, "ITT0");
+ break;
+
+ case D_ITT1:
+ sprint(str, "ITT1");
+ break;
+
+ case D_DTT0:
+ sprint(str, "DTT0");
+ break;
+
+ case D_DTT1:
+ sprint(str, "DTT1");
+ break;
+
+ case D_MMUSR:
+ sprint(str, "MMUSR");
+ break;
+ case D_URP:
+ sprint(str, "URP");
+ break;
+
+ case D_SRP:
+ sprint(str, "SRP");
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *s;
+
+ s = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = s[i] & 0xff;
+ if(c != '\\' && c != '"' && isprint(c)) {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = '0';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = ((c>>6) & 7) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = ((c>>0) & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/2c/mkfile b/utils/2c/mkfile
new file mode 100644
index 00000000..7efbd5cc
--- /dev/null
+++ b/utils/2c/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=2c
+
+OFILES=\
+ cgen.$O\
+ reg.$O\
+ txt.$O\
+ peep.$O\
+ swt.$O\
+ sgen.$O\
+ list.$O\
+ enam.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ 2.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/2c/mul.c b/utils/2c/mul.c
new file mode 100644
index 00000000..65ddda2f
--- /dev/null
+++ b/utils/2c/mul.c
@@ -0,0 +1,174 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant
+ * all sequences start with leading '0'.
+ * if sequence starts with 'i', then the
+ * leading '0' is suppressed.
+ * '0' mov r0,r1
+ * '1' sub r0,r1
+ * '2' sub r1,r0
+ * '3' add r0,r1
+ * '4' add r1,r0
+ * '5' add r0,r0
+ * '6' add r1,r1
+ * 'b' lsh $2,r0
+ * 'c' lsh $3,r0
+ * 'd'-'h' ...
+ * 'j' lsh $2,r1
+ * 'k'-'p' ...
+ */
+Multab multab[] =
+{
+ 2, "i5",
+ 3, "64",
+ 4, "i55",
+ 5, "664",
+ 6, "645",
+ 7, "c2",
+ 9, "k4",
+ 10, "6645",
+ 11, "66364",
+ 12, "6455",
+ 13, "66464",
+ 14, "6d2",
+ 15, "d2",
+ 17, "l4",
+ 18, "6d4",
+ 19, "64k4",
+ 20, "66455",
+ 21, "664664",
+ 22, "64c2",
+ 23, "44c2",
+ 24, "64c",
+ 25, "63k4",
+ 26, "64c4",
+ 27, "663e2",
+ 28, "66e2",
+ 29, "63e2",
+ 30, "6e2",
+ 31, "e2",
+ 33, "m4",
+ 34, "6e4",
+ 35, "64l4",
+ 36, "66e4",
+ 37, "664k4",
+ 38, "64k45",
+ 39, "454c2",
+ 40, "664c",
+ 41, "663k4",
+ 42, "644c4",
+ 43, "643k4",
+ 44, "664c4",
+ 45, "640d2",
+ 46, "64d2",
+ 47, "44d2",
+ 48, "64d",
+ 49, "63l4",
+ 50, "64d4",
+ 51, "640l4",
+ 52, "646d4",
+ 53, "643d4",
+ 54, "6636f2",
+ 55, "k3f2",
+ 56, "kf2",
+ 57, "k2k4",
+ 58, "636f2",
+ 59, "663f2",
+ 60, "66f2",
+ 61, "63f2",
+ 62, "6f2",
+ 63, "f2",
+ 65, "n4",
+ 66, "6f4",
+ 67, "64m4",
+ 68, "66f4",
+ 69, "664l4",
+ 70, "64l45",
+ 71, "k1f4",
+ 72, "k4c",
+ 73, "k4k4",
+ 74, "664k45",
+ 75, "6640d2",
+ 76, "664d2",
+ 77, "434d2",
+ 78, "644d2",
+ 79, "454d2",
+ 80, "664d",
+ 81, "663l4",
+ 82, "644d4",
+ 83, "643l4",
+ 84, "664d4",
+ 85, "6640l4",
+ 86, "6634l4",
+ 87, "6443d4",
+ 88, "6646d4",
+ 89, "6643d4",
+ 90, "6406e2",
+ 91, "643e2",
+ 92, "646e2",
+ 93, "640e2",
+ 94, "64e2",
+ 95, "44e2",
+ 96, "64e",
+ 97, "63m4",
+ 98, "64e4",
+ 99, "640m4",
+ 100, "646e4",
+ 200, "66f364",
+ 300, "j40jf2",
+ 400, "64kg4",
+ 500, "66h212",
+ 600, "64m4c4",
+ 700, "j4c4d2",
+ 800, "64lh4",
+ 900, "6464g4",
+ 1000, "63g2c",
+ 1100, "j4d2p4",
+ 1200, "64k4f2",
+ 1300, "j4n4b4",
+ 1400, "64j4g2",
+ 1600, "64d4e",
+ 1800, "p4c2",
+ 2000, "63g2d",
+ 2100, "l4b2o4",
+ 2200, "k4d4p4",
+ 2300, "6644h2",
+ 2400, "j4k4f4",
+ 2500, "j4e2d4",
+ 2600, "j40n4c",
+ 3100, "jd12p2",
+ 3200, "64d4f",
+ 3600, "6d1p2",
+ 3800, "e3k3g2",
+ 3900, "jf20n4",
+ 4000, "o4e2",
+ 4100, "66p455",
+ 4200, "l4c3e2",
+ 4300, "l4b1f4",
+ 4400, "64o4d4",
+ 4600, "k45h2",
+ 4700, "k3j4g2",
+ 4800, "j40d2f",
+ 5000, "l4c3m4",
+ 5100, "j40h2b",
+ 5200, "j40n4d",
+ 6000, "d1o3h2",
+ 6100, "o1l4b2",
+ 6200, "ke12p2",
+ 6400, "64d4g",
+ 7200, "66e1p2",
+ 7400, "m3m4c2",
+ 7600, "l4f3c2",
+ 7800, "kg20n4",
+ 8000, "63g2f",
+ 8100, "m2b4p4",
+ 8200, "66p4c",
+ 8700, "66f4g2",
+ 8900, "l3j4g4",
+ 9200, "k45h25",
+ 9600, "j40d2g",
+ 9800, "k4f3d4",
+};
+
+int multabsize = sizeof(multab) / sizeof(multab[0]);
diff --git a/utils/2c/peep.c b/utils/2c/peep.c
new file mode 100644
index 00000000..4bde0d40
--- /dev/null
+++ b/utils/2c/peep.c
@@ -0,0 +1,1076 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t, s;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ /*
+ * propigate move's by renaming
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVL || p->as == AFMOVEF || p->as == AFMOVED)
+ if(regtyp(p->from.type))
+ if(anyvar(&p->to)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ /*
+ * convert (A) ... A++ into (A)++
+ * and A-- ... (A) into --(A)
+ */
+ t = aregind(&p->from);
+ if(t == D_NONE)
+ goto out1;
+ s = asize(p->as);
+ if(s == 0)
+ goto out1;
+ r1 = findop(r, t, AADDL, s);
+ if(r1 != R) {
+ if(usedin(t, &p->to))
+ goto out1;
+ p->from.type += I_INDINC - I_INDIR;
+ excise(r1);
+ goto out1;
+ }
+ r1 = findop(r, t, ASUBL, s);
+ if(r1 != R) {
+ p->from.type += I_INDDEC - I_INDIR;
+ excise(r1);
+ }
+ out1:
+ t = aregind(&p->to);
+ if(t == D_NONE)
+ goto out2;
+ s = asize(p->as);
+ if(s == 0)
+ goto out2;
+ r1 = findop(r, t, AADDL, s);
+ if(r1 != R) {
+ p->to.type += I_INDINC - I_INDIR;
+ excise(r1);
+ goto out2;
+ }
+ r1 = findop(r, t, ASUBL, s);
+ if(r1 != R) {
+ if(usedin(t, &p->from))
+ goto out2;
+ p->to.type += I_INDDEC - I_INDIR;
+ excise(r1);
+ }
+ out2:
+ /*
+ * get rid of unneeded save/restore CCR
+ */
+ if(p->from.type == D_CCR) {
+ r1 = findccr(r);
+ if(r1 != R) {
+ excise(r);
+ excise(r1);
+ }
+ }
+ switch(p->as) {
+ case ATSTB:
+ case ATSTW:
+ case ATSTL:
+ if(findtst(r, r->prog, 0))
+ excise(r);
+ }
+ /*
+ * turn TSTB (A); BLT; ORB $128,(A) into TAS (A); BLT; NOP
+ */
+ if(p->as == ATSTB && (r1 = r->s1)) {
+ if((r1->prog->as == ABLT && (r2 = r1->s1)) ||
+ (r1->prog->as == ABGE && (r2 = r1->s2))) {
+ p1 = r2->prog;
+ if(p1->as == AORB)
+ if(p1->from.type == D_CONST)
+ if(p1->from.offset == 128)
+ if(r1 == uniqp(r2))
+ if(tasas(&p->to, &p1->to)) {
+ p->as = ATAS;
+ excise(r2);
+ }
+ }
+ }
+ }
+}
+
+void
+excise(Reg *r)
+{
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+/*
+ * chase backward all cc setting.
+ * returns 1 if all set same.
+ */
+int
+findtst(Reg *r0, Prog *rp, int n)
+{
+ Reg *r;
+ int c;
+
+loop:
+ n++;
+ if(n >= 10)
+ return 0;
+ for(r=r0->p2; r!=R; r=r->p2link) {
+ c = setcc(r->prog, rp);
+ if(c > 0)
+ continue;
+ if(c == 0)
+ return 0;
+ if(findtst(r, rp, n) == 0)
+ return 0;
+ }
+ r = r0->p1;
+ if(r == R)
+ return 1;
+ c = setcc(r->prog, rp);
+ if(c > 0)
+ return 1;
+ if(c == 0)
+ return 0;
+ r0 = r;
+ goto loop;
+}
+
+/*
+ * tests cc
+ * returns -1 if no change
+ * returns 1 if set the same
+ * returns 0 if set different
+ */
+int
+setcc(Prog *p, Prog *rp)
+{
+ int s;
+
+ s = asize(rp->as);
+ switch(p->as) {
+ default:
+ if(debug['P'])
+ print("unknown setcc %A\n", p->as);
+ break;
+
+ case ACMPB:
+ case ACMPW:
+ case ACMPL:
+ case ABSR:
+ return 0;
+
+ case ABRA:
+ case ABGE:
+ case ABNE:
+ case ABLE:
+ case ABEQ:
+ case ABHI:
+ case ABLS:
+ case ABMI:
+ case ABPL:
+ case ABGT:
+ case ABLT:
+ case ABCC:
+ case ABCS:
+ case APEA:
+ case ALEA:
+ case ANOP:
+
+ case AFADDD:
+ case AFMULD:
+ case AFDIVD:
+ case AFSUBD:
+ case AFADDF:
+ case AFMULF:
+ case AFDIVF:
+ case AFSUBF:
+ case AADJSP:
+ return -1;
+
+ case AADDW:
+ case AADDL:
+ case ASUBW:
+ case ASUBL:
+ case ACLRL:
+ case ACLRW:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ goto areg;
+
+ case AADDB:
+ case ASUBB:
+ case AANDB:
+ case AANDW:
+ case AANDL:
+ case AORB:
+ case AORW:
+ case AORL:
+ case AEORB:
+ case AEORW:
+ case AEORL:
+ case ALSLB:
+ case ALSLW:
+ case ALSLL:
+ case ALSRB:
+ case ALSRW:
+ case ALSRL:
+ case AASLB:
+ case AASLW:
+ case AASLL:
+ case AASRB:
+ case AASRW:
+ case AASRL:
+ case ATSTB:
+ case ATSTW:
+ case ATSTL:
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ACLRB:
+ if(asize(p->as) != s)
+ break;
+ if(compat(&rp->to, &p->to))
+ return 1;
+ break;
+
+ case AMOVW:
+ case AMOVL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ goto areg;
+ case AMOVB:
+ if(asize(p->as) != s)
+ break;
+ if(compat(&rp->to, &p->to))
+ return 1;
+ if(compat(&rp->to, &p->from))
+ return 1;
+ }
+ return 0;
+
+areg:
+ if((rp->to.type&D_MASK) == p->to.type)
+ return 0;
+ return -1;
+}
+
+int
+compat(Adr *a, Adr *b)
+{
+ int o;
+
+ if(a->index != D_NONE)
+ return 0;
+ if(b->index != D_NONE)
+ return 0;
+ o = a->type;
+ if((o >= D_R0 && o < D_R0+NREG) ||
+ (o >= D_A0 && o < D_A0+NREG))
+ return o == b->type;
+ o &= D_MASK;
+ if(o >= D_A0 && o < D_A0+NREG) {
+ if(o != (b->type&D_MASK))
+ return 0;
+ if(a->offset != b->offset)
+ return 0;
+ o = a->type & I_MASK;
+ if(o == I_INDIR) {
+ o = b->type & I_MASK;
+ if(o == I_INDIR || o == I_INDDEC)
+ return 1;
+ return 0;
+ }
+ if(o == I_INDINC) {
+ o = b->type & I_MASK;
+ if(o == I_INDIR) {
+ b->type += I_INDINC-I_INDIR;
+ return 1;
+ }
+ if(o == I_INDDEC) {
+ b->type += I_INDIR-I_INDDEC;
+ return 1;
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int
+aregind(Adr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t >= (D_A0|I_INDIR) && t < ((D_A0+NREG)|I_INDIR))
+ while(a->offset == 0 && a->index == D_NONE)
+ return t & D_MASK;
+ return D_NONE;
+}
+
+int
+asize(int a)
+{
+
+ switch(a) {
+ case AFTSTD:
+ case AFMOVED:
+ case AFADDD:
+ case AFSUBD:
+ case AFMULD:
+ case AFDIVD:
+ case AFCMPD:
+ case AFNEGD:
+ return 8;
+
+ case AFTSTF:
+ case AFMOVEF:
+ case AFADDF:
+ case AFSUBF:
+ case AFMULF:
+ case AFDIVF:
+ case AFCMPF:
+ case AFNEGF:
+
+ case ACLRL:
+ case ATSTL:
+ case AMOVL:
+ case AADDL:
+ case ASUBL:
+ case ACMPL:
+ case AANDL:
+ case AORL:
+ case AEORL:
+ case ALSLL:
+ case ALSRL:
+ case AASLL:
+ case AASRL:
+ case ANEGL:
+ return 4;
+
+ case ACLRW:
+ case ATSTW:
+ case AMOVW:
+ case AADDW:
+ case ASUBW:
+ case ACMPW:
+ case AANDW:
+ case AORW:
+ case AEORW:
+ case ALSLW:
+ case ALSRW:
+ case AASLW:
+ case AASRW:
+ case ANEGW:
+ return 2;
+
+ case ACLRB:
+ case ATSTB:
+ case AMOVB:
+ case AADDB:
+ case ASUBB:
+ case ACMPB:
+ case AANDB:
+ case AORB:
+ case AEORB:
+ case ALSLB:
+ case ALSRB:
+ case AASLB:
+ case AASRB:
+ case ANEGB:
+ return 1;
+ }
+ if(debug['P'])
+ print("unknown asize %A\n", p->as);
+ return 0;
+}
+
+int
+usedin(int t, Adr *a)
+{
+
+ if((a->type&D_MASK) == t)
+ return 1;
+ if((a->index&D_MASK) == t)
+ return 1;
+ return 0;
+}
+
+Reg*
+findccr(Reg *r)
+{
+ Prog *p;
+
+ for(;;) {
+ r = uniqs(r);
+ if(r == R)
+ break;
+ p = r->prog;
+ if(p->to.type == D_CCR)
+ return r;
+ if(setccr(p))
+ break;
+ }
+ return R;
+}
+
+int
+setccr(Prog *p)
+{
+
+ switch(p->as) {
+ case ANOP:
+ return 0;
+
+ case AADDL:
+ case AMOVL:
+ case ACLRL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ return 0;
+ }
+ return 1;
+}
+
+Reg*
+findop(Reg *r, int t, int o, int s)
+{
+ Prog *p;
+ Reg *r1;
+
+ for(;;) {
+ if(o == AADDL) {
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ if(uniqp(r1) != r)
+ break;
+ } else {
+ r1 = uniqp(r);
+ if(r1 == R)
+ break;
+ if(uniqs(r1) != r)
+ break;
+ }
+ r = r1;
+ p = r->prog;
+ if(usedin(t, &p->from))
+ break;
+ if(usedin(t, &p->to)) {
+ if(p->as == o)
+ if(p->to.type == t)
+ if(p->to.index == D_NONE)
+ if(p->from.type == D_CONST)
+ if(p->from.offset == s)
+ return r;
+ break;
+ }
+ }
+ return R;
+}
+
+int
+regtyp(int t)
+{
+
+ if(t >= D_R0 && t < D_R0+8)
+ return 1;
+ if(t >= D_A0 && t < D_A0+8)
+ return 1;
+ if(t >= D_F0 && t < D_F0+8)
+ return 1;
+ return 0;
+}
+
+int
+anyvar(Adr *a)
+{
+
+ if(regtyp(a->type))
+ return 1;
+ return 0;
+ if(a->type == D_AUTO || a->type == D_PARAM)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOVL
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1->type))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2->type))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ADIVUW: /* these set Rn and Rn+1 */
+ case ADIVUL:
+ case ADIVSW:
+ case ADIVSL:
+ case ABSR:
+ return 0;
+
+ case AFMOVED:
+ case AFMOVEF:
+ case AMOVL:
+ if(p->to.type == v1->type)
+ goto gotit;
+ }
+ if(copyau(&p->from, v2) || copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, p, 0) || copysub(&p->to, v1, v2, p, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, p, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ if(p->from.type == v2->type)
+ excise(r);
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, p, 1);
+ copysub(&p->to, v1, v2, p, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+
+ if(r->active) {
+ if(debug['P'])
+ print("copyret 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D\n", v1, v2);
+ for(; r != R; r = r->s1) {
+ if(debug['P'])
+ print("%P", r->prog);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(r->prog, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; rar return 0\n");
+ return 0;
+ case 3: /* set */
+ if(debug['P'])
+ print("; set; return 1\n");
+ return 1;
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(debug['P'])
+ print("; used and f; return 0\n");
+ return 0;
+ }
+ if(copyu(r->prog, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; substitute");
+ if(t == 4) {
+ if(debug['P'])
+ print("; used and set; return 1\n");
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(r->prog, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ if(debug['P'])
+ print("; f set used");
+ f = 1;
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+ int t;
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print("unknown op %A\n", p->as);
+ return 2;
+
+ case APEA: /* rhs addr */
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ALEA: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+ case AMOVL: /* rhs store */
+ case ACLRL:
+ case AFMOVEF:
+ case AFMOVED:
+ case AFMOVEB:
+ case AFMOVEW:
+ case AFMOVEL:
+ case ANOP:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, p, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AADDL: /* rhs rar */
+ case AADDW:
+ case AADDB:
+ case ASUBL:
+ case ASUBW:
+ case ASUBB:
+ case AANDL:
+ case AANDW:
+ case AANDB:
+ case AORL:
+ case AORW:
+ case AORB:
+ case AEORL:
+ case AEORW:
+ case AEORB:
+ case AASRL:
+ case AASRW:
+ case AASRB:
+ case AASLL:
+ case AASLW:
+ case AASLB:
+ case ALSRL:
+ case ALSRW:
+ case ALSRB:
+ case ANOTL:
+ case ANOTW:
+ case ANOTB:
+ case ANEGL:
+ case ANEGW:
+ case ANEGB:
+ case AEXTBL:
+ case AEXTWL:
+ case AEXTBW:
+
+ case AMULSL:
+ case AMULUL:
+
+ case AMOVW: /* only sets part of register */
+ case AMOVB:
+ case ACLRW:
+ case ACLRB:
+
+ case AFADDD:
+ case AFMULD:
+ case AFDIVD:
+ case AFSUBD:
+ case AFNEGD:
+ case AFADDF:
+ case AFMULF:
+ case AFDIVF:
+ case AFSUBF:
+ case AFNEGF:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ADBF: /* lhs rar */
+ if(copyas(&p->from, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case AFCMPF:
+ case AFCMPD:
+ case ATSTL:
+ case ATSTW:
+ case ATSTB:
+ case AFTSTF:
+ case AFTSTD:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, p, 1))
+ return 1;
+ return copysub(&p->to, v, s, p, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case ABRA: /* no reference */
+ case ABGE:
+ case ABNE:
+ case ABLE:
+ case ABEQ:
+ case ABHI:
+ case ABLS:
+ case ABMI:
+ case ABPL:
+ case ABGT:
+ case ABLT:
+ case ABCC:
+ case ABCS:
+
+ case AFBEQ:
+ case AFBNE:
+ case AFBGT:
+ case AFBGE:
+ case AFBLE:
+ case AFBLT:
+
+ case AADJSP:
+ case ACASEW:
+ break;
+
+ case ADIVUW: /* these set Rn and Rn+1 */
+ case ADIVUL:
+ case ADIVSW:
+ case ADIVSL:
+ t = v->type;
+ if(t == p->to.type || t == p->to.type+1)
+ return 2;
+ goto caseread;
+
+ case ARTS: /* funny */
+ t = v->type;
+ if(t == D_R0 || t == D_F0)
+ return 2;
+ if(t >= D_R0 && t < D_R0+NREG)
+ if(t-D_R0 > exregoffset)
+ return 2;
+ if(t >= D_A0 && t < D_A0+NREG)
+ if(t-D_A0 > exaregoffset)
+ return 2;
+ if(t >= D_F0 && t < D_F0+NREG)
+ if(t-D_F0 > exfregoffset)
+ return 2;
+ return 3;
+
+ case ABSR: /* funny */
+ t = v->type;
+ if(t >= D_R0 && t < D_R0+NREG)
+ if(t-D_R0 > exregoffset)
+ return 2;
+ if(t >= D_A0 && t < D_A0+NREG)
+ if(t-D_A0 > exaregoffset)
+ return 2;
+ if(t >= D_F0 && t < D_F0+NREG)
+ if(t-D_F0 > exfregoffset)
+ return 2;
+ return 3;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v->type))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM) {
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * indirect
+ */
+int
+tasas(Adr *a, Adr *v)
+{
+ int t;
+
+ if(a->index != D_NONE)
+ return 0;
+ if(v->index != D_NONE)
+ return 0;
+ t = a->type;
+ if(t < I_INDIR+D_A0 && t >= I_INDIR+D_A0+8)
+ return 0;
+ if(v->type != t)
+ return 0;
+ if(a->displace != v->displace)
+ return 0;
+ return 1;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+ int t;
+
+ if(copyas(a, v))
+ return 1;
+ t = v->type;
+ if(regtyp(t)) {
+ if((a->type & D_MASK) == t)
+ return 1;
+ if((a->index & D_MASK) == t)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, Prog *p, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_F0 && t < D_F0+8) {
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ if(t >= D_R0 && t < D_R0+8) {
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ if(!(t >= D_A0 && t < D_A0+8))
+ return 1;
+ switch(p->as) {
+ default:
+ return 1;
+
+ case AMOVL:
+ case AMOVW:
+ case ACMPL:
+ case ACMPW:
+ break;
+
+ case AADDL:
+ case AADDW:
+ case ASUBL:
+ case ASUBW:
+ if(a == &p->from && !regtyp(p->to.type))
+ return 1;
+ break;
+ }
+ if(f)
+ a->type = t;
+ return 0;
+ }
+ t = v->type;
+ if(regtyp(t)) {
+ if((a->type & D_MASK) == t) {
+ if((s->type ^ t) & ~(NREG-1))
+ return 1;
+ if(f)
+ a->type = (a->type & ~D_MASK) | s->type;
+ return 0;
+ }
+ if((a->index & D_MASK) == t) {
+ if(f)
+ a->index = (a->index & ~D_MASK) | s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/utils/2c/reg.c b/utils/2c/reg.c
new file mode 100644
index 00000000..d314096d
--- /dev/null
+++ b/utils/2c/reg.c
@@ -0,0 +1,1275 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->costr;
+ if(p2->costa > c1)
+ c1 = p2->costa;
+ c2 = p1->costr;
+ if(p1->costa > c2)
+ c2 = p1->costa;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long val, initpc, npc;
+ ulong vreg;
+ Bits bit;
+ Var *v;
+ struct {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+ regbits = RtoB(0) | /* return reg */
+ AtoB(6) | AtoB(7) | /* sp and sb */
+ FtoB(0) | FtoB(1); /* floating return reg */
+ for(i=0; i<NREG; i++) {
+ if(regused[i])
+ regbits |= RtoB(i);
+ if(fregused[i])
+ regbits |= FtoB(i);
+ if(aregused[i])
+ regbits |= AtoB(i);
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ABRA:
+ case ARTS:
+ case ARTE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(&p->from, AGOK);
+ if(bany(&bit))
+ switch(p->as) {
+ case ALEA:
+ if(!(mvbits & B_INDIR))
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+
+ default:
+ if(mvbits & B_ADDR)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ }
+
+ bit = mkvar(&p->to, p->as);
+ if(bany(&bit))
+ switch(p->as) {
+ case ABSR: /* funny */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ goto def;
+
+ case APEA:
+ if(!(mvbits & B_INDIR))
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+
+ def:
+ case ACMPB: case ACMPW: case ACMPL:
+ case AFCMPF: case AFCMPD:
+ case ATSTB: case ATSTW: case ATSTL:
+ case AFTSTF: case AFTSTD:
+ case ABFEXTU: case ABFEXTS:
+ if(mvbits & B_ADDR)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+
+ case AADDB: case AADDW: case AADDL:
+ case ASUBB: case ASUBW: case ASUBL:
+ case AANDB: case AANDW: case AANDL:
+ case AORB: case AORW: case AORL:
+ case AEORB: case AEORW: case AEORL:
+ case ABFINS:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+
+ case ANOP:
+ case AMOVB: case AMOVW: case AMOVL:
+ case AFMOVEB: case AFMOVEW: case AFMOVEL:
+ case ACLRB: case ACLRW: case ACLRL:
+ case AFMOVEF: case AFMOVED:
+ if(mvbits & B_INDIR)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ else
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ diag(Z, "ref not found\n%L:%P", p->lineno, p);
+ continue;
+ }
+ if(r1 == r) {
+ diag(Z, "ref to self");
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R'])
+ print("\n%L %D\n", firstr->prog->lineno, &firstr->prog->from);
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ changer = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] | r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ changer = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARTS)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(changer)
+ goto loop1;
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ changer = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(changer)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+
+ /*
+ * 68040 'feature':
+ * load of a denormalized fp will trap
+ */
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ v = var + i;
+ if(v->type == D_AUTO) {
+ r->set.b[i/32] |= (1L << (i%32));
+ if(typefd[v->etype])
+ addmove(r, i, NREG+NREG, 1);
+ }
+ }
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n set = %B; rah = %B; cal = %B\n",
+ r->prog, r->set, r->refahead, r->calahead);
+ r->act = zbits;
+ }
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set an not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ changer = 0;
+ changea = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(changer <= 0 && changea <= 0) {
+ if(debug['R'])
+ print("%L$%d.%d: %B\n",
+ r->prog->lineno,
+ changer, changea, blsh(i));
+ continue;
+ }
+ rgp->costr = changer;
+ rgp->costa = changea;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R'])
+ print("%L$%d.%d %R: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->costr, rgp->costa,
+ rgp->regno,
+ bit);
+ if(rgp->regno != D_NONE)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Var *v;
+ int badccr;
+
+ badccr = 0;
+ p = r->prog;
+ p1 = p->link;
+ if(p1)
+ switch(p1->as) {
+ case AMOVW:
+ if(p1->from.type == D_CCR)
+ p = p1;
+ break;
+
+ case ABEQ:
+ case ABNE:
+ case ABLE:
+ case ABLS:
+ case ABLT:
+ case ABMI:
+ case ABGE:
+ case ABPL:
+ case ABGT:
+ case ABHI:
+ case ABCC:
+ case ABCS:
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ p1->from.type = D_CCR;
+ p1->to.type = D_TOS;
+ p1->as = AMOVW;
+ p = p1;
+ badccr = 1;
+ }
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+ p1->from.sym = v->sym;
+ p1->from.type = v->type;
+ p1->from.offset = v->offset;
+ p1->from.etype = v->etype;
+ p1->to.type = rn;
+ if(f) {
+ p1->to = p1->from;
+ p1->from = zprog.from;
+ p1->from.type = rn;
+ }
+ p1->as = opxt[OAS][v->etype];
+ if(badccr) {
+ p = p1;
+ p1 = prg();
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ p1->from.type = D_TOS;
+ p1->to.type = D_CCR;
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int as)
+{
+ Var *v;
+ int i, t, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ mvbits = 0;
+ t = a->type & D_MASK;
+ switch(t) {
+
+ default:
+ if(t >= D_R0 && t < D_R0+NREG) {
+ regbits |= RtoB(t-D_R0);
+ if(as == ADIVUL || as == ADIVSL)
+ regbits |= RtoB(t-D_R0+1);
+ }
+ if(t >= D_A0 && t < D_A0+NREG)
+ regbits |= AtoB(t-D_A0);
+ if(t >= D_F0 && t < D_F0+NREG)
+ regbits |= FtoB(t-D_F0);
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+
+ if((a->type & I_MASK) == I_ADDR)
+ mvbits |= B_ADDR;
+
+ switch(a->index & I_MASK) {
+ case I_INDEX1:
+ mvbits |= B_ADDR;
+ break;
+
+ case I_INDEX2:
+ case I_INDEX3:
+ mvbits |= B_INDIR;
+ break;
+ }
+
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(t == v->type)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = a->etype;
+ v->type = t;
+ if(debug['R'])
+ print("bit=%2d et=%2d %s (%p,%d,%ld)\n",
+ i, a->etype, s->name,
+ v->sym, v->type, v->offset);
+
+out:
+ bit = blsh(i);
+ if(t == D_EXTERN || t == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(t == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(a->etype != v->etype || !typechlpfd[a->etype])
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z]; /* funny punning */
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ changer++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ changer++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABSR:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARTS:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ changer++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i, j;
+
+ v = var + r->varno;
+ r->regno = D_NONE;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype");
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = BtoR(~b);
+ j = BtoA(~b);
+ if(r->costa == r->costr)
+ if(i > j)
+ i = NREG;
+ if(j < NREG && r->costa > 0)
+ if(r->costa > r->costr || i >= NREG) {
+ r->regno = D_A0 + j;
+ return AtoB(j);
+ }
+ if(i < NREG && r->costr > 0) {
+ r->regno = D_R0 + i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i < NREG) {
+ r->regno = D_F0 + i;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+ int x;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ changer -= CLOAD * r->loop;
+ changea -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d.%d\n", r->loop,
+ r->prog, blsh(bn), changer, changea);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ changer += CREF * r->loop;
+ changea += CREF * r->loop;
+ x = p->from.index;
+ if(x == D_NONE) {
+ switch(p->as) {
+ default:
+ changea = -CINF;
+ case AADDL:
+ case ASUBL:
+ case AMOVL:
+ case ACMPL:
+ break;
+ }
+ } else {
+ changer += (CXREF-CREF) * r->loop;
+ if(x != (I_INDEX3|D_NONE))
+ changer = -CINF;
+ if((x&I_MASK) == I_INDEX1)
+ changea = -CINF;
+ }
+ if(p->as == AMOVL) {
+ x = p->to.type;
+ if(x >= D_R0 && x < D_R0+NREG)
+ changer += r->loop;
+ if(x >= D_A0 && x < D_A0+NREG)
+ changea += r->loop;
+ }
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ changer += CREF * r->loop;
+ changea += CREF * r->loop;
+ x = p->to.index;
+ if(x == D_NONE)
+ switch(p->as) {
+ default:
+ changea = -CINF;
+ break;
+ case AMOVL:
+ case AADDL:
+ case ACMPL:
+ case ASUBL:
+ case ACLRL: /* can be faked */
+ case ATSTL: /* can be faked */
+ break;
+ }
+ else {
+ changer += (CXREF-CREF) * r->loop;
+ if(x != (I_INDEX3|D_NONE))
+ changer = -CINF;
+ if((x&I_MASK) == I_INDEX1)
+ changea = -CINF;
+ }
+ if(p->as == AMOVL) {
+ x = p->from.type;
+ if(x >= D_R0 && x < D_R0+NREG)
+ changer += r->loop;
+ if(x >= D_A0 && x < D_A0+NREG)
+ changea += r->loop;
+ }
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ changer -= CLOAD * r->loop;
+ changea -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d.%d\n", r->loop,
+ p, blsh(bn), changer, changea);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, ulong rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+ int x;
+
+ a->sym = 0;
+ x = a->index;
+ if(rn >= D_R0 && rn < D_R0+NREG)
+ goto addr;
+ if(x == (I_INDEX3|D_NONE)) {
+ a->type = rn | I_INDIR;
+ a->index = D_NONE;
+ a->offset = a->displace;
+ a->displace = 0;
+ return;
+ }
+ if(x != D_NONE) {
+ a->type = rn | I_INDIR;
+ a->index += I_INDEX1 - I_INDEX2;
+ a->offset = a->displace;
+ a->displace = 0;
+ return;
+ }
+ a->type = rn | (a->type & I_INDIR);
+ return;
+
+addr:
+ if(x == (I_INDEX3|D_NONE)) {
+ a->type = D_NONE|I_INDIR;
+ a->index += I_INDEX1 + rn - D_NONE - I_INDEX3;
+ a->scale = 4; /* .L*1 */
+ a->offset = a->displace;
+ a->displace = 0;
+ return;
+ }
+ a->type = rn | (a->type & I_INDIR);
+}
+
+/*
+ * bit reg
+ * 0-7 R0-R7
+ * 8-15 A0-A7
+ * 16-23 F0-F7
+ */
+ulong
+RtoB(int r)
+{
+
+ if(r < 0 || r >= NREG)
+ return 0;
+ return 1L << (r + 0);
+}
+
+int
+BtoR(ulong b)
+{
+
+ b &= 0x0000ffL;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - 0;
+}
+
+ulong
+AtoB(int a)
+{
+
+ if(a < 0 || a >= NREG)
+ return 0;
+ return 1L << (a + NREG);
+}
+
+int
+BtoA(ulong b)
+{
+
+ b &= 0x00ff00L;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - NREG;
+}
+
+ulong
+FtoB(int f)
+{
+
+ if(f < 0 || f >= NREG)
+ return 0;
+ return 1L << (f + NREG+NREG);
+}
+
+int
+BtoF(ulong b)
+{
+
+ b &= 0xff0000L;
+ if(b == 0)
+ return NREG;
+ return bitno(b) - NREG-NREG;
+}
diff --git a/utils/2c/sgen.c b/utils/2c/sgen.c
new file mode 100644
index 00000000..85925f72
--- /dev/null
+++ b/utils/2c/sgen.c
@@ -0,0 +1,819 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+
+ argoff = 0;
+ inargs = 0;
+ for(;; nn = nn->left) {
+ if(nn == Z) {
+ diag(Z, "cant find function name");
+ return;
+ }
+ if(nn->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, nn->sym, D_CONST, stkoff);
+ sp = p;
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", nn->sym->name);
+
+ noretval(3);
+ gbranch(ORETURN);
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+}
+
+void
+gen(Node *n)
+{
+ Node *l;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int g, o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ doinc(n, PRE);
+ cgen(n, D_NONE, n);
+ doinc(n, POST);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ doinc(l, PRE);
+ if(typesuv[n->type->etype]) {
+ sugen(l, D_TREE, nodret, n->type->width);
+ doinc(l, POST);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ g = regalloc(n->type, regret(n->type));
+ cgen(l, g, n);
+ doinc(l, POST);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ regfree(g);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ gbranch(OGOTO);
+ if(n->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ setsp();;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ setsp();
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ doinc(l, PRE);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+ g = regalloc(types[TLONG], D_NONE);
+ n->type = types[TLONG];
+ cgen(l, g, n);
+ regfree(g);
+ doinc(l, POST);
+ setsp();
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ doswit(g, l);
+
+ patch(spb, pc);
+ cases = cn;
+ breakpc = sbc;
+ setsp();
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ bcomplex(l);
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z);
+ p->as = ANOP;
+ break;
+ case ONAME:
+ if(o == OSET)
+ gopcode(OTST, types[TINT], D_NONE, Z, D_TREE, n);
+ else
+ gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z);
+ p->as = ANOP;
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TLONG]), Z);
+ p->as = ANOP;
+ }
+ if(n & 2) {
+ gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TDOUBLE]), Z);
+ p->as = ANOP;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * REGISTER ==> 12 register
+ * NAME ==> 10/11 name+value(SB/SP)
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 12 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (12) + (20) ==> 12 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(12) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (2,10,11) + (20) ==> 2 indirect w offset
+ * (2) ==> &13
+ * *(10,11) ==> 13 indirect, no index
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (12,1) ==> 8 adder in indexing (addresses)
+ * (X,7) + (10,11,2) ==> 8 adder in indexing (names)
+ * (8) ==> &9 index, almost addressable
+ *
+ * (X)++ ==> X fake addressability
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 10;
+ if(n->class == CPARAM || n->class == CAUTO)
+ n->addable = 11;
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 12;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ if(l->addable == 20)
+ switch(r->addable) {
+ case 12:
+ case 1:
+ n->addable = r->addable;
+ goto brk;
+ case 10:
+ case 11:
+ case 2:
+ goto addr13;
+ }
+ if(r->addable == 20)
+ switch(l->addable) {
+ case 12:
+ case 1:
+ n->addable = l->addable;
+ goto brk;
+ case 10:
+ case 11:
+ case 2:
+ addr13:
+ n->addable = 2;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OIND;
+ n->left = l;
+ n->right = Z;
+ n->addable = 13;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 2;
+ goto brk;
+ }
+
+ switch(r->addable) {
+ case 10:
+ case 11:
+ case 12:
+ case 1:
+ n->addable = 8;
+ }
+ switch(l->addable) {
+ case 10:
+ case 11:
+ case 12:
+ case 1:
+ n->addable = 8;
+ }
+ if(n->addable == 8) {
+ indx(n);
+ l = new1(OINDEX, idx.basetree, idx.regtree);
+ l->scale = idx.scale;
+ l->addable = 9;
+ l->complex = l->right->complex;
+ l->type = l->left->type;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 0;
+ break;
+ }
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 12:
+ n->addable = 10;
+ break;
+ case 10:
+ case 11:
+ case 2:
+ n->addable = 13;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vconst(r);
+ if(g >= 0 && g < 4)
+ n->addable = 7;
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ if(g < 4)
+ n->addable = 7;
+ break;
+ }
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ n->op = OASHL;
+ r->vconst = g;
+ if(g < 4)
+ n->addable = 7;
+ break;
+ }
+ break;
+
+ case ODIV:
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ if(n->op == ODIV)
+ n->op = OASHR;
+ else
+ n->op = OLSHR;
+ r->vconst = g;
+ }
+ break;
+
+ case OSUB:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ if(vconst(l) == 0) {
+ n->op = ONEG;
+ n->left = r;
+ n->right = Z;
+ }
+ break;
+
+ case OXOR:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ if(vconst(l) == -1) {
+ n->op = OCOM;
+ n->left = r;
+ n->right = Z;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ goto aseae;
+
+ case OASDIV:
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+ g = vlog(r);
+ if(g >= 0) {
+ if(n->op == OASDIV)
+ n->op = OASASHR;
+ else
+ n->op = OASLSHR;
+ r->vconst = g;
+ }
+ goto aseae;
+
+ case OASLMOD:
+ case OASMOD:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+
+ aseae: /* hack that there are no byte/short mul/div operators */
+ if(n->type->etype == TCHAR || n->type->etype == TSHORT) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = types[TLONG];
+ n->type = types[TLONG];
+ }
+ if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = types[TULONG];
+ n->type = types[TULONG];
+ }
+ goto asop;
+
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+ case OAS:
+ xcom(l);
+ xcom(r);
+ if(typev[n->type->etype])
+ break;
+
+ asop:
+ if(l->addable > INDEXED &&
+ l->complex < FNX &&
+ r && r->complex < FNX)
+ n->addable = l->addable;
+ break;
+
+ case OPOSTINC:
+ case OPREINC:
+ case OPOSTDEC:
+ case OPREDEC:
+ xcom(l);
+ if(typev[n->type->etype])
+ break;
+ if(l->addable > INDEXED &&
+ l->complex < FNX)
+ n->addable = l->addable;
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+
+brk:
+ n->complex = 0;
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OMUL:
+ case OLMUL:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * symmetric operators, make right side simple
+ * if same, put constant on left to get movq
+ */
+ if(r->complex > l->complex ||
+ (r->complex == l->complex && r->addable == 20)) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OEQ:
+ case ONE:
+ /*
+ * relational operators, make right side simple
+ * if same, put constant on left to get movq
+ */
+ if(r->complex > l->complex || r->addable == 20) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+indx(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(debug['x'])
+ prtree(n, "indx");
+ t = 0;
+
+loop:
+ l = n->left;
+ r = n->right;
+ switch(r->addable) {
+ default:
+ if(t) {
+ diag(n, "bad indx");
+ break;
+ }
+ n->right = l;
+ n->left = r;
+ t++;
+ goto loop;
+
+ case 10:
+ case 11:
+ if(l->op == ONAME && r->op == ONAME)
+ if(l->etype == TIND)
+ if(r->etype != TIND) {
+ n->right = l;
+ n->left = r;
+ goto loop;
+ }
+ if(l->addable == 1 || l->addable == 12) {
+ n->right = l;
+ n->left = r;
+ goto loop;
+ }
+
+ case 1:
+ case 12:
+ break;
+ }
+ if(l->addable != 7) {
+ idx.regtree = l;
+ idx.scale = 0;
+ } else
+ if(l->right->addable == 20) {
+ idx.regtree = l->left;
+ idx.scale = l->right->vconst;
+ } else {
+ idx.regtree = l->right;
+ idx.scale = l->left->vconst;
+ }
+ t = ewidth[idx.regtree->type->etype];
+ if(t == SZ_LONG)
+ idx.scale += 4;
+ else
+ if(t != SZ_SHORT)
+ diag(n, "index not W or L");
+
+ idx.basetree = r;
+ if(debug['x']) {
+ print("scale = %d\n", idx.scale);
+ prtree(idx.regtree, "index");
+ prtree(idx.basetree, "base");
+ }
+}
+
+void
+bcomplex(Node *n)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ bool64(n);
+ doinc(n, PRE);
+ boolgen(n, 1, D_NONE, Z, n);
+ } else
+ gbranch(OGOTO);
+}
+
+Node*
+nodconst(long v)
+{
+
+ return (Node*)v;
+}
diff --git a/utils/2c/swt.c b/utils/2c/swt.c
new file mode 100644
index 00000000..442d1fea
--- /dev/null
+++ b/utils/2c/swt.c
@@ -0,0 +1,1046 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(int g, Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ swit1(iq, nc, def, g, n);
+}
+
+#define N1 4 /* ncase: always linear */
+#define N2 5 /* min ncase: direct */
+#define N3 4 /* range/ncase: direct */
+ /* else binary */
+void
+swit1(C1 *q, int nc, long def, int g, Node *n)
+{
+ C1 *r, *s;
+ int i, l, m, y;
+ long v, range;
+ Prog *sp1, *sp2;
+
+ /* note that g and g+1 are not allocated */
+ if(nc <= N1)
+ goto linear;
+ y = 23*nc/100 + 5; /* number of cases needed to make */
+ if(y < N2) /* direct switch worthwile */
+ y = N2; /* try to do better than n**2 here */
+ for(m=nc; m>=y; m--) { /* m is number of cases */
+ s = q+nc;
+ r = s-m;
+ for(l=nc-m; l>=0; l--) { /* l is base of contig cases */
+ s--;
+ range = s->val - r->val;
+ if(range > 0 && range <= N3*m)
+ goto direct;
+ r--;
+ }
+ }
+
+ /*
+ * divide and conquer
+ */
+ i = nc / 2;
+ r = q+i;
+ v = r->val;
+ /* compare median */
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g, n, g+1, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OLT);
+ sp1 = p;
+ gbranch(OGT);
+ sp2 = p;
+ gbranch(OGOTO);
+ patch(p, r->label);
+
+ patch(sp1, pc);
+ swit1(q, i, def, g, n);
+
+ patch(sp2, pc);
+ swit1(r+1, nc-i-1, def, g, n);
+ return;
+
+direct:
+ /* compare low bound */
+ v = r->val;
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g, n, g+1, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OLT);
+ sp1 = p;
+
+ /* compare high bound */
+ v = s->val;
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g, n, g+1, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OGT);
+ sp2 = p;
+
+ /* switch */
+ v = r->val;
+ gpseudo(AMOVW, symstatic, D_R0, 0L);
+ p->from.offset = nstatic - v*2;
+ p->from.index = g|I_INDEX1;
+ p->from.scale = 5;
+ nextpc();
+ p->as = ACASEW;
+
+ /* table */
+ for(i=0; i<=range; i++) {
+ gbranch(OCASE);
+ if(v == r->val) {
+ patch(p, r->label);
+ r++;
+ } else
+ patch(p, def);
+ p->from.type = D_STATIC;
+ p->from.sym = symstatic;
+ p->from.offset = nstatic;
+ nstatic += types[TSHORT]->width;
+ v++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ if(r != s+1)
+ print("smelly direct switch\n");
+
+ if(l > 0) {
+ patch(sp1, pc);
+ swit1(q, l, def, g, n);
+ } else
+ patch(sp1, def);
+
+ m += l;
+ if(m < nc) {
+ patch(sp2, pc);
+ swit1(q+m, nc-m, def, g, n);
+ } else
+ patch(sp2, def);
+ return;
+
+
+linear:
+ for(i=0; i<nc; i++) {
+ v = q->val;
+ if(v >= -128 && v < 128) {
+ gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n);
+ gopcode(OEQ, n->type, g+1, n, g, n);
+ } else
+ gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v));
+ gbranch(OEQ);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+
+int
+bitload(Node *b, int n1, int n2, int n3, Node *nn)
+{
+ int sh, g, gs;
+ long v;
+ Node *l;
+ Type *t;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ gs = 0;
+ t = tfield;
+
+ l = b->left;
+ g = regalloc(t, n3);
+ if(n2 != D_NONE) {
+ lcgen(l, n2, Z);
+ n2 |= I_INDIR;
+ gmove(t, t, n2, l, g, l);
+ gmove(t, t, g, l, n1, l);
+ } else
+ cgen(l, g, nn);
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, t, D_CONST, nodconst(v), g, l);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ if(sh >= 8) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ gopcode(OASHL, t, gs, l, g, l);
+ if(b->type->shift)
+ regfree(gs);
+ } else
+ gopcode(OASHL, t, D_CONST, nodconst(sh), g, l);
+ sh += b->type->shift;
+ if(sh > 0) {
+ if(sh >= 8) {
+ if(b->type->shift) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ }
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, t, gs, l, g, l);
+ else
+ gopcode(OASHR, t, gs, l, g, l);
+ regfree(gs);
+ } else {
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, t, D_CONST, nodconst(sh), g, l);
+ else
+ gopcode(OASHR, t, D_CONST, nodconst(sh), g, l);
+ }
+ }
+ }
+ return g;
+}
+
+void
+bitstore(Node *b, int n1, int n2, int n3, int result, Node *nn)
+{
+ long v;
+ Node *l;
+ Type *t;
+ int sh, g, gs;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ t = tfield;
+
+ l = b->left;
+ g = regalloc(t, D_NONE);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, t, D_CONST, nodconst(v), n1, l);
+ gmove(t, t, n1, l, g, l);
+ if(result != D_NONE)
+ gmove(t, nn->type, n1, l, result, nn);
+ sh = b->type->shift;
+ if(sh > 0) {
+ if(sh >= 8) {
+ gs = regalloc(t, D_NONE);
+ gmove(t, t, D_CONST, nodconst(sh), gs, l);
+ gopcode(OASHL, t, gs, l, g, l);
+ regfree(gs);
+ } else
+ gopcode(OASHL, t, D_CONST, nodconst(sh), g, l);
+ }
+ v <<= sh;
+ gopcode(OAND, t, D_CONST, nodconst(~v), n3, l);
+ gopcode(OOR, t, n3, l, g, l);
+ gmove(t, t, g, l, n2|I_INDIR, l);
+
+ regfree(g);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, D_SCONST, 0L);
+ memmove(p->to.sval, string, NSNAME);
+ p->from.offset = nstring - NSNAME;
+ p->from.displace = NSNAME;
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+doinc(Node *n, int f)
+{
+ Node *l;
+ int a;
+
+loop:
+ if(n == Z)
+ return 0;
+ l = n->left;
+ switch(n->op) {
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(f & POST) {
+ a = n->addable;
+ if(a >= INDEXED) {
+ if(f & TEST)
+ return 1;
+ n->addable = 0;
+ cgen(n, D_NONE, n);
+ n->addable = a;
+ }
+ }
+ break;
+
+ case OAS:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+
+ case OPREINC:
+ case OPREDEC:
+ if(f & PRE) {
+ a = n->addable;
+ if(a >= INDEXED) {
+ if(f & TEST)
+ return 1;
+ n->addable = 0;
+ doinc(n, PRE);
+ cgen(n, D_NONE, n);
+ n->addable = a;
+ return 0;
+ }
+ }
+ break;
+
+ case OFUNC:
+ if(f & PRE)
+ break;
+ return 0;
+
+ case ONAME:
+ case OREGISTER:
+ case OSTRING:
+ case OCONST:
+
+ case OANDAND:
+ case OOROR:
+ return 0;
+
+ case OCOND:
+ return 0;
+
+ case OCOMMA:
+ n = n->right;
+ if(f & PRE)
+ n = l;
+ goto loop;
+ }
+ if(l != Z)
+ if(doinc(l, f))
+ return 1;
+ n = n->right;
+ goto loop;
+}
+
+void
+setsp(void)
+{
+
+ nextpc();
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+}
+
+void
+adjsp(long o)
+{
+
+ if(o != 0) {
+ nextpc();
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = o;
+ argoff += o;
+ }
+}
+
+int
+simplv(Node *n)
+{
+
+ if(n->addable <= INDEXED)
+ return 0;
+ while(n->op == OIND)
+ n = n->left;
+ if(n->op == ONAME)
+ return 1;
+ return 0;
+}
+
+int
+eval(Node *n, int g)
+{
+
+ if(n->addable >= INDEXED)
+ return D_TREE;
+ g = regalloc(n->type, g);
+ cgen(n, g, n);
+ return g;
+}
+
+void outhist(Biobuf*);
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cant open %s", outfile);
+ errorexit();
+ }
+ Binit(&b, f, OWRITE);
+ Bseek(&b, 0L, 2);
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type & D_MASK;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type & D_MASK;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&b, p, sf, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ long l;
+
+ l = p->as;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ l = p->lineno;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ zaddr(b, &p->from, sf);
+ zaddr(b, &p->to, st);
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->field)
+ t |= T_FIELD;
+ if(a->index != D_NONE)
+ t |= T_INDEX;
+ if(s)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ if(a->offset)
+ t |= T_OFFSET;
+ if(a->displace)
+ t |= T_INDEX;
+ if(a->type & ~0xff)
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_FIELD) { /* implies field */
+ i = a->field;
+ Bputc(b, i);
+ Bputc(b, i>>8);
+ }
+ if(t & T_INDEX) { /* implies index, scale, displace */
+ i = a->index;
+ Bputc(b, i);
+ Bputc(b, i>>8);
+ Bputc(b, a->scale);
+ l = a->displace;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ i = a->type;
+ Bputc(b, i);
+ if(t & T_TYPE)
+ Bputc(b, i>>8);
+}
+
+
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+int
+nodalloc(Type *t, int g, Node *n)
+{
+
+ n->type = t;
+ n->op = OREGISTER;
+ n->addable = 12;
+ n->complex = 0;
+ g = regaddr(g);
+ n->reg = g | I_INDIR;
+ n->xoffset = 0;
+ return g;
+}
+
+int
+mulcon(Node *n, Node *c, int result, Node *nn)
+{
+ long v;
+
+ if(typefd[n->type->etype])
+ return 0;
+ v = c->vconst;
+ if(mulcon1(n, v, result, nn))
+ return 1;
+ return 0;
+}
+
+int
+shlcon(Node *n, Node *c, int result, Node *nn)
+{
+ long v;
+
+ v = 1L << c->vconst;
+ return mulcon1(n, v, result, nn);
+}
+
+int
+mulcon1(Node *n, long v, int result, Node *nn)
+{
+ int g, g1, a1, a2, neg;
+ int o;
+ char code[10], *p;
+
+ if(result == D_NONE)
+ return 0;
+ neg = 0;
+ if(v < 0) {
+ v = -v;
+ neg++;
+ }
+ a1 = 0;
+ a2 = multabsize;
+ for(;;) {
+ if(a1 >= a2)
+ return 0;
+ g1 = (a2 + a1)/2;
+ if(v < multab[g1].val) {
+ a2 = g1;
+ continue;
+ }
+ if(v > multab[g1].val) {
+ a1 = g1+1;
+ continue;
+ }
+ break;
+ }
+ strcpy(code, "0");
+ strncat(code, multab[g1].code, sizeof(multab[0].code));
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ g = regalloc(n->type, result);
+ cgen(n, g, n);
+ if(neg)
+ gopcode(ONEG, n->type, D_NONE, n, g, n);
+ g1 = regalloc(n->type, D_NONE);
+loop:
+ switch(*p) {
+ case 0:
+ regfree(g1);
+ gmove(n->type, nn->type, g, n, result, nn);
+ regfree(g);
+ return 1;
+ case '0':
+ o = OAS;
+ *p -= '0';
+ goto com;
+ case '1':
+ case '2':
+ o = OSUB;
+ *p -= '1';
+ goto com;
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ o = OADD;
+ *p -= '3';
+ com:
+ a1 = g;
+ if(*p == 1 || *p == 3)
+ a1 = g1;
+ a2 = g;
+ if(*p == 0 || *p == 3)
+ a2 = g1;
+ gopcode(o, n->type, a1, n, a2, n);
+ p++;
+ break;
+ default:
+ a1 = *p++ - 'a' + 1;
+ a2 = g;
+ if(a1 > 8) {
+ a2 = g1;
+ a1 -= 8;
+ }
+ gopcode(OASHL, n->type, D_CONST, nodconst(a1), a2, n);
+ break;
+ }
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, D_NONE, Z);
+ if(r != Z)
+ cgen(r, D_NONE, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, D_SCONST, 0L);
+ p->from.offset += o+e;
+ p->from.displace = lw;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, D_CONST, (long)(a->vconst>>32));
+ p->from.offset += o;
+ p->from.displace = 4;
+ gpseudo(ADATA, s, D_CONST, (long)(a->vconst));
+ p->from.offset += o + 4;
+ p->from.displace = 4;
+ return;
+ }
+ gpseudotree(ADATA, s, a);
+ p->from.offset += o;
+ p->from.displace = w;
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_SHORT)
+ w = SZ_SHORT;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ o += SZ_LONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/utils/2c/txt.c b/utils/2c/txt.c
new file mode 100644
index 00000000..2723c6d6
--- /dev/null
+++ b/utils/2c/txt.c
@@ -0,0 +1,940 @@
+#include "gc.h"
+
+void
+tindex(Type *tf, Type *tt)
+{
+ int i, j;
+
+ j = 0;
+ if(tt != T) {
+ j = tt->etype;
+ if(j >= NTYPE)
+ j = 0;
+ }
+ i = 0;
+ if(tf != T) {
+ i = tf->etype;
+ if(i >= NTYPE)
+ if(typesu[i])
+ i = j;
+ else
+ i = 0;
+ }
+ txtp = &txt[i][j];
+}
+
+void
+ginit(void)
+{
+ int i, j, si, sj;
+
+ thestring = "68020";
+ thechar = '2';
+ exregoffset = 7;
+ exaregoffset = 5;
+ exfregoffset = 7;
+ listinit();
+ for(i=0; i<NREG; i++) {
+ regused[i] = 0;
+ fregused[i] = 0;
+ aregused[i] = 0;
+ }
+ regaddr(D_A0+6);
+ regaddr(D_A0+7);
+ for(i=0; i<sizeof(regbase); i++)
+ regbase[i] = D_NONE;
+ for(i=0; i<NREG; i++) {
+ regbase[D_R0+i] = D_R0+i;
+ regbase[D_A0+i] = D_A0+i;
+ regbase[D_F0+i] = D_F0+i;
+ }
+ regbase[D_TOS] = D_TOS;
+
+ for(i=0; i<NTYPE; i++)
+ for(j=0; j<NTYPE; j++) {
+ txtp = &txt[i][j];
+ txtp->movas = AGOK;
+ txtp->preclr = 0;
+ txtp->postext = AGOK;
+ if(!(typechlp[i] && typechlp[j]))
+ continue;
+ si = types[i]->width;
+ sj = types[j]->width;
+ if(sj < si)
+ txtp->preclr = -1;
+ if(sj > si) {
+ if(typeu[i]) {
+ txtp->preclr = 1;
+ } else {
+ if(sj == 2)
+ txtp->postext = AEXTBW;
+ if(sj == 4)
+ if(si == 1)
+ txtp->postext = AEXTBL;
+ else
+ txtp->postext = AEXTWL;
+ }
+ sj = si;
+ }
+ if(sj == 1)
+ txtp->movas = AMOVB;
+ if(sj == 2)
+ txtp->movas = AMOVW;
+ if(sj == 4)
+ txtp->movas = AMOVL;
+ }
+
+ for(i=0; i<ALLOP; i++)
+ for(j=0; j<NTYPE; j++)
+ opxt[i][j] = AGOK;
+ oinit(OFUNC, ABSR, ATRAP, AGOK, AGOK, AGOK);
+
+ oinit(OAS, AMOVB, AMOVW, AMOVL, AFMOVEF, AFMOVED);
+ oinit(OFAS, AFMOVEB, AFMOVEW, AFMOVEL, AFMOVEF, AFMOVED);
+ oinit(OADDR, AGOK, APEA, ALEA, AGOK, AGOK);
+ oinit(OPREINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OPOSTINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OPREDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OPOSTDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OASADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
+ oinit(OSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OASSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
+ oinit(OMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OASMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(OASLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
+ oinit(ODIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
+ oinit(OLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
+ oinit(OASDIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
+ oinit(OASLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
+ oinit(OMOD, AGOK, ADIVSW, ADIVSL, AFMODF, AFMODD);
+ oinit(OASMOD, AGOK, ADIVSW, ADIVSL, AGOK, AGOK);
+ oinit(OLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
+ oinit(OASLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
+ oinit(OAND, AANDB, AANDW, AANDL, AGOK, AGOK);
+ oinit(OASAND, AANDB, AANDW, AANDL, AGOK, AGOK);
+ oinit(OOR, AORB, AORW, AORL, AGOK, AGOK);
+ oinit(OASOR, AORB, AORW, AORL, AGOK, AGOK);
+ oinit(OXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
+ oinit(OASXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
+ oinit(ONEG, ANEGB, ANEGW, ANEGL, AFNEGF, AFNEGD);
+ oinit(OCOM, ANOTB, ANOTW, ANOTL, AGOK, AGOK);
+ oinit(OTST, ATSTB, ATSTW, ATSTL, AFTSTF, AFTSTD);
+ oinit(OEQ, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(ONE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OGE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OGT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OLO, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OHS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OHI, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
+ oinit(OASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
+ oinit(OASASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
+ oinit(OLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
+ oinit(OASLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
+ oinit(OASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
+ oinit(OASASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
+ oinit(OBIT, ABFEXTU, AGOK, AGOK, AGOK, AGOK);
+
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ nstatic = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.to = zprog.from;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = types[TIND]->etype;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = typ(TARRAY, types[TCHAR]);
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = symrathole->type;
+
+ com64init();
+
+ symstatic = slookup(".static");
+ symstatic->class = CSTATIC;
+ symstatic->type = typ(TARRAY, types[TLONG]);
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ regfree(D_A0+6);
+ regfree(D_A0+7);
+ for(i=0; i<NREG; i++) {
+ if(regused[i])
+ diag(Z, "missing R%d", i);
+ if(aregused[i])
+ diag(Z, "missing A%d", i);
+ if(fregused[i])
+ diag(Z, "missing F%d", i);
+ }
+
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symstatic->type->width = nstatic;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, D_CONST, s->type->width);
+ pc--;
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+oinit(int o, int ab, int aw, int al, int af, int ad)
+{
+ int i;
+
+ i = o;
+ if(i >= ALLOP) {
+ diag(Z, "op(%d) >= ALLOP(%d)", i, ALLOP);
+ errorexit();
+ }
+ opxt[i][TCHAR] = ab;
+ opxt[i][TUCHAR] = ab;
+ opxt[i][TSHORT] = aw;
+ opxt[i][TUSHORT] = aw;
+ opxt[i][TINT] = al;
+ opxt[i][TUINT] = al;
+ opxt[i][TLONG] = al;
+ opxt[i][TULONG] = al;
+ opxt[i][TIND] = al;
+ opxt[i][TFLOAT] = af;
+ opxt[i][TDOUBLE] = ad;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ return p;
+}
+
+void
+nextpc(void)
+{
+
+ p = prg();
+ pc++;
+ p->lineno = nearln;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n)
+{
+ long s;
+
+loop:
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ gargs(n->right);
+ n = n->left;
+ goto loop;
+ }
+ s = argoff;
+ cgen(n, D_TOS, n);
+ argoff = s + n->type->width;
+}
+
+void
+naddr(Node *n, Adr *a, int x)
+{
+ Node *l;
+ long v;
+
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OADDR:
+ case OIND:
+ naddr(n->left, a, x);
+ goto noadd;
+
+ case OREGISTER:
+ a->sym = S;
+ a->type = n->reg;
+ a->offset = n->xoffset;
+ a->displace = 0;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->displace = 0;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ a->type = D_STATIC;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OINDEX:
+ naddr(n->left, a, x);
+ switch(n->left->addable) {
+ default:
+ goto bad;
+ case 1:
+ case 12:
+ a->index = x | I_INDEX1;
+ a->type &= D_MASK;
+ break;
+ case 2:
+ case 10:
+ case 11:
+ a->index = x | I_INDEX2;
+ break;
+ }
+ a->scale = n->scale;
+ break;
+
+ case OCONST:
+ a->displace = 0;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ break;
+
+ case OADD:
+ l = n->left;
+ if(l->addable == 20) {
+ v = l->vconst;
+ naddr(n->right, a, x);
+ goto add;
+ }
+ l = n->right;
+ if(l->addable == 20) {
+ v = l->vconst;
+ naddr(n->left, a, x);
+ goto add;
+ }
+ goto bad;
+ noadd:
+ v = 0;
+ add:
+ switch(n->addable) {
+ default:
+ goto bad;
+ case 2:
+ a->displace += v;
+ break;
+ case 21:
+ a->type &= D_MASK;
+ a->type |= I_INDIR;
+ break;
+ case 1:
+ case 12:
+ a->offset += v;
+ a->type &= D_MASK;
+ a->type |= I_ADDR;
+ break;
+ case 13:
+ a->index = D_NONE|I_INDEX3;
+ case 10:
+ case 11:
+ case 20:
+ a->type &= D_MASK;
+ a->type |= I_DIR;
+ break;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+
+ case OAS:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ case OASXOR:
+ case OASOR:
+ case OASADD:
+ case OASSUB:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASAND:
+ naddr(n->left, a, x);
+ break;
+ }
+}
+
+int
+regalloc(Type *t, int g)
+{
+
+ if(t == T)
+ return D_NONE;
+ g &= D_MASK;
+ if(typefd[t->etype]) {
+ if(g >= D_F0 && g < D_F0+NREG) {
+ fregused[g-D_F0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(fregused[g] == 0) {
+ fregused[g]++;
+ return g + D_F0;
+ }
+ } else {
+ if(g >= D_R0 && g < D_R0+NREG) {
+ regused[g-D_R0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(regused[g] == 0) {
+ regused[g]++;
+ return g + D_R0;
+ }
+ }
+ diag(Z, "out of registers");
+ return D_TOS;
+}
+
+int
+regaddr(int g)
+{
+
+ if(g >= D_A0 && g < D_A0+NREG) {
+ aregused[g-D_A0]++;
+ return g;
+ }
+ for(g=0; g<NREG; g++)
+ if(aregused[g] == 0) {
+ aregused[g]++;
+ return g + D_A0;
+ }
+ diag(Z, "out of addr registers");
+ return D_TOS;
+}
+
+int
+regpair(int g)
+{
+
+ if(g >= D_R0+1 && g < D_R0+NREG)
+ if(!regused[g-D_R0-1]) {
+ regused[g-D_R0-1]++;
+ regused[g-D_R0]++;
+ return g-1;
+ }
+ if(g >= D_R0 && g < D_R0+NREG-1)
+ if(!regused[g-D_R0+1]) {
+ regused[g-D_R0+1]++;
+ regused[g-D_R0]++;
+ return g;
+ }
+ for(g = 0; g < NREG-1; g++)
+ if(!regused[g])
+ if(!regused[g+1]) {
+ regused[g]++;
+ regused[g+1]++;
+ return g + D_R0;
+ }
+ diag(Z, "out of register pairs");
+ return D_TOS;
+}
+
+int
+regret(Type *t)
+{
+
+ if(t == T)
+ return D_NONE;
+ if(typefd[t->etype])
+ return D_F0;
+ return D_R0;
+}
+
+void
+regfree(int g)
+{
+
+ g &= D_MASK;
+ if(g == D_TOS || g == D_TREE || g == D_NONE)
+ return;
+ if(g >= D_R0 && g < D_R0+NREG) {
+ regused[g-D_R0]--;
+ return;
+ }
+ if(g >= D_A0 && g < D_A0+NREG) {
+ aregused[g-D_A0]--;
+ return;
+ }
+ if(g >= D_F0 && g < D_F0+NREG) {
+ fregused[g-D_F0]--;
+ return;
+ }
+ diag(Z, "bad in regfree: %d", g);
+}
+
+void
+gmove(Type *tf, Type *tt, int gf, Node *f, int gt, Node *t)
+{
+ int g, a, b;
+ Prog *p1;
+
+ tindex(tf, tt);
+ if(txtp->preclr) {
+ if(gf >= D_R0 && gf < D_R0+NREG)
+ if(txtp->preclr < 0) {
+ gmove(tt, tt, gf, f, gt, t);
+ return;
+ }
+ g = regalloc(types[TLONG], gt);
+ if(g == gf) {
+ g = regalloc(types[TLONG], D_NONE);
+ regfree(gf);
+ }
+ if(txtp->preclr > 0)
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(0), g, Z);
+ gopcode(OAS, tf, gf, f, g, Z);
+ if(g != gt)
+ gopcode(OAS, tt, g, Z, gt, t);
+ regfree(g);
+ return;
+ }
+ a = txtp->postext;
+ if(a != AGOK) {
+ if(gf >= D_R0 && gf < D_R0+NREG)
+ g = regalloc(types[TLONG], gf);
+ else
+ g = regalloc(types[TLONG], gt);
+ if(g != gf)
+ gopcode(OAS, tf, gf, f, g, Z);
+ nextpc();
+ p->as = a;
+ p->to.type = g;
+ if(debug['g'])
+ print("%P\n", p);
+ if(g != gt)
+ gopcode(OAS, tt, g, Z, gt, t);
+ regfree(g);
+ return;
+ }
+ if((regbase[gf] != D_NONE && regbase[gf] == regbase[gt]) ||
+ (gf == D_TREE && gt == D_TREE && f == t))
+ return;
+ if(typefd[tf->etype] || typefd[tt->etype]) {
+ if(typeu[tf->etype] && typefd[tt->etype]) { /* unsign->float */
+ a = regalloc(types[TLONG], D_NONE);
+ gmove(tf, types[TLONG], gf, f, a, t);
+ if(tf->etype == TULONG) {
+ b = regalloc(types[TDOUBLE], D_NONE);
+ gmove(types[TLONG], tt, a, t, b, t);
+ gopcode(OTST, types[TLONG], D_NONE, Z, a, t);
+ gbranch(OGE);
+ p1 = p;
+ gopcode(OASADD, types[TDOUBLE],
+ D_CONST, nodconst(100), b, t);
+ p->from.dval = 4294967296.;
+ patch(p1, pc);
+ gmove(types[TDOUBLE], tt, b, t, gt, t);
+ regfree(b);
+ } else
+ gmove(types[TLONG], tt, a, t, gt, t);
+ regfree(a);
+ return;
+ }
+ if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */
+ a = regalloc(types[TLONG], D_NONE);
+ gopcode(OAS, types[TLONG], D_FPCR, t, a, t);
+ gopcode(OAS, types[TLONG], D_CONST, nodconst(16), D_FPCR, t);
+ }
+ if(gf < D_F0 || gf >= D_F0+NREG) {
+ g = regalloc(types[TDOUBLE], gt);
+ gopcode(OFAS, tf, gf, f, g, t);
+ if(g != gt)
+ gopcode(OFAS, tt, g, t, gt, t);
+ regfree(g);
+ } else
+ gopcode(OFAS, tt, gf, f, gt, t);
+ if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */
+ gopcode(OAS, types[TLONG], a, t, D_FPCR, t);
+ regfree(a);
+ }
+ return;
+ }
+ gopcode(OAS, tt, gf, f, gt, t);
+}
+
+void
+gopcode(int o, Type *ty, int gf, Node *f, int gt, Node *t)
+{
+ int i, fidx, tidx;
+ long v;
+
+ if(o == OAS)
+ if(gf == gt)
+ if(gf != D_TREE || f == t)
+ return;
+
+ fidx = D_NONE;
+ if(gf == D_TREE) {
+ if(f->op == OINDEX) {
+ fidx = regalloc(types[TIND], fidx);
+ cgen(f->right, fidx, f->right);
+ }
+ }
+ tidx = D_NONE;
+ if(gt == D_TREE) {
+ if(t->op == OINDEX) {
+ v = argoff;
+ tidx = regalloc(types[TIND], tidx);
+ cgen(t->right, tidx, t->right);
+ if(gf == D_TOS)
+ adjsp(v - argoff);
+ }
+ }
+ i = 0;
+ if(ty != T) {
+ i = ty->etype;
+ if(i >= NTYPE)
+ i = 0;
+ }
+ nextpc();
+ if(gf == D_TREE) {
+ naddr(f, &p->from, fidx);
+ } else {
+ p->from.type = gf;
+ if(gf == D_CONST) {
+ p->from.offset = (long)(uintptr)f;
+ if(typefd[i]) {
+ p->from.type = D_FCONST;
+ p->from.dval = (long)(uintptr)f;
+ }
+ }
+ }
+ p->as = opxt[o][i];
+ if(gt == D_TREE) {
+ naddr(t, &p->to, tidx);
+ } else {
+ p->to.type = gt;
+ if(gt == D_CONST)
+ p->to.offset = (long)(uintptr)t;
+ }
+ if(o == OBIT) {
+ p->from.field = f->type->nbits;
+ p->to.field = f->type->shift;
+ if(p->from.field == 0)
+ diag(Z, "BIT zero width bit field");
+ }
+ if(p->as == AMOVL || p->as == AMOVW || p->as == AMOVB)
+ asopt();
+ if(debug['g'])
+ print("%P\n", p);
+ if(p->as == AGOK)
+ diag(Z, "GOK in gopcode: %s", onames[o]);
+ if(fidx != D_NONE)
+ regfree(fidx);
+ if(tidx != D_NONE)
+ regfree(tidx);
+}
+
+void
+asopt(void)
+{
+ long v;
+ int g;
+ Prog *q;
+
+ /*
+ * mov $0, ...
+ * ==>
+ * clr , ...
+ */
+ v = 0;
+ if(p->from.type == D_CONST) {
+ v = p->from.offset;
+ if(v == 0) {
+ p->from.type = D_NONE;
+ if(p->as == AMOVL)
+ p->as = ACLRL;
+ if(p->as == AMOVW)
+ p->as = ACLRW;
+ if(p->as == AMOVB)
+ p->as = ACLRB;
+ return;
+ }
+ }
+ /*
+ * mov ..., TOS
+ * ==>
+ * pea (...)
+ */
+ if(p->as == AMOVL && p->to.type == D_TOS && p->from.index == D_NONE)
+ switch(p->from.type) {
+ case D_CONST:
+ p->from.type |= I_INDIR;
+ p->to = p->from;
+ p->from = zprog.from;
+ p->as = APEA;
+ return;
+
+ case I_ADDR|D_EXTERN:
+ case I_ADDR|D_STATIC:
+ p->from.type &= ~I_ADDR;
+ p->to = p->from;
+ p->from = zprog.from;
+ p->as = APEA;
+ return;
+ }
+ /*
+ * movL $Qx, ...
+ * ==>
+ * movL $Qx,R
+ * movL R, ...
+ */
+ if(p->as == AMOVL && p->from.type == D_CONST)
+ if(v >= -128 && v < 128)
+ if(p->to.type < D_R0 || p->to.type >= D_R0+NREG) {
+ g = regalloc(types[TLONG], D_NONE);
+ q = p;
+ nextpc();
+ p->as = AMOVL;
+ p->from.type = g;
+ p->to = q->to;
+ q->to = p->from;
+ regfree(g);
+ if(debug['g'])
+ print("%P\n", q);
+ return;
+ }
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = ABNE;
+ switch(o) {
+ case ORETURN: a = ARTS; break;
+ case OGOTO: a = ABRA; break;
+ case OEQ: a = ABEQ; break;
+ case ONE: a = ABNE; break;
+ case OLE: a = ABLE; break;
+ case OLS: a = ABLS; break;
+ case OLT: a = ABLT; break;
+ case OLO: a = ABCS; break;
+ case OGE: a = ABGE; break;
+ case OHS: a = ABCC; break;
+ case OGT: a = ABGT; break;
+ case OHI: a = ABHI; break;
+ case OBIT: a = ABCS; break;
+ case OCASE: a = ABCASE; break;
+ }
+ nextpc();
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+ p->as = a;
+}
+
+void
+fpbranch(void)
+{
+ int a;
+
+ a = p->as;
+ switch(a) {
+ case ABEQ: a = AFBEQ; break;
+ case ABNE: a = AFBNE; break;
+ case ABLE: a = AFBLE; break;
+ case ABLT: a = AFBLT; break;
+ case ABGE: a = AFBGE; break;
+ case ABGT: a = AFBGT; break;
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, int g, long v)
+{
+
+ nextpc();
+ if(a == ADATA)
+ pc--;
+ p->as = a;
+ if(g == D_TREE)
+ abort(); /* obsolete */
+ p->to.type = g;
+ p->to.offset = v;
+ p->from.sym = s;
+ p->from.type = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+}
+
+void
+gpseudotree(int a, Sym *s, Node *n)
+{
+ nextpc();
+ if(a == ADATA)
+ pc--;
+ p->as = a;
+ naddr(n, &p->to, D_NONE);
+ p->from.sym = s;
+ p->from.type = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechl[t->etype]) {
+ if(exregoffset <= 5)
+ return 0;
+ o = exregoffset + D_R0;
+ exregoffset--;
+ return o;
+ }
+ if(t->etype == TIND) {
+ if(exaregoffset <= 3)
+ return 0;
+ o = exaregoffset + D_A0;
+ exaregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 5)
+ return 0;
+ o = exfregoffset + D_F0;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/2l/Nt.c b/utils/2l/Nt.c
new file mode 100644
index 00000000..2efff499
--- /dev/null
+++ b/utils/2l/Nt.c
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/2l/Plan9.c b/utils/2l/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/2l/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/2l/Posix.c b/utils/2l/Posix.c
new file mode 100644
index 00000000..aa5d9551
--- /dev/null
+++ b/utils/2l/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fials if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
diff --git a/utils/2l/asm.c b/utils/2l/asm.c
new file mode 100644
index 00000000..10129e98
--- /dev/null
+++ b/utils/2l/asm.c
@@ -0,0 +1,1569 @@
+#include "l.h"
+
+short opa[20];
+short *op;
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long v;
+ int a;
+ short *op1;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ curp = firstp;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->pc != pc) {
+ if(!debug['a'])
+ print("%P\n", curp);
+ diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
+ pc = p->pc;
+ }
+ curp = p;
+ if(debug['a'])
+ Bprint(&bso, "%lux:%P\n", pc, curp);
+ asmins(p);
+ if(cbc < sizeof(opa))
+ cflush();
+ for(op1 = opa; op1 < op; op1++) {
+ a = *op1;
+ *cbp++ = a >> 8;
+ *cbp++ = a;
+ }
+ a = 2*(op - opa);
+ pc += a;
+ cbc -= a;
+ if(debug['a']) {
+ for(op1 = opa; op1 < op; op1++)
+ if(op1 == opa)
+ Bprint(&bso, "\t\t%4ux", *op1 & 0xffff);
+ else
+ Bprint(&bso, " %4ux", *op1 & 0xffff);
+ if(op != opa)
+ Bprint(&bso, "\n");
+ }
+ }
+ cflush();
+ switch(HEADTYPE) {
+ case 0: /* this is garbage */
+ seek(cout, rnd(HEADR+textsize, 8192), 0);
+ break;
+ case 1: /* plan9 boot data goes into text */
+ seek(cout, rnd(HEADR+textsize, INITRND), 0);
+ break;
+ case 2: /* plan 9 */
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 3: /* next boot */
+ seek(cout, HEADR+rnd(textsize, INITRND), 0);
+ break;
+ case 4: /* preprocess pilot */
+ seek(cout, HEADR+textsize, 0);
+ break;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ for(v = 0; v < datsize; v += sizeof(buf)-100) {
+ if(datsize-v > sizeof(buf)-100)
+ datblk(v, sizeof(buf)-100);
+ else
+ datblk(v, datsize-v);
+ }
+
+ symsize = 0;
+ spsize = 0;
+ lcsize = 0;
+
+ Bflush(&bso);
+
+ switch(HEADTYPE) {
+ default:
+ seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ break;
+ case 1: /* plan9 boot data goes into text */
+ seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ break;
+ case 2: /* plan 9 */
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 3: /* next boot */
+ seek(cout, HEADR+rnd(textsize, INITRND)+datsize, 0);
+ break;
+ }
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ asmsym();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ asmsp();
+ }
+ Bflush(&bso);
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ asmlc();
+ }
+ cflush();
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ default:
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lput((0413<<16)|0437L); /* magic and version */
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT-HEADR); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ break;
+ case 1: /* plan9 boot data goes into text */
+ lput(0407); /* magic */
+ lput(rnd(HEADR+textsize, INITRND)-HEADR+datsize); /* sizes */
+ lput(0);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 2: /* plan 9 */
+ lput(0407); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 3: /* next boot */
+ /* header */
+ lput(0xfeedfaceL); /* magic */
+ lput(6); /* 68040 */
+ lput(1); /* more 68040 */
+ lput(5); /* file type 'boot' */
+ lput(HEADTYPE); /* number commands */
+ lput(HEADR-7*4); /* sizeof commands */
+ lput(1); /* no undefineds */
+ /* command 1 text */
+ lput(1); /* command = 'segment' */
+ lput(124); /* command size */
+ s16put("__TEXT");
+ /* botch?? entryvalue() */
+ lput(INITTEXT); /* va of start */
+ lput(rnd(textsize, 8192)); /* va size */
+ lput(HEADR); /* file offset */
+ lput(rnd(textsize, 8192)); /* file size */
+ lput(7); /* max prot */
+ lput(7); /* init prot */
+ lput(1); /* number of sections */
+ lput(0); /* flags */
+ /* text section */
+ s16put("__text");
+ s16put("__TEXT");
+ /* botch?? entryvalue() */
+ lput(INITTEXT); /* va of start */
+ lput(textsize); /* va size */
+ lput(HEADR); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(0); /* flags */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* command 1 data */
+ lput(1); /* command = 'segment' */
+ lput(192); /* command size */
+ s16put("__DATA");
+ lput(INITDAT); /* va of start */
+ lput(rnd(datsize, 8192)); /* va size */
+ lput(HEADR+rnd(textsize, 8192)); /* file offset */
+ lput(rnd(datsize, 8192)); /* file size */
+ lput(7); /* max prot */
+ lput(7); /* init prot */
+ lput(2); /* number of sections */
+ lput(0); /* flags */
+ /* data section */
+ s16put("__data");
+ s16put("__DATA");
+ lput(INITDAT); /* va of start */
+ lput(datsize); /* va size */
+ lput(HEADR+rnd(textsize, 8192)); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(0); /* flags */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* bss section */
+ s16put("__bss");
+ s16put("__DATA");
+ lput(INITDAT+datsize); /* va of start */
+ lput(bsssize); /* va size */
+ lput(0); /* file offset */
+ lput(2); /* align */
+ lput(0); /* reloff */
+ lput(0); /* nreloc */
+ lput(1); /* flags = zero fill */
+ lput(0); /* reserved1 */
+ lput(0); /* reserved2 */
+ /* command 2 symbol */
+ lput(2); /* command = 'symbol' */
+ lput(24); /* command size */
+ lput(HEADR+rnd(textsize, INITRND)
+ +datsize); /* symoff */
+ lput(symsize); /* nsyms */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ }
+ cflush();
+}
+
+void
+asmins(Prog *p)
+{
+ Optab *o;
+ int t, a, b;
+ long v;
+ Prog *q;
+
+ op = opa + 1;
+ if(special[p->from.type])
+ switch(p->from.type) {
+
+ case D_CCR:
+ if(p->as != AMOVW)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x42c0 | a; /* mov from ccr */
+ return;
+
+ case D_SR:
+ if(p->as != AMOVW)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x40c0 | a; /* mov from sr */
+ return;
+
+ case D_USP:
+ if(p->as != AMOVL)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 010) {
+ opa[0] = 0x4e68|(a&7); /* mov usp An */
+ return;
+ }
+ t = 0x800;
+ goto movec1;
+
+ case D_SFC:
+ t = 0x000;
+ goto movec1;
+
+ case D_DFC:
+ t = 0x001;
+ goto movec1;
+
+ case D_CACR:
+ t = 0x002;
+ goto movec1;
+
+ case D_TC:
+ t = 0x003;
+ goto movec1;
+
+ case D_ITT0:
+ t = 0x004;
+ goto movec1;
+
+ case D_ITT1:
+ t = 0x005;
+ goto movec1;
+
+ case D_DTT0:
+ t = 0x006;
+ goto movec1;
+
+ case D_DTT1:
+ t = 0x007;
+ goto movec1;
+
+ case D_VBR:
+ t = 0x801;
+ goto movec1;
+
+ case D_CAAR:
+ t = 0x802;
+ goto movec1;
+
+ case D_MSP:
+ t = 0x803;
+ goto movec1;
+
+ case D_ISP:
+ t = 0x804;
+ goto movec1;
+
+ case D_MMUSR:
+ t = 0x805;
+ goto movec1;
+
+ case D_URP:
+ t = 0x806;
+ goto movec1;
+
+ case D_SRP:
+ t = 0x807;
+ goto movec1;
+
+ movec1:
+ if(p->as != AMOVL)
+ goto bad;
+ opa[0] = 0x4e7a; /* mov spc Dn */
+ a = asmea(p, &p->to);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ *op++ = (a<<12) | t;
+ return;
+ }
+ goto bad;
+
+ case D_FPCR:
+ t = 0xb000;
+ goto movec3;
+
+ case D_FPSR:
+ t = 0xa800;
+ goto movec3;
+
+ case D_FPIAR:
+ t = 0xa400;
+
+ movec3:
+ if(p->as != AMOVL)
+ goto bad;
+ op++;
+ a = asmea(p, &p->to);
+ opa[0] = optab[AFMOVEL].opcode0 | a;
+ opa[1] = t;
+ return;
+ }
+ if(special[p->to.type])
+ switch(p->to.type) {
+
+ case D_CCR:
+ if(p->as != AMOVW) /* botch, needs and, eor etc. */
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x44c0 | a; /* mov to ccr */
+ return;
+
+ case D_SR:
+ if(p->as != AMOVW) /* botch, needs and, eor etc. */
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010)
+ goto bad;
+ opa[0] = 0x46c0 | a; /* mov to sr */
+ return;
+
+ case D_USP:
+ if(p->as != AMOVL)
+ goto bad;
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010) {
+ opa[0] = 0x4e60|(a&7); /* mov An usp */
+ return;
+ }
+ t = 0x800;
+ goto movec2;
+
+ case D_SFC:
+ t = 0x000;
+ goto movec2;
+
+ case D_DFC:
+ t = 0x001;
+ goto movec2;
+
+ case D_CACR:
+ t = 0x002;
+ goto movec2;
+
+ case D_TC:
+ t = 0x003;
+ goto movec2;
+
+ case D_ITT0:
+ t = 0x004;
+ goto movec2;
+
+ case D_ITT1:
+ t = 0x005;
+ goto movec2;
+
+ case D_DTT0:
+ t = 0x006;
+ goto movec2;
+
+ case D_DTT1:
+ t = 0x007;
+ goto movec2;
+
+ case D_VBR:
+ t = 0x801;
+ goto movec2;
+
+ case D_CAAR:
+ t = 0x802;
+ goto movec2;
+
+ case D_MSP:
+ t = 0x803;
+ goto movec2;
+
+ case D_ISP:
+ t = 0x804;
+ goto movec2;
+
+ case D_MMUSR:
+ t = 0x805;
+ goto movec2;
+
+ case D_URP:
+ t = 0x806;
+ goto movec2;
+
+ case D_SRP:
+ t = 0x807;
+ goto movec2;
+
+ movec2:
+ if(p->as != AMOVL)
+ goto bad;
+ opa[0] = 0x4e7b; /* mov Dn spc */
+ a = asmea(p, &p->from);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ *op++ = (a<<12) | t;
+ return;
+ }
+ goto bad;
+
+ case D_FPCR:
+ t = 0x9000;
+ goto movec4;
+
+ case D_FPSR:
+ t = 0x8800;
+ goto movec4;
+
+ case D_FPIAR:
+ t = 0x8400;
+
+ movec4:
+ if(p->as != AMOVL)
+ goto bad;
+ op++;
+ a = asmea(p, &p->from);
+ opa[0] = optab[AFMOVEL].opcode0 | a;
+ opa[1] = t;
+ return;
+ }
+
+ o = &optab[p->as];
+ t = o->opcode0;
+ switch(o->optype) {
+ case 0: /* pseudo ops */
+ if(p->as != ATEXT && p->as != ANOP) {
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("unimplemented instruction in %s", TNAME);
+ return;
+ }
+ op = opa;
+ return;
+
+ case 1: /* branches */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ a = asmea(p, &p->to);
+ /* hack to turn 3-word bsr into 2-word jsr */
+ if(a == 0xff && p->as == ABSR &&
+ p->pcond->pc < 32768L && p->pcond->pc >= 0) {
+ op = opa + 1;
+ t = o->opcode1;
+ *op++ = p->pcond->pc;
+ break;
+ }
+ t |= a;
+ break;
+
+ case 2: /* move */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0110) { /* src quick */
+ t = o->opcode1;
+ if((b & 0170) != 0)
+ goto bad;
+ t |= a >> 7;
+ t |= b << 9;
+ break;
+ }
+ t |= a;
+ t |= (b&7) << 9;
+ t |= (b&070) << 3;
+ break;
+
+ case 3: /* add */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0110) { /* src quick */
+ t = o->opcode1;
+ t |= (a&01600) << 2;
+ t |= b;
+ break;
+ }
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+ }
+ if((b & 0170) == 010) { /* dst An */
+ if((t & 0xc0) == 0)
+ goto bad;
+ t = o->opcode2;
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t |= 0x100;
+ t |= (a & 7) << 9;
+ t |= b;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode3;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 4: /* no operands */
+ break;
+
+ case 5: /* tst */
+ t |= asmea(p, &p->to);
+ if((t&0170) == 010)
+ goto bad;
+ break;
+
+ case 6: /* lea */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) != 010)
+ goto bad;
+ t |= a;
+ t |= (b & 7) << 9;
+ break;
+
+ case 7: /* cmp */
+ b = asmea(p, &p->to);
+ a = asmea(p, &p->from);
+ if((a & 0170) == 010) { /* dst An */
+ t = o->opcode1;
+ if(t == 0) /* cmpb illegal */
+ goto bad;
+ t |= 0xc0;
+ t |= b;
+ t |= (a & 7) << 9;
+ break;
+ }
+ if((b & 0177) == 074) { /* src immed */
+ t = o->opcode2;
+ t |= a;
+ break;
+ }
+ if((a & 0170) == 0) { /* dst Dn */
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((b&0170) == 030 && (a&0170) == 030) { /* (A)+,(A)+ */
+ t = o->opcode3;
+ t |= b & 7;
+ t |= (a & 7) << 9;
+ break;
+ }
+ goto bad;
+
+ case 8: /* svc */
+ *op++ = optab[ARTS].opcode0;
+ break;
+
+ case 9: /* and */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= a;
+ t |= (b&7) << 9;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t = o->opcode1;
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode2;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 10: /* eor */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 010)
+ goto bad;
+ if((a & 0170) == 0) { /* src Dn */
+ t |= b;
+ t |= (a&7) << 9;
+ break;
+ }
+ if((a & 0177) == 074) { /* src immed */
+ t = o->opcode1;
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 11: /* ext */
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ t |= b;
+ break;
+ }
+ goto bad;
+
+ case 12: /* shift */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0177) == 0110) { /* src quick */
+ t |= (a & 01600) << 2;
+ t |= b;
+ break;
+ }
+ if((a & 0170) == 0) { /* src Dn */
+ t |= 0x20;
+ t |= a << 9;
+ t |= b;
+ break;
+ }
+ goto bad;
+ }
+ goto bad;
+
+ case 13: /* mul, div short */
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0170) == 010)
+ goto bad;
+ t |= a;
+ t |= b << 9;
+ break;
+ }
+ goto bad;
+
+ case 14: /* mul, div long */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) == 0) { /* dst Dn */
+ if((a & 0170) == 010)
+ goto bad;
+ t |= a;
+ opa[1] |= b << 12;
+ opa[1] |= b+1;
+ break;
+ }
+ goto bad;
+
+ case 15: /* dec and branch */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ a = asmea(p, &p->from);
+ if((a & 0170) != 0)
+ goto bad;
+ t |= a;
+ break;
+
+ case 16: /* fmove */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) == 0100) { /* src Fn */
+ if((b & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= b;
+ opa[1] = o->opcode2;
+ opa[1] |= (a&7) << 7;
+ break;
+ }
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ t |= a;
+ opa[1] = o->opcode3;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 17: /* floating ea,Fn */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((a & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 18: /* floating branchs */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ break;
+
+ case 19: /* floating dec and branch */
+ if(p->to.type != D_BRANCH)
+ goto bad;
+ *op++ = o->opcode1;
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L)
+ goto bad;
+ *op++ = v;
+ a = asmea(p, &p->from);
+ if((a & 0170) != 0)
+ goto bad;
+ t |= a;
+ break;
+
+ case 20: /* ftst ea */
+ *op++ = o->opcode1;
+ if(p->from.type != D_NONE)
+ goto bad;
+ a = asmea(p, &p->to);
+ if((a & 0170) == 0100) { /* Fn */
+ opa[1] |= (a&7) << 10;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ break;
+
+ case 21: /* fneg */
+ *op++ = o->opcode1;
+ if(p->from.type == D_NONE) {
+ b = asmea(p, &p->to);
+ a = b;
+ } else {
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ }
+ if((b & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((a & 0170) == 0100) { /* both Fn */
+ opa[1] |= (a&7) << 10;
+ opa[1] |= (b&7) << 7;
+ break;
+ }
+ t |= a;
+ opa[1] = o->opcode2;
+ opa[1] |= (b&7) << 7;
+ break;
+
+ case 22: /* floating cmp Fn,ea */
+ *op++ = o->opcode1;
+ a = asmea(p, &p->from);
+ b = asmea(p, &p->to);
+ if((a & 0170) != 0100) /* dst Fn */
+ goto bad;
+ if((b & 0170) == 0100) { /* both Fn */
+ opa[1] |= (b&7) << 10;
+ opa[1] |= (a&7) << 7;
+ break;
+ }
+ t |= b;
+ opa[1] = o->opcode2;
+ opa[1] |= (a&7) << 7;
+ break;
+
+ case 23: /* word, long */
+ op = opa;
+ a = asmea(p, &p->to);
+ if(a == ((7<<3)|4))
+ return;
+ if(a == ((7<<3)|1)) {
+ if(p->as == AWORD) {
+ op = opa;
+ *op++ = opa[1];
+ }
+ return;
+ }
+ if(a == ((7<<3)|0)) {
+ if(p->as == ALONG) {
+ *op++ = opa[0];
+ opa[0] = 0;
+ }
+ return;
+ }
+ goto bad;
+
+ case 24: /* bit field */
+ a = ((p->to.field&31)<<6) | (p->from.field&31);
+ if(p->as == ABFINS) {
+ b = asmea(p, &p->from);
+ if((b&0170) != 0)
+ goto bad;
+ a |= b<<12;
+ *op++ = a;
+ a = asmea(p, &p->to);
+ } else {
+ if(p->to.type != D_NONE) {
+ b = asmea(p, &p->to);
+ if((b&0170) != 0)
+ goto bad;
+ a |= b<<12;
+ }
+ *op++ = a;
+ a = asmea(p, &p->from);
+ }
+ t |= a;
+ a &= 0170;
+ if(a == 010 || a == 030 || a == 040 || a == 074)
+ goto bad;
+ break;
+
+ case 25: /* movem */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ asmea(p, &p->from);
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ t |= 0x400;
+ asmea(p, &p->to);
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 26: /* chk */
+ a = asmea(p, &p->from);
+ if((a&0170) == 010)
+ goto bad;
+ b = asmea(p, &p->to);
+ if((b&0170) != 0)
+ goto bad;
+ t |= a;
+ t |= b<<9;
+ break;
+
+ case 27: /* btst */
+ a = asmea(p, &p->from);
+ if(a == 074) {
+ t = o->opcode1;
+ } else
+ if((a&0170) != 0)
+ goto bad;
+ b = asmea(p, &p->to);
+ if(b == 074 || (b&0170) == 010)
+ goto bad;
+ t |= b;
+ break;
+
+ case 28: /* fmovem */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ b = p->from.offset & 0xff;
+ b |= 0xf000; /* control or postinc */
+ *op++ = b;
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ if(b == 040)
+ op[-1] &= ~0x1000; /* predec */
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ b = p->to.offset & 0xff;
+ b |= 0xd000; /* control or postinc */
+ *op++ = b;
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 29: /* fmovemc */
+ if(p->from.type == D_CONST) { /* registers -> memory */
+ b = (p->from.offset & 0x7) << 10;
+ b |= 0xa000;
+ *op++ = b;
+ a = asmea(p, &p->to);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 030)
+ goto bad;
+ t |= a;
+ break;
+ }
+ if(p->to.type == D_CONST) { /* memory -> registers */
+ b = (p->to.offset & 0x7) << 10;
+ b |= 0x8000;
+ *op++ = b;
+ a = asmea(p, &p->from);
+ if(a == 074)
+ goto bad;
+ b = a & 0170;
+ if(b == 000 || b == 010 || b == 040)
+ goto bad;
+ t |= a;
+ break;
+ }
+ goto bad;
+
+ case 30: /* trap */
+ if(p->to.type == D_CONST) {
+ t |= p->to.offset & 0xf;
+ break;
+ }
+ goto bad;
+
+ case 31: /* chk2, cmp2 */
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a == 000 || a == 010) {
+ *op++ = o->opcode1 | (b << 12);
+ t |= asmea(p, &p->from);
+ break;
+ }
+ goto bad;
+
+ case 32: /* casew */
+ /* jmp (0,pc,r0.w*1) */
+ casepc = p->pc;
+ *op++ = o->opcode1;
+ break;
+
+ case 33: /* bcase */
+ q = copyp(p);
+ q->as = ADATA;
+ q->to.type = D_CONST;
+ q->to.offset = p->pcond->pc - casepc - 2;
+ q->from.displace = 2;
+ q->link = datap;
+ datap = q;
+ if(debug['a'])
+ Bprint(&bso, "%P\n", q);
+ op = opa;
+ return;
+
+ case 34: /* moves */
+ op++;
+ a = asmea(p, &p->from);
+ b = a & 0170;
+ if(b == 0 || b == 010) {
+ opa[1] = (a << 12) | 0x800;
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a == 0 || a == 010)
+ goto bad;
+ t |= b;
+ break;
+ }
+ t |= a;
+ b = asmea(p, &p->to);
+ a = b & 0170;
+ if(a != 0 && a != 010)
+ goto bad;
+ opa[1] = (b << 12);
+ break;
+
+ case 35: /* swap */
+ a = asmea(p, &p->to);
+ if((a & 0170) == 0) {
+ t |= a;
+ break;
+ }
+ goto bad;
+ }
+ opa[0] = t;
+ return;
+
+bad:
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("bad combination of addressing in %s", TNAME);
+ opa[0] = 0;
+}
+
+int
+asmea(Prog *p, Adr *a)
+{
+ Optab *o;
+ int f, t, r, i;
+ short *top;
+ long v;
+
+ if(a->index != D_NONE)
+ goto index;
+ t = a->type;
+ r = simple[t];
+ v = a->offset;
+ if(r != 0177) {
+ if(v == 0)
+ return r;
+ if((r & 070) != 020)
+ return r;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return t-D_A0-I_INDIR+050; /* d(Ax) */
+ }
+ *op++ = 0x170; /* is, no indirect */
+ *op++ = v>>16;
+ *op++ = v;
+ return t-D_A0-I_INDIR+060; /* (d,Ax) */
+ }
+ f = 0;
+ if(a == &p->from)
+ f++;
+ o = &optab[p->as];
+ switch(t) {
+ case D_TOS:
+ if(f) {
+ if(o->srcsp)
+ return (3<<3) | 7; /* (A7)+ */
+ } else
+ if(o->dstsp)
+ return (4<<3) | 7; /* -(A7) */
+ return (2<<3) | 7; /* (A7) */
+
+ case D_BRANCH:
+ v = p->pcond->pc - p->pc - 2;
+ if(v < -32768L || v >= 32768L) {
+ *op++ = v>>16;
+ *op++ = v;
+ return 0xff;
+ }
+ if(v < -128 || v >= 128 || p->mark == 4) {
+ *op++ = v;
+ return 0;
+ }
+ return v & 0xff;
+
+ case I_ADDR|D_STATIC:
+ case I_ADDR|D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ v = a->sym->value + a->offset;
+ if(t != STEXT)
+ v += INITDAT;
+
+ case D_CONST:
+ switch(f? o->srcsp: o->dstsp) {
+ case 4:
+ *op++ = v>>16;
+
+ case 2:
+ *op++ = v;
+ break;
+
+ default:
+ diag("unknown srcsp asmea in %s", TNAME);
+ }
+ return (7<<3) | 4;
+
+ case D_FCONST:
+ r = f? o->srcsp: o->dstsp;
+ for(i=0; i<r; i++)
+ ((char*)op)[i] = gnuxi(&a->ieee, i, r);
+ op += r/2;
+ return (7<<3) | 4;
+
+ case D_QUICK:
+ v = a->offset & 0xff;
+ return 0110 | (v<<7);
+
+ case D_STACK:
+ case D_AUTO:
+ case D_PARAM:
+ if(v == 0)
+ return (2<<3) | 7; /* (A7) */
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (5<<3) | 7; /* d(A7) */
+ }
+ *op++ = 0x170; /* is, no indirect */
+ *op++ = v>>16;
+ *op++ = v;
+ return (6<<3) | 7; /* (d,A7) */
+
+ case I_INDIR|D_CONST:
+ goto adr;
+
+ case D_STATIC:
+ case D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ if(t == STEXT) {
+ v = a->sym->value + a->offset;
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ v = a->sym->value + a->offset - A6OFFSET;
+ if(debug['6']) {
+ v += INITDAT + A6OFFSET;
+ goto adr;
+ }
+ if(v == 0)
+ return (2<<3) | 6;
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (5<<3) | 6;
+ }
+ v += INITDAT + A6OFFSET;
+
+ adr:
+ if(v >= -32768L && v < 32768L) {
+ *op++ = v;
+ return (7<<3) | 0;
+ }
+ *op++ = v>>16;
+ *op++ = v;
+ return (7<<3) | 1;
+ }
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("unknown addressing mode: %d in %s", t, TNAME);
+ return 0;
+
+index:
+ top = op++;
+ t = a->index & D_MASK;
+ f = (a->scale & 7) << 9; /* w/l scale */
+ f |= (t & 7) << 12; /* register */
+ if(t < D_R0 || t >= D_R0+8) {
+ if(t >= D_A0 && t < D_A0+8) {
+ f |= 0x8000; /* d/a */
+ } else
+ if(t == D_NONE)
+ f = 0x40; /* is */
+ else
+ goto bad;
+ }
+
+ t = a->type;
+ r = t & 7;
+ v = a->offset;
+ if(t < (I_INDIR|D_A0) || t >= (I_INDIR|(D_A0+8)))
+ switch(t) {
+ default:
+ goto bad;
+
+ case I_INDIR|D_NONE:
+ f |= 0x80; /* bs */
+ r = 0;
+ break;
+
+ case D_AUTO:
+ case D_PARAM:
+ case D_STACK:
+ r = 7;
+ break;
+
+ case D_STATIC:
+ case D_EXTERN:
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ r = 6;
+ v += a->sym->value - A6OFFSET;
+ if(t == STEXT) {
+ f |= 0x80; /* bs */
+ r = 0;
+ v += A6OFFSET;
+ goto bdlong;
+ }
+ if(debug['6']) {
+ f |= 0x80; /* bs */
+ r = 0;
+ v += INITDAT + A6OFFSET;
+ }
+ }
+ if(v == 0)
+ f |= 0x10; /* bd size = null */
+ else
+ if(v >= -32768L && v < 32768L) {
+ f |= 0x20; /* bd size = word */
+ *op++ = v;
+ } else {
+ bdlong:
+ f |= 0x30; /* bd size = long */
+ *op++ = v>>16;
+ *op++ = v;
+ }
+ v = a->displace;
+ t = a->index & I_MASK;
+ if(t != I_INDEX1) { /* non-memory index */
+ if(t == I_INDEX2)
+ f |= 5; /* post indexing */
+ else
+ if(t == I_INDEX3)
+ f |= 1; /* pre indexing */
+ else
+ goto bad;
+ }
+ if(v != 0) {
+ if(v >= -32768L && v < 32768L) {
+ f++; /* is size = word */
+ *op++ = v;
+ } else {
+ f += 2; /* is size = long */
+ *op++ = v>>16;
+ *op++ = v;
+ }
+ }
+ *top = f | 0x100;
+ return (6<<3) | r;
+
+bad:
+ if(!debug['a'])
+ print("%P\n", p);
+ diag("bad operand in %s", TNAME);
+ return 0;
+}
+
+void
+lput(long l)
+{
+
+ CPUT(l>>24)
+ CPUT(l>>16)
+ CPUT(l>>8)
+ CPUT(l)
+}
+
+void
+s16put(char *n)
+{
+ char name[16];
+ int i;
+
+ strncpy(name, n, sizeof(name));
+ for(i=0; i<sizeof(name); i++)
+ CPUT(name[i])
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->from.displace;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ switch(p->to.type) {
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (char*)&fl;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j+4]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i+4]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.scon[i];
+ l++;
+ }
+ break;
+ default:
+ fl = p->to.offset;
+ if(p->to.sym) {
+ if(p->to.sym->type == STEXT)
+ fl += p->to.sym->value;
+ if(p->to.sym->type == SDATA)
+ fl += p->to.sym->value + INITDAT;
+ if(p->to.sym->type == SBSS)
+ fl += p->to.sym->value + INITDAT;
+ }
+
+ cast = (char*)&fl;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi1[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi2[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux",cast[inuxi4[j]] & 0xff);
+ Bprint(&bso, "\n");
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+int
+gnuxi(Ieee *d, int i, int c)
+{
+ char *p;
+ long l;
+
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ return 0;
+
+ /*
+ * 2301 vax
+ * 0123 68k
+ */
+ case 4:
+ l = ieeedtof(d);
+ p = (char*)&l;
+ i = gnuxi8[i+4];
+ break;
+
+ /*
+ * 67452301 vax
+ * 45670123 68k
+ */
+ case 8:
+ p = (char*)d;
+ i = gnuxi8[i];
+ break;
+ }
+ return p[i];
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/utils/2l/l.h b/utils/2l/l.h
new file mode 100644
index 00000000..8b03604c
--- /dev/null
+++ b/utils/2l/l.h
@@ -0,0 +1,263 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../2c/2.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext?curtext->from.sym->name:noname)
+#define CPUT(c)\
+ { *cbp++ = c;\
+ if(--cbc <= 0)\
+ cflush(); }
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+
+struct Adr
+{
+ short type;
+ short index;
+ union
+ {
+ struct
+ {
+ long u0displace;
+ long u0offset;
+ } s0;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ uchar field;
+ uchar scale;
+};
+
+#define displace u0.s0.u0displace
+#define offset u0.s0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0stkoff;
+ Prog *u0forwd;
+ } u0;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ long pc;
+ long line;
+ short as;
+ uchar mark; /* work on these */
+ uchar back;
+};
+
+#define stkoff u0.u0stkoff
+#define forwd u0.u0forwd
+
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ long value;
+ Sym* link;
+};
+struct Optab
+{
+ short as;
+ short fas;
+ short srcsp;
+ short dstsp;
+ ushort optype;
+ ushort opcode0;
+ ushort opcode1;
+ ushort opcode2;
+ ushort opcode3;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SAUTO,
+ SPARAM,
+ SFILE,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 4,
+ STRINGSZ = 200,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ A6OFFSET = 32766
+};
+
+EXTERN union
+{
+ struct
+ {
+ char obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+EXTERN long HEADR;
+EXTERN long HEADTYPE;
+EXTERN long INITDAT;
+EXTERN long INITRND;
+EXTERN long INITTEXT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN long casepc;
+EXTERN int cbc;
+EXTERN char* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi8[8];
+EXTERN char gnuxi8[8];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN long ncase;
+EXTERN long ndata;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long nsymbol;
+EXTERN char* noname;
+EXTERN short* op;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN char simple[I_MASK];
+EXTERN char special[I_MASK];
+EXTERN long spsize;
+EXTERN Sym* symlist;
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN Prog zprg;
+
+extern Optab optab[];
+extern char mmsize[];
+extern char* anames[];
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+int Xconv(Fmt*);
+void addhist(long, int);
+int andsize(Prog*, Adr*);
+Prog* appendp(Prog*);
+void asmb(void);
+int asmea(Prog*, Adr*);
+void asmins(Prog*);
+void asmlc(void);
+void asmsp(void);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void cflush(void);
+Prog* copyp(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+long entryvalue(void);
+void errorexit(void);
+int find1(long, int);
+int find2(long, int);
+void follow(void);
+void gethunk(void);
+int gnuxi(Ieee*, int, int);
+void histtoauto(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void main(int, char*[]);
+void mkfwd(void);
+void* mysbrk(ulong);
+void nuxiinit(void);
+void objfile(char*);
+void patch(void);
+Prog* prg(void);
+int relinv(int);
+long reuse(Prog*, Sym*);
+long rnd(long, long);
+void s16put(char*);
+void span(void);
+void undef(void);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+int zaddr(uchar*, Adr*, Sym*[]);
diff --git a/utils/2l/list.c b/utils/2l/list.c
new file mode 100644
index 00000000..1ebf488e
--- /dev/null
+++ b/utils/2l/list.c
@@ -0,0 +1,395 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+}
+
+static Prog *bigP;
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[20];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ sprint(str, "(%ld) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ if(p->from.field) {
+ sprint(s, ",%d,%d", p->to.field, p->from.field);
+ strcat(str, s);
+ }
+ bigP = P;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+
+ return fmtstrcpy(fp, anames[va_arg(fp->args, int)]);
+}
+
+int
+Xconv(Fmt *fp)
+{
+ char str[20], s[10];
+ int i0, i1;
+
+ str[0] = 0;
+ i0 = va_arg(fp->args, int) & D_MASK;
+ i1 = va_arg(fp->args, int);
+ if(i0 != D_NONE) {
+ sprint(str, "(%R.", i0);
+ sprint(s, "%c*%c)",
+ "WWWWLLLL"[i1],
+ "12481248"[i1]);
+ strcat(str, s);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i, j;
+ long d;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->index;
+ if(i != D_NONE) {
+ a->index = D_NONE;
+ d = a->displace;
+ a->displace = 0;
+ switch(i & I_MASK) {
+ default:
+ sprint(str, "???%ld(%D)", d, a);
+ break;
+
+ case I_INDEX1:
+ sprint(str, "%D", a);
+ break;
+
+ case I_INDEX2:
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_INDEX3:
+ if(d)
+ sprint(str, "%ld(%D", d, a);
+ else
+ sprint(str, "(%D", a);
+ break;
+ }
+
+ if(i != D_NONE) {
+ j = a->scale & 7;
+ sprint(strchr(str,0), "(%R.", i);
+ sprint(strchr(str,0), "%c*%c)",
+ "WWWWLLLL"[j],
+ "12481248"[j]);
+ }
+ if((i & I_MASK) == I_INDEX3)
+ strcat(str, ")");
+ a->displace = d;
+ a->index = i;
+ goto out;
+ }
+ i = a->type;
+ j = i & I_MASK;
+ if(j) {
+ a->type = i & D_MASK;
+ d = a->offset;
+ a->offset = 0;
+ switch(j) {
+ case I_INDINC:
+ sprint(str, "(%D)+", a);
+ break;
+
+ case I_INDDEC:
+ sprint(str, "-(%D)", a);
+ break;
+
+ case I_INDIR:
+ if(d)
+ sprint(str, "%ld(%D)", d, a);
+ else
+ sprint(str, "(%D)", a);
+ break;
+
+ case I_ADDR:
+ a->offset = d;
+ sprint(str, "$%D", a);
+ break;
+ }
+ a->type = i;
+ a->offset = d;
+ goto out;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ sprint(str, "%lux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ sprint(str, "%lux", bigP->pcond->pc);
+ else
+ sprint(str, "%ld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<%d>+%ld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_STACK:
+ sprint(str, "TOS+%ld", a->offset);
+ break;
+
+ case D_QUICK:
+ sprint(str, "$Q%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ goto out;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->scon);
+ goto out;
+ }
+ if(a->displace) {
+ sprint(s, "/%ld", a->displace);
+ strcat(str, s);
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_R0 && r < D_R0+NREG)
+ sprint(str, "R%d", r-D_R0);
+ else
+ if(r >= D_A0 && r < D_A0+NREG)
+ sprint(str, "A%d", r-D_A0);
+ else
+ if(r >= D_F0 && r < D_F0+NREG)
+ sprint(str, "F%d", r-D_F0);
+ else
+ switch(r) {
+
+ default:
+ sprint(str, "gok(%d)", r);
+ break;
+
+ case D_NONE:
+ sprint(str, "NONE");
+ break;
+
+ case D_TOS:
+ sprint(str, "TOS");
+ break;
+
+ case D_CCR:
+ sprint(str, "CCR");
+ break;
+
+ case D_SR:
+ sprint(str, "SR");
+ break;
+
+ case D_SFC:
+ sprint(str, "SFC");
+ break;
+
+ case D_DFC:
+ sprint(str, "DFC");
+ break;
+
+ case D_CACR:
+ sprint(str, "CACR");
+ break;
+
+ case D_USP:
+ sprint(str, "USP");
+ break;
+
+ case D_VBR:
+ sprint(str, "VBR");
+ break;
+
+ case D_CAAR:
+ sprint(str, "CAAR");
+ break;
+
+ case D_MSP:
+ sprint(str, "MSP");
+ break;
+
+ case D_ISP:
+ sprint(str, "ISP");
+ break;
+
+ case D_FPCR:
+ sprint(str, "FPCR");
+ break;
+
+ case D_FPSR:
+ sprint(str, "FPSR");
+ break;
+
+ case D_FPIAR:
+ sprint(str, "FPIAR");
+ break;
+
+ case D_TREE:
+ sprint(str, "TREE");
+ break;
+
+ case D_TC:
+ sprint(str, "TC");
+ break;
+
+ case D_ITT0:
+ sprint(str, "ITT0");
+ break;
+
+ case D_ITT1:
+ sprint(str, "ITT1");
+ break;
+
+ case D_DTT0:
+ sprint(str, "DTT0");
+ break;
+
+ case D_DTT1:
+ sprint(str, "DTT1");
+ break;
+
+ case D_MMUSR:
+ sprint(str, "MMUSR");
+ break;
+ case D_URP:
+ sprint(str, "URP");
+ break;
+
+ case D_SRP:
+ sprint(str, "SRP");
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/2l/mkfile b/utils/2l/mkfile
new file mode 100644
index 00000000..c52b5ce7
--- /dev/null
+++ b/utils/2l/mkfile
@@ -0,0 +1,26 @@
+<../../mkconfig
+
+TARG=2l
+OFILES=\
+ asm.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ list.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../2c/2.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9
+BIN=$ROOT/$OBJDIR/bin
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I ../include
+
+enam.$O: ../2c/enam.c
+ $CC $CFLAGS ../2c/enam.c
diff --git a/utils/2l/obj.c b/utils/2l/obj.c
new file mode 100644
index 00000000..f51d028b
--- /dev/null
+++ b/utils/2l/obj.c
@@ -0,0 +1,1402 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = '2';
+char *thestring = "68020";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is garbage unix
+ * -H1 -T0x80020000 -R4 is garbage format
+ * -H2 -T8224 -R8192 is plan9 format
+ * -H3 -Tx -Rx is next boot
+ */
+
+void
+main(int argc, char *argv[])
+{
+ int i, c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = "2.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0) {
+ diag("usage: 2l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 2;
+ if(debug['B'])
+ HEADTYPE = 2;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ if(INITDAT != -1 && INITRND == -1)
+ INITRND = 0;
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option %d", HEADTYPE);
+ errorexit();
+
+ case 0: /* this is garbage */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* plan9 boot data goes into text */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 8224;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 8224;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192;
+ break;
+ case 3: /* next boot */
+ HEADR = 28+124+192+24;
+ if(INITTEXT == -1)
+ INITTEXT = 0x04002000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 8192L;
+ break;
+ case 4: /* preprocess pilot */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITDAT != 0 && INITRND == -1)
+ INITRND = 0;
+ if(INITRND == -1)
+ INITRND = 32;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
+ }
+
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.from.index = D_NONE;
+ zprg.to = zprg.from;
+
+ memset(special, 0, sizeof(special));
+ special[D_CCR] = 1;
+ special[D_SR] = 1;
+ special[D_SFC] = 1;
+ special[D_CACR] = 1;
+ special[D_USP] = 1;
+ special[D_VBR] = 1;
+ special[D_CAAR] = 1;
+ special[D_MSP] = 1;
+ special[D_ISP] = 1;
+ special[D_DFC] = 1;
+ special[D_FPCR] = 1;
+ special[D_FPSR] = 1;
+ special[D_FPIAR] = 1;
+ special[D_TC] = 1;
+ special[D_ITT0] = 1;
+ special[D_ITT1] = 1;
+ special[D_DTT0] = 1;
+ special[D_DTT1] = 1;
+ special[D_MMUSR] = 1;
+ special[D_URP] = 1;
+ special[D_SRP] = 1;
+ memset(simple, 0177, sizeof(simple));
+ for(i=0; i<8; i++) {
+ simple[D_R0+i] = i;
+ simple[D_F0+i] = i+0100;
+ simple[D_A0+i] = i+010;
+ simple[D_A0+I_INDIR+i] = i+020;
+ simple[D_A0+I_INDINC+i] = i+030;
+ simple[D_A0+I_INDDEC+i] = i+040;
+ }
+ nuxiinit();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s", outfile);
+ errorexit();
+ }
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ errorexit();
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ follow();
+ dodata();
+ dostkoff();
+ span();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld+%ld = %ld data statements\n",
+ ndata, ncase, ndata+ncase);
+ Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ Bflush(&bso);
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int c, t, i;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ t = p[0];
+
+ /*
+ * first try the high-time formats
+ */
+ if(t == 0) {
+ a->index = D_NONE;
+ a->type = p[1];
+ return 2;
+ }
+ if(t == T_OFFSET) {
+ a->index = D_NONE;
+ a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
+ a->type = p[5];
+ return 6;
+ }
+ if(t == (T_OFFSET|T_SYM)) {
+ a->index = D_NONE;
+ a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
+ s = h[p[5]];
+ a->sym = s;
+ a->type = p[6];
+ c = 7;
+ goto dosym;
+ }
+ if(t == T_SYM) {
+ a->index = D_NONE;
+ s = h[p[1]];
+ a->sym = s;
+ a->type = p[2];
+ c = 3;
+ goto dosym;
+ }
+ if(t == (T_INDEX|T_OFFSET|T_SYM)) {
+ a->index = p[1] | (p[2]<<8);
+ a->scale = p[3];
+ a->displace = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
+ a->offset = p[8] | (p[9]<<8) | (p[10]<<16) | (p[11]<<24);
+ s = h[p[12]];
+ a->sym = s;
+ a->type = p[13];
+ c = 14;
+ goto dosym;
+ }
+
+ /*
+ * now do it the hard way
+ */
+ c = 1;
+ a->index = D_NONE;
+ if(t & T_FIELD) {
+ a->field = p[c] | (p[c+1]<<8);
+ c += 2;
+ }
+ if(t & T_INDEX) {
+ a->index = p[c] | (p[c+1]<<8);
+ a->scale = p[c+2];
+ a->displace = p[c+3] | (p[c+4]<<8) | (p[c+5]<<16) | (p[c+6]<<24);
+ c += 7;
+ }
+ if(t & T_OFFSET) {
+ a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ c += 4;
+ }
+ if(t & T_SYM) {
+ a->sym = h[p[c]];
+ c += 1;
+ }
+ if(t & T_FCONST) {
+ a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
+ c += 8;
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ for(i=0; i<NSNAME; i++)
+ a->scon[i] = p[c+i];
+ c += NSNAME;
+ a->type = D_SCONST;
+ } else
+ if(t & T_TYPE) {
+ a->type = p[c] | (p[c+1]<<8);
+ c += 2;
+ } else {
+ a->type = p[c];
+ c++;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+
+dosym:
+ t = a->type & D_MASK;
+ if(t != D_AUTO && t != D_PARAM)
+ return c;
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ Prog *p;
+ Sym *h[NSYM], *s;
+ int v, o, r;
+ long ipc, lv;
+ double dv;
+ uchar *bloc, *bsize, *stop;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0] | (bloc[1] << 8);
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .2 file\n");
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[2]; /* type */
+ o = bloc[3]; /* sym */
+ bloc += 4;
+ c -= 4;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+ p->back = 2;
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ goto loop;
+
+ case ABCASE:
+ ncase++;
+ goto casdef;
+
+ case ADATA:
+ p->link = datap;
+ datap = p;
+ ndata++;
+ goto loop;
+
+ case AGOK:
+ diag("%s: unknown opcode in %s", pn, TNAME);
+ pc++;
+ goto loop;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ curtext = p;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ s = p->from.sym;
+ if(s->type != 0 && s->type != SXREF)
+ diag("%s: redefinition: %s", pn, s->name);
+ s->type = STEXT;
+ s->value = p->pc;
+ pc++;
+ p->pcond = P;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->pcond = p;
+ etextp = p;
+ goto loop;
+
+ case AJSR:
+ p->as = ABSR;
+
+ case ABSR:
+ if(p->to.index != D_NONE)
+ p->as = AJSR;
+ if(p->to.type != D_EXTERN && p->to.type != D_STATIC)
+ p->as = AJSR;
+ goto casdef;
+
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv >= -128 && lv < 128)
+ if(p->to.type >= D_R0 && p->to.type < D_R0+8)
+ if(p->to.index == D_NONE) {
+ p->from.type = D_QUICK;
+ goto casdef;
+ }
+
+ if(lv >= -0x7fff && lv <= 0x7fff)
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8)
+ if(p->to.index == D_NONE)
+ if(p->as == AMOVL)
+ p->as = AMOVW;
+ goto casdef;
+
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv < 0) {
+ lv = -lv;
+ p->from.offset = lv;
+ if(p->as == AADDB)
+ p->as = ASUBB;
+ else
+ if(p->as == AADDW)
+ p->as = ASUBW;
+ else
+ if(p->as == AADDL)
+ p->as = ASUBL;
+ }
+ if(lv > 0)
+ if(lv <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST)
+ goto casdef;
+ lv = p->from.offset;
+ if(lv < 0) {
+ lv = -lv;
+ p->from.offset = lv;
+ if(p->as == ASUBB)
+ p->as = AADDB;
+ else
+ if(p->as == ASUBW)
+ p->as = AADDW;
+ else
+ if(p->as == ASUBL)
+ p->as = AADDL;
+ }
+ if(lv > 0)
+ if(lv <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case AROTRB:
+ case AROTRL:
+ case AROTRW:
+ case AROTLB:
+ case AROTLL:
+ case AROTLW:
+
+ case AASLB:
+ case AASLL:
+ case AASLW:
+ case AASRB:
+ case AASRL:
+ case AASRW:
+ case ALSLB:
+ case ALSLL:
+ case ALSLW:
+ case ALSRB:
+ case ALSRL:
+ case ALSRW:
+ if(p->from.type == D_CONST)
+ if(p->from.offset > 0)
+ if(p->from.offset <= 8)
+ p->from.type = D_QUICK;
+ goto casdef;
+
+ case ATSTL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8) {
+ p->as = ACMPW;
+ p->from = p->to;
+ p->to.type = D_CONST;
+ p->to.offset = 0;
+ }
+ goto casdef;
+
+ case ACMPL:
+ if(p->to.type != D_CONST)
+ goto casdef;
+ lv = p->to.offset;
+ if(lv >= -0x7fff && lv <= 0x7fff)
+ if(p->from.type >= D_A0 && p->from.type < D_A0+8)
+ if(p->from.index == D_NONE)
+ p->as = ACMPW;
+ goto casdef;
+
+ case ACLRL:
+ if(p->to.type >= D_A0 && p->to.type < D_A0+8) {
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(p->from.type == D_FCONST)
+ if(optab[p->as].fas != AXXX) {
+ dv = ieeedtod(&p->from.ieee);
+ if(dv >= -(1L<<30) && dv <= (1L<<30)) {
+ lv = dv;
+ if(lv == dv) {
+ p->as = optab[p->as].fas;
+ p->from.type = D_CONST;
+ p->from.offset = lv;
+ p->from.displace = 0;
+ }
+ }
+ }
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ goto loop;
+ }
+ goto loop;
+
+eof:
+ diag("%s: truncated object file in %s", pn, TNAME);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int l, c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ nsymbol++;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = q->link;
+ q->link = p;
+ p->line = q->line;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->as = AADDL;
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ q->from.type = D_CONST;
+ q->from.offset = 1;
+ q->to.type = D_EXTERN;
+ q->to.sym = s;
+ q->to.offset = n*4 + 4;
+
+ q = prg();
+ q->as = ADATA;
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.offset = n*4;
+ q->from.displace = 4;
+ q->to.type = D_EXTERN;
+ q->to.sym = p->from.sym;
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->as = ADATA;
+ q->link = datap;
+ datap = q;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.displace = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->from.displace = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->from.displace = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.displace != 0) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ABSR;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARTS) {
+ /*
+ * RTS
+ */
+ q = prg();
+ q->as = ARTS;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BSR profout
+ */
+ p->as = ABSR;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+long
+reuse(Prog *r, Sym *s)
+{
+ Prog *p;
+
+
+ if(r == P)
+ return 0;
+ for(p = datap; p != r; p = p->link)
+ if(p->to.sym == s)
+ return p->from.offset;
+ return 0;
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x01020304L, i+1);
+ if(i >= 2)
+ inuxi2[i-2] = c;
+ if(i >= 3)
+ inuxi1[i-3] = c;
+ inuxi4[i] = c;
+ fnuxi8[i] = c+4;
+ fnuxi8[i+4] = c;
+ c = find2(0x01020304L, i+1);
+ gnuxi8[i] = c+4;
+ gnuxi8[i+4] = c;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\n[fg]nuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", gnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+int
+find2(long l, int c)
+{
+ short *p;
+ int i;
+
+ p = (short*)&l;
+ for(i=0; i<4; i+=2) {
+ if(((*p >> 8) & 0xff) == c)
+ return i;
+ if((*p++ & 0xff) == c)
+ return i+1;
+ }
+ return 0;
+}
+
+long
+ieeedtof(Ieee *e)
+{
+ int exp;
+ long v;
+
+ if(e->h == 0)
+ return 0;
+ exp = (e->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (e->h & 0xfffffL) << 3;
+ v |= (e->l >> 29) & 0x7L;
+ if((e->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= e->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
diff --git a/utils/2l/optab.c b/utils/2l/optab.c
new file mode 100644
index 00000000..9f4527b7
--- /dev/null
+++ b/utils/2l/optab.c
@@ -0,0 +1,444 @@
+#include "l.h"
+
+#define X1 0
+#define X2 0
+#define X3 0
+#define C 0xf200
+
+Optab optab[] =
+/* as, fas, srcsp, dstsp, optype, opcode */
+{
+ { AXXX },
+ { AABCD, AXXX, X1, X2, X3, 0x4e71 },
+ { AADDB, AXXX, 2, 0, 3, 0xd000, 0x5000, 0, 0x0600 },
+ { AADDL, AXXX, 4, 0, 3, 0xd080, 0x5080, 0xd1c0, 0x0680 },
+ { AADDW, AXXX, 2, 0, 3, 0xd040, 0x5040, 0xd0c0, 0x0640 },
+ { AADDXB },
+ { AADDXL },
+ { AADDXW },
+ { AADJSP },
+ { AANDB, AXXX, 2, 0, 9, 0xc000, 0xc100, 0x0200 },
+ { AANDL, AXXX, 4, 0, 9, 0xc080, 0xc180, 0x0280 },
+ { AANDW, AXXX, 2, 0, 9, 0xc040, 0xc140, 0x0240 },
+ { AASLB, AXXX, 0, 2, 12, 0xe100 },
+ { AASLL, AXXX, 0, 4, 12, 0xe180 },
+ { AASLW, AXXX, 0, 2, 12, 0xe140 },
+ { AASRB, AXXX, 0, 2, 12, 0xe000 },
+ { AASRL, AXXX, 0, 4, 12, 0xe080 },
+ { AASRW, AXXX, 0, 2, 12, 0xe040 },
+ { ABCASE, AXXX, 0, 0, 33 },
+ { ABCC, AXXX, 0, 0, 1, 0x6400 },
+ { ABCHG, AXXX, 2, 2, 27, 0x0140, 0x0840 },
+ { ABCLR, AXXX, 2, 2, 27, 0x0180, 0x0880 },
+ { ABCS, AXXX, 0, 0, 1, 0x6500 },
+ { ABEQ, AXXX, 0, 0, 1, 0x6700 },
+ { ABFCHG, AXXX, 0, 0, 24, 0xeac0 },
+ { ABFCLR, AXXX, 0, 0, 24, 0xecc0 },
+ { ABFEXTS, AXXX, 0, 0, 24, 0xebc0 },
+ { ABFEXTU, AXXX, 0, 0, 24, 0xe9c0 },
+ { ABFFFO, AXXX, 0, 0, 24, 0xedc0 },
+ { ABFINS, AXXX, 0, 0, 24, 0xefc0 },
+ { ABFSET, AXXX, 0, 0, 24, 0xeec0 },
+ { ABFTST, AXXX, 0, 0, 24, 0xe8c0 },
+ { ABGE, AXXX, 0, 0, 1, 0x6c00 },
+ { ABGT, AXXX, 0, 0, 1, 0x6e00 },
+ { ABHI, AXXX, 0, 0, 1, 0x6200 },
+ { ABKPT },
+ { ABLE, AXXX, 0, 0, 1, 0x6f00 },
+ { ABLS, AXXX, 0, 0, 1, 0x6300 },
+ { ABLT, AXXX, 0, 0, 1, 0x6d00 },
+ { ABMI, AXXX, 0, 0, 1, 0x6b00 },
+ { ABNE, AXXX, 0, 0, 1, 0x6600 },
+ { ABPL, AXXX, 0, 0, 1, 0x6a00 },
+ { ABRA, AXXX, 0, 0, 1, 0x6000 },
+ { ABSET, AXXX, 2, 2, 27, 0x01c0, 0x08c0 },
+ { ABSR, AXXX, 0, 0, 1, 0x6100, 0x4eb8 },
+ { ABTST, AXXX, 2, 2, 27, 0x0100, 0x0800 },
+ { ABVC, AXXX, 0, 0, 1, 0x6800 },
+ { ABVS, AXXX, 0, 0, 1, 0x6900 },
+ { ACALLM },
+ { ACAS2B },
+ { ACAS2L },
+ { ACAS2W },
+ { ACASB },
+ { ACASEW, AXXX, 0, 0, 32, 0x4efb, 0 },
+ { ACASL },
+ { ACASW },
+ { ACHK2B, AXXX, 2, 0, 31, 0x00c0, 0x0800 },
+ { ACHK2L, AXXX, 4, 0, 31, 0x04c0, 0x0800 },
+ { ACHK2W, AXXX, 2, 0, 31, 0x02c0, 0x0800 },
+ { ACHKL, AXXX, 4, 4, 26, 0x4100 },
+ { ACHKW, AXXX, 2, 2, 26, 0x4180 },
+ { ACLRB, AXXX, 0, -2, 5, 0x4200 },
+ { ACLRL, AXXX, 0, -4, 5, 0x4280 },
+ { ACLRW, AXXX, 0, -2, 5, 0x4240 },
+ { ACMP2B, AXXX, 2, 0, 31, 0x00c0, 0x0000 },
+ { ACMP2L, AXXX, 4, 0, 31, 0x04c0, 0x0000 },
+ { ACMP2W, AXXX, 2, 0, 31, 0x02c0, 0x0000 },
+ { ACMPB, AXXX, 2, 2, 7, 0xb000, 0, 0x0c00, 0xb108 },
+ { ACMPL, AXXX, 4, 4, 7, 0xb080, 0xb100, 0x0c80, 0xb188 },
+ { ACMPW, AXXX, 2, 2, 7, 0xb040, 0xb080, 0x0c40, 0xb148 },
+ { ADATA },
+ { ADBCC, AXXX, 0, 0, 15, 0x54c8 },
+ { ADBCS, AXXX, 0, 0, 15, 0x55c8 },
+ { ADBEQ, AXXX, 0, 0, 15, 0x57c8 },
+ { ADBF, AXXX, 0, 0, 15, 0x51c8 },
+ { ADBGE, AXXX, 0, 0, 15, 0x5cc8 },
+ { ADBGT, AXXX, 0, 0, 15, 0x5ec8 },
+ { ADBHI, AXXX, 0, 0, 15, 0x52c8 },
+ { ADBLE, AXXX, 0, 0, 15, 0x5fc8 },
+ { ADBLS, AXXX, 0, 0, 15, 0x53c8 },
+ { ADBLT, AXXX, 0, 0, 15, 0x5dc8 },
+ { ADBMI, AXXX, 0, 0, 15, 0x5bc8 },
+ { ADBNE, AXXX, 0, 0, 15, 0x56c8 },
+ { ADBPL, AXXX, 0, 0, 15, 0x5ac8 },
+ { ADBT, AXXX, 0, 0, 15, 0x50c8 },
+ { ADBVC, AXXX, 0, 0, 15, 0x58c8 },
+ { ADBVS, AXXX, 0, 0, 15, 0x59c8 },
+ { ADIVSL, AXXX, 4, 0, 14, 0x4c40, 0x0800 },
+ { ADIVSW, AXXX, 2, 0, 13, 0x81c0 },
+ { ADIVUL, AXXX, 4, 0, 14, 0x4c40, 0x0000 },
+ { ADIVUW, AXXX, 2, 0, 13, 0x80c0 },
+ { AEND },
+ { AEORB, AXXX, 2, 0, 10, 0xb100, 0x0a00 },
+ { AEORL, AXXX, 4, 0, 10, 0xb180, 0x0a80 },
+ { AEORW, AXXX, 2, 0, 10, 0xb140, 0x0a40 },
+ { AEXG },
+ { AEXTBL, AXXX, 0, 0, 11, 0x49c0 },
+ { AEXTBW, AXXX, 0, 0, 11, 0x4880 },
+ { AEXTWL, AXXX, 0, 0, 11, 0x48c0 },
+ { AFABSB, AXXX, 2, 0, 17, C, 0x0018, 0x5818 },
+ { AFABSD, AFABSL, 8, 0, 17, C, 0x0018, 0x5418 },
+ { AFABSF, AFABSL, 4, 0, 17, C, 0x0018, 0x4418 },
+ { AFABSL, AXXX, 4, 0, 17, C, 0x0018, 0x4018 },
+ { AFABSW, AXXX, 2, 0, 17, C, 0x0018, 0x5018 },
+ { AFACOSB, AXXX, 2, 0, 17, C, 0x001c, 0x581c },
+ { AFACOSD, AFACOSL, 8, 0, 17, C, 0x001c, 0x541c },
+ { AFACOSF, AFACOSL, 4, 0, 17, C, 0x001c, 0x441c },
+ { AFACOSL, AXXX, 4, 0, 17, C, 0x001c, 0x401c },
+ { AFACOSW, AXXX, 2, 0, 17, C, 0x001c, 0x501c },
+ { AFADDB, AXXX, 2, 0, 17, C, 0x0022, 0x5822 },
+ { AFADDD, AFADDL, 8, 0, 17, C, 0x0022, 0x5422 },
+ { AFADDF, AFADDL, 4, 0, 17, C, 0x0022, 0x4422 },
+ { AFADDL, AXXX, 4, 0, 17, C, 0x0022, 0x4022 },
+ { AFADDW, AXXX, 2, 0, 17, C, 0x0022, 0x5022 },
+ { AFASINB, AXXX, 2, 0, 17, C, 0x000c, 0x580c },
+ { AFASIND, AFASINL, 8, 0, 17, C, 0x000c, 0x540c },
+ { AFASINF, AFASINL, 4, 0, 17, C, 0x000c, 0x440c },
+ { AFASINL, AXXX, 4, 0, 17, C, 0x000c, 0x400c },
+ { AFASINW, AXXX, 2, 0, 17, C, 0x000c, 0x500c },
+ { AFATANB, AXXX, 2, 0, 17, C, 0x000a, 0x580a },
+ { AFATAND, AFATANL, 8, 0, 17, C, 0x000a, 0x540a },
+ { AFATANF, AFATANL, 4, 0, 17, C, 0x000a, 0x440a },
+ { AFATANHB, AXXX, 2, 0, 17, C, 0x000d, 0x580d },
+ { AFATANHD, AFATANHL, 8, 0, 17, C, 0x000d, 0x540d },
+ { AFATANHF, AFATANHL, 4, 0, 17, C, 0x000d, 0x440d },
+ { AFATANHL, AXXX, 4, 0, 17, C, 0x000d, 0x400d },
+ { AFATANHW, AXXX, 2, 0, 17, C, 0x000d, 0x500d },
+ { AFATANL, AXXX, 4, 0, 17, C, 0x000a, 0x400a },
+ { AFATANW, AXXX, 2, 0, 17, C, 0x000a, 0x500a },
+ { AFBEQ, AXXX, 0, 0, 18, C+0x81 },
+ { AFBF, AXXX, 0, 0, 18, C+0x8f },
+ { AFBGE, AXXX, 0, 0, 18, C+0x93 },
+ { AFBGT, AXXX, 0, 0, 18, C+0x92 },
+ { AFBLE, AXXX, 0, 0, 18, C+0x95 },
+ { AFBLT, AXXX, 0, 0, 18, C+0x94 },
+ { AFBNE, AXXX, 0, 0, 18, C+0x8e },
+ { AFBT, AXXX, 0, 0, 18, C+0x80 },
+ { AFCMPB, AXXX, 0, 2, 22, C, 0x0038, 0x5838 },
+ { AFCMPD, AFCMPL, 0, 8, 22, C, 0x0038, 0x5438 },
+ { AFCMPF, AFCMPL, 0, 4, 22, C, 0x0038, 0x4438 },
+ { AFCMPL, AXXX, 0, 4, 22, C, 0x0038, 0x4038 },
+ { AFCMPW, AXXX, 0, 2, 22, C, 0x0038, 0x5038 },
+ { AFCOSB, AXXX, 2, 0, 17, C, 0x001d, 0x581d },
+ { AFCOSD, AFCOSL, 8, 0, 17, C, 0x001d, 0x541d },
+ { AFCOSF, AFCOSL, 4, 0, 17, C, 0x001d, 0x441d },
+ { AFCOSHB, AXXX, 2, 0, 17, C, 0x0019, 0x5819 },
+ { AFCOSHD, AFCOSHL, 8, 0, 17, C, 0x0019, 0x5419 },
+ { AFCOSHF, AFCOSHL, 4, 0, 17, C, 0x0019, 0x4419 },
+ { AFCOSHL, AXXX, 4, 0, 17, C, 0x0019, 0x4019 },
+ { AFCOSHW, AXXX, 2, 0, 17, C, 0x0019, 0x5019 },
+ { AFCOSL, AXXX, 4, 0, 17, C, 0x001d, 0x401d },
+ { AFCOSW, AXXX, 2, 0, 17, C, 0x001d, 0x501d },
+ { AFDBEQ, AXXX, 0, 0, 19, C+0x48, 0x01 },
+ { AFDBF, AXXX, 0, 0, 19, C+0x48, 0x0f },
+ { AFDBGE, AXXX, 0, 0, 19, C+0x48, 0x13 },
+ { AFDBGT, AXXX, 0, 0, 19, C+0x48, 0x12 },
+ { AFDBLE, AXXX, 0, 0, 19, C+0x48, 0x15 },
+ { AFDBLT, AXXX, 0, 0, 19, C+0x48, 0x14 },
+ { AFDBNE, AXXX, 0, 0, 19, C+0x48, 0x0e },
+ { AFDBT, AXXX, 0, 0, 19, C+0x48, 0x00 },
+ { AFDIVB, AXXX, 2, 0, 17, C, 0x0020, 0x5820 },
+ { AFDIVD, AFDIVL, 8, 0, 17, C, 0x0020, 0x5420 },
+ { AFDIVF, AFDIVL, 4, 0, 17, C, 0x0020, 0x4420 },
+ { AFDIVL, AXXX, 4, 0, 17, C, 0x0020, 0x4020 },
+ { AFDIVW, AXXX, 2, 0, 17, C, 0x0020, 0x5020 },
+ { AFETOXB, AXXX, 2, 0, 17, C, 0x0010, 0x5810 },
+ { AFETOXD, AFETOXL, 8, 0, 17, C, 0x0010, 0x5410 },
+ { AFETOXF, AFETOXL, 4, 0, 17, C, 0x0010, 0x4410 },
+ { AFETOXL, AXXX, 4, 0, 17, C, 0x0010, 0x4010 },
+ { AFETOXM1B, AXXX, 2, 0, 17, C, 0x0008, 0x5808 },
+ { AFETOXM1D, AFETOXM1L, 8, 0, 17, C, 0x0008, 0x5408 },
+ { AFETOXM1F, AFETOXM1L, 4, 0, 17, C, 0x0008, 0x4408 },
+ { AFETOXM1L, AXXX, 4, 0, 17, C, 0x0008, 0x4008 },
+ { AFETOXM1W, AXXX, 2, 0, 17, C, 0x0008, 0x5008 },
+ { AFETOXW, AXXX, 2, 0, 17, C, 0x0010, 0x5010 },
+ { AFGETEXPB, AXXX, 2, 0, 17, C, 0x001e, 0x581e },
+ { AFGETEXPD, AFGETEXPL, 8, 0, 17, C, 0x001e, 0x541e },
+ { AFGETEXPF, AFGETEXPL, 4, 0, 17, C, 0x001e, 0x441e },
+ { AFGETEXPL, AXXX, 4, 0, 17, C, 0x001e, 0x401e },
+ { AFGETEXPW, AXXX, 2, 0, 17, C, 0x001e, 0x501e },
+ { AFGETMANB, AXXX, 2, 0, 17, C, 0x001f, 0x581f },
+ { AFGETMAND, AFGETMANL, 8, 0, 17, C, 0x001f, 0x541f },
+ { AFGETMANF, AFGETMANL, 4, 0, 17, C, 0x001f, 0x441f },
+ { AFGETMANL, AXXX, 4, 0, 17, C, 0x001f, 0x401f },
+ { AFGETMANW, AXXX, 2, 0, 17, C, 0x001f, 0x501f },
+ { AFINTB, AXXX, 2, 0, 17, C, 0x0001, 0x5801 },
+ { AFINTD, AFINTL, 8, 0, 17, C, 0x0001, 0x5401 },
+ { AFINTF, AFINTL, 4, 0, 17, C, 0x0001, 0x4401 },
+ { AFINTL, AXXX, 4, 0, 17, C, 0x0001, 0x4001 },
+ { AFINTRZB, AXXX, 2, 0, 17, C, 0x0003, 0x5803 },
+ { AFINTRZD, AFINTRZL, 8, 0, 17, C, 0x0003, 0x5403 },
+ { AFINTRZF, AFINTRZL, 4, 0, 17, C, 0x0003, 0x4403 },
+ { AFINTRZL, AXXX, 4, 0, 17, C, 0x0003, 0x4003 },
+ { AFINTRZW, AXXX, 2, 0, 17, C, 0x0003, 0x5003 },
+ { AFINTW, AXXX, 2, 0, 17, C, 0x0001, 0x5001 },
+ { AFLOG10B, AXXX, 2, 0, 17, C, 0x0015, 0x5815 },
+ { AFLOG10D, AFLOG10L, 8, 0, 17, C, 0x0015, 0x5415 },
+ { AFLOG10F, AFLOG10L, 4, 0, 17, C, 0x0015, 0x4415 },
+ { AFLOG10L, AXXX, 4, 0, 17, C, 0x0015, 0x4015 },
+ { AFLOG10W, AXXX, 2, 0, 17, C, 0x0015, 0x5015 },
+ { AFLOG2B, AXXX, 2, 0, 17, C, 0x0016, 0x5816 },
+ { AFLOG2D, AFLOG2L, 8, 0, 17, C, 0x0016, 0x5416 },
+ { AFLOG2F, AFLOG2L, 4, 0, 17, C, 0x0016, 0x4416 },
+ { AFLOG2L, AXXX, 4, 0, 17, C, 0x0016, 0x4016 },
+ { AFLOG2W, AXXX, 2, 0, 17, C, 0x0016, 0x5016 },
+ { AFLOGNB, AXXX, 2, 0, 17, C, 0x0014, 0x5814 },
+ { AFLOGND, AFLOGNL, 8, 0, 17, C, 0x0014, 0x5414 },
+ { AFLOGNF, AFLOGNL, 4, 0, 17, C, 0x0014, 0x4414 },
+ { AFLOGNL, AXXX, 4, 0, 17, C, 0x0014, 0x4014 },
+ { AFLOGNP1B, AXXX, 2, 0, 17, C, 0x0006, 0x5806 },
+ { AFLOGNP1D, AFLOGNP1L, 8, 0, 17, C, 0x0006, 0x5406 },
+ { AFLOGNP1F, AFLOGNP1L, 4, 0, 17, C, 0x0006, 0x4406 },
+ { AFLOGNP1L, AXXX, 4, 0, 17, C, 0x0006, 0x4006 },
+ { AFLOGNP1W, AXXX, 2, 0, 17, C, 0x0006, 0x5006 },
+ { AFLOGNW, AXXX, 2, 0, 17, C, 0x0014, 0x5014 },
+ { AFMODB, AXXX, 2, 0, 17, C, 0x0021, 0x5821 },
+ { AFMODD, AFMODL, 8, 0, 17, C, 0x0021, 0x5421 },
+ { AFMODF, AFMODL, 4, 0, 17, C, 0x0021, 0x4421 },
+ { AFMODL, AXXX, 4, 0, 17, C, 0x0021, 0x4021 },
+ { AFMODW, AXXX, 2, 0, 17, C, 0x0021, 0x5021 },
+ { AFMOVEB, AXXX, 2, -2, 16, C, 0x0000, 0x7800, 0x5800 },
+ { AFMOVED, AFMOVEL, 8, -8, 16, C, 0x0000, 0x7400, 0x5400 },
+ { AFMOVEF, AFMOVEL, 4, -4, 16, C, 0x0000, 0x6400, 0x4400 },
+ { AFMOVEL, AXXX, 4, -4, 16, C, 0x0000, 0x6000, 0x4000 },
+ { AFMOVEM, AXXX, 2, 2, 28, C },
+ { AFMOVEMC, AXXX, 2, 2, 29, C },
+ { AFMOVEW, AXXX, 2, -2, 16, C, 0x0000, 0x7000, 0x5000 },
+ { AFMULB, AXXX, 2, 0, 17, C, 0x0023, 0x5823 },
+ { AFMULD, AFMULL, 8, 0, 17, C, 0x0023, 0x5423 },
+ { AFMULF, AFMULL, 4, 0, 17, C, 0x0023, 0x4423 },
+ { AFMULL, AXXX, 4, 0, 17, C, 0x0023, 0x4023 },
+ { AFMULW, AXXX, 2, 0, 17, C, 0x0023, 0x5023 },
+ { AFNEGB, AXXX, 2, 0, 21, C, 0x001a, 0x581a },
+ { AFNEGD, AFNEGL, 8, 0, 21, C, 0x001a, 0x541a },
+ { AFNEGF, AFNEGL, 4, 0, 21, C, 0x001a, 0x441a },
+ { AFNEGL, AXXX, 4, 0, 21, C, 0x001a, 0x401a },
+ { AFNEGW, AXXX, 2, 0, 21, C, 0x001a, 0x501a },
+ { AFREMB, AXXX, 2, 0, 17, C, 0x0025, 0x5825 },
+ { AFREMD, AFREML, 8, 0, 17, C, 0x0025, 0x5425 },
+ { AFREMF, AFREML, 4, 0, 17, C, 0x0025, 0x4425 },
+ { AFREML, AXXX, 4, 0, 17, C, 0x0025, 0x4025 },
+ { AFREMW, AXXX, 2, 0, 17, C, 0x0025, 0x5025 },
+ { AFRESTORE, AXXX, 0, 2, 5, C+0x0140 },
+ { AFSAVE, AXXX, 0, 2, 5, C+0x0100 },
+ { AFSCALEB, AXXX, 2, 0, 17, C, 0x0026, 0x5826 },
+ { AFSCALED, AFSCALEL, 8, 0, 17, C, 0x0026, 0x5426 },
+ { AFSCALEF, AFSCALEL, 4, 0, 17, C, 0x0026, 0x4426 },
+ { AFSCALEL, AXXX, 4, 0, 17, C, 0x0026, 0x4026 },
+ { AFSCALEW, AXXX, 2, 0, 17, C, 0x0026, 0x5026 },
+ { AFSEQ, AXXX, X1, X2, X3, 0xffff },
+ { AFSF, AXXX, 4, X2, X3, 0xffff },
+ { AFSGE, AXXX, X1, X2, X3, 0xffff },
+ { AFSGT, AXXX, X1, X2, X3, 0xffff },
+ { AFSINB, AXXX, 2, 0, 17, C, 0x000e, 0x580e },
+ { AFSIND, AFSINL, 8, 0, 17, C, 0x000e, 0x540e },
+ { AFSINF, AFSINL, 4, 0, 17, C, 0x000e, 0x440e },
+ { AFSINHB, AXXX, 2, 0, 17, C, 0x0002, 0x5802 },
+ { AFSINHD, AFSINHL, 8, 0, 17, C, 0x0002, 0x5402 },
+ { AFSINHF, AFSINHL, 4, 0, 17, C, 0x0002, 0x4402 },
+ { AFSINHL, AXXX, 4, 0, 17, C, 0x0002, 0x4002 },
+ { AFSINHW, AXXX, 2, 0, 17, C, 0x0002, 0x5002 },
+ { AFSINL, AXXX, 4, 0, 17, C, 0x000e, 0x400e },
+ { AFSINW, AXXX, 2, 0, 17, C, 0x000e, 0x500e },
+ { AFSLE, AXXX, X1, X2, X3, 0xffff },
+ { AFSLT, AXXX, X1, X2, X3, 0xffff },
+ { AFSNE, AXXX, X1, X2, X3, 0xffff },
+ { AFSQRTB, AXXX, 2, 0, 17, C, 0x0004, 0x5804 },
+ { AFSQRTD, AFSQRTL, 8, 0, 17, C, 0x0004, 0x5404 },
+ { AFSQRTF, AFSQRTL, 4, 0, 17, C, 0x0004, 0x4404 },
+ { AFSQRTL, AXXX, 4, 0, 17, C, 0x0004, 0x4004 },
+ { AFSQRTW, AXXX, 2, 0, 17, C, 0x0004, 0x5004 },
+ { AFST, AXXX, X1, X2, X3, 0xffff },
+ { AFSUBB, AXXX, 2, 0, 17, C, 0x0028, 0x5828 },
+ { AFSUBD, AFSUBL, 8, 0, 17, C, 0x0028, 0x5428 },
+ { AFSUBF, AFSUBL, 4, 0, 17, C, 0x0028, 0x4428 },
+ { AFSUBL, AXXX, 4, 0, 17, C, 0x0028, 0x4028 },
+ { AFSUBW, AXXX, 2, 0, 17, C, 0x0028, 0x5028 },
+ { AFTANB, AXXX, 2, 0, 17, C, 0x000f, 0x580f },
+ { AFTAND, AFTANL, 8, 0, 17, C, 0x000f, 0x540f },
+ { AFTANF, AFTANL, 4, 0, 17, C, 0x000f, 0x440f },
+ { AFTANHB, AXXX, 2, 0, 17, C, 0x0009, 0x5809 },
+ { AFTANHD, AFTANHL, 8, 0, 17, C, 0x0009, 0x5409 },
+ { AFTANHF, AFTANHL, 4, 0, 17, C, 0x0009, 0x4409 },
+ { AFTANHL, AXXX, 4, 0, 17, C, 0x0009, 0x4009 },
+ { AFTANHW, AXXX, 2, 0, 17, C, 0x0009, 0x5009 },
+ { AFTANL, AXXX, 4, 0, 17, C, 0x000f, 0x400f },
+ { AFTANW, AXXX, 2, 0, 17, C, 0x000f, 0x500f },
+ { AFTENTOXB, AXXX, 2, 0, 17, C, 0x0012, 0x5812 },
+ { AFTENTOXD, AFTENTOXL, 8, 0, 17, C, 0x0012, 0x5412 },
+ { AFTENTOXF, AFTENTOXL, 4, 0, 17, C, 0x0012, 0x4412 },
+ { AFTENTOXL, AXXX, 4, 0, 17, C, 0x0012, 0x4012 },
+ { AFTENTOXW, AXXX, 2, 0, 17, C, 0x0012, 0x5012 },
+ { AFTSTB, AXXX, 0, 2, 20, C, 0x003a, 0x583a },
+ { AFTSTD, AFTSTL, 0, 8, 20, C, 0x003a, 0x543a },
+ { AFTSTF, AFTSTL, 0, 4, 20, C, 0x003a, 0x443a },
+ { AFTSTL, AXXX, 0, 4, 20, C, 0x003a, 0x403a },
+ { AFTSTW, AXXX, 0, 2, 20, C, 0x003a, 0x503a },
+ { AFTWOTOXB, AXXX, 2, 0, 17, C, 0x0011, 0x5811 },
+ { AFTWOTOXD, AFTWOTOXL, 8, 0, 17, C, 0x0011, 0x5411 },
+ { AFTWOTOXF, AFTWOTOXL, 4, 0, 17, C, 0x0011, 0x4411 },
+ { AFTWOTOXL, AXXX, 4, 0, 17, C, 0x0011, 0x4011 },
+ { AFTWOTOXW, AXXX, 2, 0, 17, C, 0x0011, 0x5011 },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AILLEG, AXXX, 0, 0, 4, 0x4efc },
+ { AINSTR },
+ { AJMP, AXXX, 0, 0, 5, 0x4ec0 },
+ { AJSR, AXXX, 0, 0, 5, 0x4e80 },
+ { ALEA, AXXX, 0, 0, 6, 0x41c0 },
+ { ALINKL },
+ { ALINKW },
+ { ALOCATE },
+ { ALONG, AXXX, 0, 4, 23 },
+ { ALSLB, AXXX, 0, 2, 12, 0xe108 },
+ { ALSLL, AXXX, 0, 4, 12, 0xe188 },
+ { ALSLW, AXXX, 0, 2, 12, 0xe148 },
+ { ALSRB, AXXX, 0, 2, 12, 0xe008 },
+ { ALSRL, AXXX, 0, 4, 12, 0xe088 },
+ { ALSRW, AXXX, 0, 2, 12, 0xe048 },
+ { AMOVB, AXXX, 2, -2, 2, 0x1000, 0x7000 },
+ { AMOVEM, AXXX, 2, 2, 25, 0x48c0 },
+ { AMOVEPL },
+ { AMOVEPW },
+ { AMOVESB, AXXX, 2, -2, 34, 0xe00 },
+ { AMOVESL, AXXX, 4, -4, 34, 0xe80 },
+ { AMOVESW, AXXX, 2, -2, 34, 0xe40 },
+ { AMOVL, AXXX, 4, -4, 2, 0x2000, 0x7000 },
+ { AMOVW, AXXX, 2, -2, 2, 0x3000, 0x7000 },
+ { AMULSL, AXXX, 4, 0, 14, 0x4c00, 0x0800 },
+ { AMULSW, AXXX, 2, 0, 13, 0xc1c0 },
+ { AMULUL, AXXX, 4, 0, 14, 0x4c00, 0x0000 },
+ { AMULUW, AXXX, 2, 0, 13, 0xc0c0 },
+ { ANAME },
+ { ANBCD },
+ { ANEGB, AXXX, 0, 0, 5, 0x4400 },
+ { ANEGL, AXXX, 0, 0, 5, 0x4480 },
+ { ANEGW, AXXX, 0, 0, 5, 0x4440 },
+ { ANEGXB },
+ { ANEGXL },
+ { ANEGXW },
+ { ANOP },
+ { ANOTB, AXXX, 0, 0, 5, 0x4600 },
+ { ANOTL, AXXX, 0, 0, 5, 0x4680 },
+ { ANOTW, AXXX, 0, 0, 5, 0x4640 },
+ { AORB, AXXX, 2, 0, 9, 0x8000, 0x8100, 0x0000 },
+ { AORL, AXXX, 4, 0, 9, 0x8080, 0x8180, 0x0080 },
+ { AORW, AXXX, 2, 0, 9, 0x8040, 0x8140, 0x0040 },
+ { APACK },
+ { APEA, AXXX, 0, 0, 5, 0x4840 },
+ { ARESET },
+ { AROTLB, AXXX, 0, 2, 12, 0xe118 },
+ { AROTLL, AXXX, 0, 4, 12, 0xe198 },
+ { AROTLW, AXXX, 0, 2, 12, 0xe158 },
+ { AROTRB, AXXX, 0, 2, 12, 0xe018 },
+ { AROTRL, AXXX, 0, 4, 12, 0xe098 },
+ { AROTRW, AXXX, 0, 2, 12, 0xe058 },
+ { AROXLB },
+ { AROXLL },
+ { AROXLW },
+ { AROXRB },
+ { AROXRL },
+ { AROXRW },
+ { ARTD },
+ { ARTE, AXXX, 0, 0, 4, 0x4e73 },
+ { ARTM },
+ { ARTR },
+ { ARTS, AXXX, 0, 0, 4, 0x4e75 },
+ { ASBCD },
+ { ASCC },
+ { ASCS },
+ { ASEQ },
+ { ASF },
+ { ASGE },
+ { ASGT },
+ { ASHI },
+ { ASLE },
+ { ASLS },
+ { ASLT },
+ { ASMI },
+ { ASNE },
+ { ASPL },
+ { AST },
+ { ASTOP },
+ { ASUBB, AXXX, 2, 0, 3, 0x9000, 0x5100, 0, 0x0400 },
+ { ASUBL, AXXX, 4, 0, 3, 0x9080, 0x5180, 0x91c0, 0x0480 },
+ { ASUBW, AXXX, 2, 0, 3, 0x9040, 0x5140, 0x90c0, 0x0440 },
+ { ASUBXB },
+ { ASUBXL },
+ { ASUBXW },
+ { ASVC },
+ { ASVS },
+ { ASWAP, AXXX, 0, 0, 35, 0x4840 },
+ { ASYS, AXXX, 0, 2, 8, 0x4e40 },
+ { ATAS, AXXX, 0, 2, 5, 0x4ac0 },
+ { ATEXT },
+ { ATRAP, AXXX, 0, 0, 30, 0x4e40 },
+ { ATRAPCC, AXXX, 0, 0, 4, 0x54fc },
+ { ATRAPCS, AXXX, 0, 0, 4, 0x55fc },
+ { ATRAPEQ, AXXX, 0, 0, 4, 0x57fc },
+ { ATRAPF, AXXX, 0, 0, 4, 0x51fc },
+ { ATRAPGE, AXXX, 0, 0, 4, 0x5cfc },
+ { ATRAPGT, AXXX, 0, 0, 4, 0x5efc },
+ { ATRAPHI, AXXX, 0, 0, 4, 0x52fc },
+ { ATRAPLE, AXXX, 0, 0, 4, 0x5ffc },
+ { ATRAPLS, AXXX, 0, 0, 4, 0x53fc },
+ { ATRAPLT, AXXX, 0, 0, 4, 0x5dfc },
+ { ATRAPMI, AXXX, 0, 0, 4, 0x5bfc },
+ { ATRAPNE, AXXX, 0, 0, 4, 0x56fc },
+ { ATRAPPL, AXXX, 0, 0, 4, 0x5afc },
+ { ATRAPT, AXXX, 0, 0, 4, 0x50fc },
+ { ATRAPV, AXXX, 0, 0, 4, 0x4e76 },
+ { ATRAPVC, AXXX, 0, 0, 4, 0x58fc },
+ { ATRAPVS, AXXX, 0, 0, 4, 0x59fc },
+ { ATSTB, AXXX, 0, 2, 5, 0x4a00 },
+ { ATSTL, AXXX, 0, 4, 5, 0x4a80 },
+ { ATSTW, AXXX, 0, 2, 5, 0x4a40 },
+ { AUNLK },
+ { AUNPK },
+ { AWORD, AXXX, 0, 2, 23 },
+ { AXXX }
+};
+
+char mmsize[] =
+{
+ /* 0 */ 0, 2, 2, 2, 2,
+ /* 5 */ 2, 2, 2, 4, 2,
+ /* 10 */ 2, 2, 2, 2, 4,
+ /* 15 */ 4, 4, 4, 4, 6,
+ /* 20 */ 4, 4, 4, 0, 4,
+ /* 25 */ 2, 2, 2, 2, 2,
+ /* 30 */ 2, 4, 4, 0, 4,
+ /* 35 */ 2, 0, 0, 0, 0,
+};
diff --git a/utils/2l/pass.c b/utils/2l/pass.c
new file mode 100644
index 00000000..d429494e
--- /dev/null
+++ b/utils/2l/pass.c
@@ -0,0 +1,538 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i;
+ Sym *s;
+ Prog *p;
+ long t, u;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ t = p->from.offset + p->from.displace;
+ if(t > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ /* allocate small guys */
+ datsize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA)
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t == 0) {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ t = rnd(t, 4);;
+ s->value = t;
+ if(t > MINSIZ)
+ continue;
+ s->value = datsize;
+ datsize += t;
+ s->type = SDATA1;
+ }
+
+ /* allocate the rest of the data */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA) {
+ if(s->type == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ t = s->value;
+ s->value = datsize;
+ datsize += t;
+ }
+
+ if(debug['j']) {
+ /*
+ * pad data with bss that fits up to next
+ * 8k boundary, then push data to 8k
+ */
+ u = rnd(datsize, 8192);
+ u -= datsize;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t > u)
+ continue;
+ u -= t;
+ s->value = datsize;
+ s->type = SDATA;
+ datsize += t;
+ }
+ datsize += u;
+ }
+
+ /* now the bss */
+ bsssize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ s->value = bsssize + datsize;
+ bsssize += t;
+ }
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+}
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != ABRA)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+ Prog *p;
+ long o;
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+ lastp->link = P;
+ firstp = firstp->link;
+ o = 0; /* set */
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == ABCASE) { /* initialization for dodata */
+ s = p->from.sym;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("BCASE of non-data: %s in %s\n%P",
+ s->name, TNAME, p);
+ }
+
+ p->stkoff = -1; /* initialization for stkoff */
+ if(p->as == ATEXT) {
+ p->stkoff = 0;
+ o = p->to.offset;
+ continue;
+ }
+ if(p->as == AADJSP && p->from.offset == 0) {
+ p->stkoff = o;
+ continue;
+ }
+ }
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == ABRA)
+ if((q = p->pcond) != P) {
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /* copy up to 4 instructions to avoid branch */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == P)
+ break;
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == ABRA || a == ARTS || a == ARTE)
+ break;
+ if(q->pcond == P || q->pcond->mark)
+ continue;
+ if(a == ABSR || a == ABCASE || a == ADBF)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ lastp->link = q;
+ lastp = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = prg();
+ q->as = ABRA;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark = 1;
+ lastp->link = p;
+ lastp = p;
+ a = p->as;
+ if(a == ARTS || a == ABRA || a == ARTE)
+ return;
+ if(p->pcond != P)
+ if(a != ABSR) {
+ q = brchain(p->link);
+ if(q != P && q->mark)
+ if(a != ABCASE && a != ADBF) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABLE: return ABGT;
+ case ABLS: return ABHI;
+ case ABLT: return ABGE;
+ case ABMI: return ABPL;
+ case ABGE: return ABLT;
+ case ABPL: return ABMI;
+ case ABGT: return ABLE;
+ case ABHI: return ABLS;
+ case ABCS: return ABCC;
+ case ABCC: return ABCS;
+ case AFBEQ: return AFBNE;
+ case AFBF: return AFBT;
+ case AFBGE: return AFBLT;
+ case AFBGT: return AFBLE;
+ case AFBLE: return AFBGT;
+ case AFBLT: return AFBGE;
+ case AFBNE: return AFBEQ;
+ case AFBT: return AFBF;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ return a;
+}
+
+void
+patch(void)
+{
+ long c;
+ Prog *p, *q;
+ Sym *s;
+ long vexit;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if((p->as == ABSR || p->as == ARTS) && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s in %s", s->name, TNAME);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range in %s\n%P", TNAME, p);
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ long dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != ABRA)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+void
+dostkoff(void)
+{
+ Prog *p, *q;
+ long s, t;
+ int a;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f stkoff\n", cputime());
+ Bflush(&bso);
+ s = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ s = p->to.offset;
+ if(s == 0)
+ continue;
+ p = appendp(p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = s;
+ p->stkoff = 0;
+ continue;
+ }
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as == ATEXT)
+ break;
+ if(q->stkoff >= 0)
+ if(q->stkoff != s)
+ diag("stack offset %ld is %ld sb %ld in %s\n%P",
+ q->pc, q->stkoff, s, q, TNAME, p);
+ q->stkoff = s;
+ }
+ o = &optab[p->as];
+ if(p->to.type == D_TOS)
+ s -= o->dstsp;
+ if(p->from.type == D_TOS)
+ s -= o->srcsp;
+ if(p->as == AADJSP)
+ s += p->from.offset;
+ if(p->as == APEA)
+ s += 4;
+ for(q = p->link; q != P; q = q->pcond) {
+ if(q->as == ATEXT) {
+ q = P;
+ break;
+ }
+ if(q->stkoff >= 0)
+ break;
+ }
+ if(q == P || q->stkoff == s)
+ continue;
+ if(p->as == ABRA || p->as == ARTS || p->as == ARTE) {
+ s = q->stkoff;
+ continue;
+ }
+ if(p->link->as == ABCASE)
+ diag("BCASE with stack offset in %s", TNAME);
+ t = q->stkoff - s;
+ s = q->stkoff;
+ p = appendp(p);
+ p->as = AADJSP;
+ p->stkoff = s - t;
+ p->from.type = D_CONST;
+ p->from.offset = t;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ a = p->from.type & D_MASK;
+ if(a == D_AUTO)
+ p->from.offset += p->stkoff;
+ if(a == D_PARAM)
+ p->from.offset += p->stkoff + 4;
+ a = p->to.type & D_MASK;
+ if(a == D_AUTO)
+ p->to.offset += p->stkoff;
+ if(a == D_PARAM)
+ p->to.offset += p->stkoff + 4;
+ if(p->as != ARTS)
+ continue;
+ if(p->stkoff == 0)
+ continue;
+ q = p;
+ p = appendp(p);
+ p->as = ARTS;
+ p->stkoff = 0;
+
+ q->as = AADJSP;
+ q->from.type = D_CONST;
+ q->from.offset = -q->stkoff;
+ }
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
diff --git a/utils/2l/span.c b/utils/2l/span.c
new file mode 100644
index 00000000..45fc23ad
--- /dev/null
+++ b/utils/2l/span.c
@@ -0,0 +1,551 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ long v, c, idat;
+ Optab *o;
+ int m, n;
+
+ xdefine("etext", STEXT, 0L);
+ xdefine("a6base", STEXT, 0L);
+ idat = INITDAT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ n = 0;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_A0+7;
+ v = -p->from.offset;
+ p->from.offset = v;
+ if((v < -8 && v >= -32768L) || (v > 8 && v < 32768L)) {
+ p->as = ALEA;
+ p->from.type = I_INDIR | (D_A0+7);
+ continue;
+ }
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v >= 0 && v <= 8)
+ p->from.type = D_QUICK;
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+ n = 0;
+
+start:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ o = &optab[p->as];
+ p->pc = c;
+ m = mmsize[o->optype];
+ if(m == 0) {
+ if(p->as == AWORD)
+ m = 2;
+ if(p->as == ALONG)
+ m = 4;
+ p->mark = m;
+ c += m;
+ continue;
+ }
+ if(p->from.type != D_NONE)
+ m += andsize(p, &p->from);
+ if(p->to.type == D_BRANCH) {
+ if(p->pcond == P)
+ p->pcond = p;
+ c += m;
+ if(m == 2)
+ m |= 0100;
+ p->mark = m;
+ continue;
+ }
+ if(p->to.type != D_NONE)
+ m += andsize(p, &p->to);
+ p->mark = m;
+ c += m;
+ }
+
+loop:
+ n++;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span %d\n", cputime(), n);
+ Bflush(&bso);
+ if(n > 60) {
+ diag("span must be looping");
+ errorexit();
+ }
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if((m = p->mark) & 0100) {
+ q = p->pcond;
+ v = q->pc - 2;
+ if(p->back)
+ v -= c;
+ else
+ v -= p->pc;
+ p->pc = c;
+ if(v < -32768L || v >= 32768L) {
+ if(p->as == ABSR && q->pc < 32768L && q->pc >= 0)
+ c += 4;
+ else
+ c += 6;
+ } else
+ if(v < -128 || v >= 128)
+ c += 4;
+ else
+ if(v == 0) {
+ c += 4;
+ p->mark = 4;
+ } else
+ c += 2;
+ continue;
+ }
+ p->pc = c;
+ c += m;
+ }
+ if(c != textsize) {
+ textsize = c;
+ goto loop;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(INITDAT != idat) {
+ idat = INITDAT;
+ goto start;
+ }
+ xdefine("etext", STEXT, c);
+ xdefine("a6base", STEXT, INITDAT+A6OFFSET);
+ if(debug['v'])
+ Bprint(&bso, "etext = %lux\n", c);
+ Bflush(&bso);
+ for(p = textp; p != P; p = p->pcond)
+ p->from.sym->value = p->pc;
+ textsize = c - INITTEXT;
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+ if(s->type == STEXT && s->value == 0)
+ s->value = v;
+}
+
+int
+andsize(Prog *p, Adr *ap)
+{
+ int t, n;
+ long v;
+ Optab *o;
+
+ t = ap->type;
+ if(ap->index != D_NONE) {
+ n = 2;
+ v = ap->displace;
+ if(v != 0) {
+ n += 2;
+ if(v < -32768L || v >= 32768L)
+ n += 2;
+ }
+ switch(t) {
+ default:
+ v = ap->offset;
+ break;
+
+ case D_STATIC:
+ case D_EXTERN:
+ if(ap->sym->type == STEXT)
+ return n+4; /* see below */
+ v = ap->sym->value + ap->offset - A6OFFSET;
+ if(debug['6'])
+ v += INITDAT + A6OFFSET;
+ }
+ if(v != 0) {
+ n += 2;
+ if(v < -32768L || v >= 32768L)
+ n += 2;
+ }
+ return n;
+ }
+ n = simple[t];
+ if(n != 0177) {
+ v = ap->offset;
+ if(v == 0)
+ return 0;
+ if((n&070) != 020) /* D_INDIR */
+ return 0;
+ if(v == 0)
+ return 0;
+ if(v < -32768L || v >= 32768L)
+ return 6; /* switch to index1 mode */
+ return 2;
+ }
+ if((t&I_MASK) == I_ADDR)
+ t = D_CONST;
+ switch(t) {
+
+ default:
+ return 0;
+
+ case D_STACK:
+ case D_AUTO:
+ case D_PARAM:
+ v = ap->offset;
+ if(v == 0)
+ return 0;
+ if(v < -32768L || v >= 32768L)
+ return 6; /* switch to index1 mode */
+ return 2;
+
+ case I_INDIR|D_CONST:
+ v = ap->offset;
+ goto adr;
+
+ case D_STATIC:
+ case D_EXTERN:
+ if(ap->sym->type == STEXT)
+ return 4; /* too slow to get back into namelist */
+ v = ap->sym->value + ap->offset - A6OFFSET;
+ if(debug['6']) {
+ v += INITDAT + A6OFFSET;
+ goto adr;
+ }
+ if(v == 0)
+ return 0;
+
+ adr:
+ if(v < -32768L || v >= 32768L)
+ return 4;
+ return 2;
+
+ case D_CONST:
+ case D_FCONST:
+ o = &optab[p->as];
+ if(ap == &(p->from))
+ return o->srcsp;
+ return o->dstsp;
+
+ case D_CCR:
+ case D_SR:
+ if(p->as == AMOVW)
+ return 0;
+ return 2;
+
+ case D_USP:
+ t = p->from.type;
+ if(t >= D_A0 && t <= D_A0+8)
+ return 0;
+ t = p->to.type;
+ if(t >= D_A0 && t <= D_A0+8)
+ return 0;
+
+ case D_SFC:
+ case D_DFC:
+ case D_CACR:
+ case D_VBR:
+ case D_CAAR:
+ case D_MSP:
+ case D_ISP:
+ case D_FPCR:
+ case D_FPSR:
+ case D_FPIAR:
+ case D_TC:
+ case D_ITT0:
+ case D_ITT1:
+ case D_DTT0:
+ case D_DTT1:
+ case D_MMUSR:
+ case D_URP:
+ case D_SRP:
+ return 2;
+ }
+}
+
+void
+putsymb(Sym *s, int t, long v)
+{
+ int i, f;
+ char *n;
+
+ n = s->name;
+ if(t == 'f')
+ n++;
+ lput(v);
+ if(s->version)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(n[0]);
+ for(i=1; n[i] != 0 || n[i+1] != 0; i += 2) {
+ CPUT(n[i]);
+ CPUT(n[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; n[i]; i++)
+ CPUT(n[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; n[i] != 0 || n[i+1] != 0; i+=2) {
+ f = ((n[i]&0xff) << 8) | (n[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(s->version)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, n, s->version);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, n);
+ }
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s, 'T', s->value);
+ s = lookup("a6base", 0);
+ if(s->type == STEXT)
+ putsymb(s, 'D', s->value);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SDATA:
+ putsymb(s, 'D', s->value+INITDAT);
+ continue;
+
+ case SBSS:
+ putsymb(s, 'B', s->value+INITDAT);
+ continue;
+
+ case SFILE:
+ putsymb(s, 'f', s->value);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->pcond) {
+ s = p->from.sym;
+ if(s->type != STEXT)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym, 'z', a->aoffset);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym, 'Z', a->aoffset);
+
+ putsymb(s, 'T', s->value);
+
+ /* auto and param after */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym, 'a', -a->aoffset);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym, 'p', a->aoffset);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+#define MINLC 2
+void
+asmsp(void)
+{
+ long oldpc, oldsp;
+ Prog *p;
+ int s;
+ long v;
+
+ oldpc = INITTEXT;
+ oldsp = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->stkoff == oldsp || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['G'])
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ continue;
+ }
+ if(debug['G'])
+ Bprint(&bso, "\t\t%6ld", spsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['G'])
+ Bprint(&bso, " pc+%d*2(%d)", s, s+128);
+ v -= s;
+ spsize++;
+ }
+ v = p->stkoff - oldsp;
+ oldsp = p->stkoff;
+ oldpc = p->pc + MINLC;
+ if(v & 3 || v > 64L*4L || v < -64L*4L) {
+ CPUT(0); /* 0 vvvv +sp */
+ lput(v);
+ if(debug['G']) {
+ if(v > 0)
+ Bprint(&bso, " sp+%ld*1(%d,%ld)\n",
+ v, 0, v);
+ else
+ Bprint(&bso, " sp%ld*1(%d,%ld)\n",
+ v, 0, v);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ spsize += 5;
+ continue;
+ }
+ s = v/4;
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +sp */
+ if(debug['G']) {
+ Bprint(&bso, " sp+%d*4(%d)\n", s, 0+s);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -sp */
+ if(debug['G']) {
+ Bprint(&bso, " sp%d*4(%d)\n", s, 64-s);
+ Bprint(&bso, "%6lux %4ld%P\n",
+ p->pc, p->stkoff, p);
+ }
+ }
+ spsize++;
+ }
+ while(spsize & 1) {
+ s = 129;
+ CPUT(s);
+ spsize++;
+ }
+ if(debug['v'] || debug['G'])
+ Bprint(&bso, "stsize = %ld\n", spsize);
+ Bflush(&bso);
+}
+
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
diff --git a/utils/5a/a.h b/utils/5a/a.h
new file mode 100644
index 00000000..23d19347
--- /dev/null
+++ b/utils/5a/a.h
@@ -0,0 +1,182 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../5c/5.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ long offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+
+ Always = 14,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(long);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void maclin(void);
+void macprag(void);
+void macif(int);
+void macend(void);
+void outhist(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/5a/a.y b/utils/5a/a.y
new file mode 100644
index 00000000..7ef969ca
--- /dev/null
+++ b/utils/5a/a.y
@@ -0,0 +1,673 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
+%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX
+%token <lval> LCONST LSP LSB LFP LPC
+%token <lval> LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR
+%token <lval> LCOND LS LAT
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr oexpr pointer offset sreg spreg creg
+%type <lval> rcon cond reglist
+%type <gen> gen rel reg regreg freg shift fcon frcon
+%type <gen> imm ximm name oreg ireg nireg ioreg imsr
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * ADD
+ */
+ LTYPE1 cond imsr ',' spreg ',' reg
+ {
+ outcode($1, $2, &$3, $5, &$7);
+ }
+| LTYPE1 cond imsr ',' spreg ','
+ {
+ outcode($1, $2, &$3, $5, &nullgen);
+ }
+| LTYPE1 cond imsr ',' reg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * MVN
+ */
+| LTYPE2 cond imsr ',' reg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * MOVW
+ */
+| LTYPE3 cond gen ',' gen
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+/*
+ * B/BL
+ */
+| LTYPE4 cond comma rel
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+| LTYPE4 cond comma nireg
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+/*
+ * BX
+ */
+| LTYPEBX comma ireg
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * BEQ
+ */
+| LTYPE5 comma rel
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * SWI
+ */
+| LTYPE6 cond comma gen
+ {
+ outcode($1, $2, &nullgen, NREG, &$4);
+ }
+/*
+ * CMP
+ */
+| LTYPE7 cond imsr ',' spreg comma
+ {
+ outcode($1, $2, &$3, $5, &nullgen);
+ }
+/*
+ * MOVM
+ */
+| LTYPE8 cond ioreg ',' '[' reglist ']'
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $6;
+ outcode($1, $2, &$3, NREG, &g);
+ }
+| LTYPE8 cond '[' reglist ']' ',' ioreg
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $4;
+ outcode($1, $2, &g, NREG, &$7);
+ }
+/*
+ * SWAP
+ */
+| LTYPE9 cond reg ',' ireg ',' reg
+ {
+ outcode($1, $2, &$5, $3.reg, &$7);
+ }
+| LTYPE9 cond reg ',' ireg comma
+ {
+ outcode($1, $2, &$5, $3.reg, &$3);
+ }
+| LTYPE9 cond comma ireg ',' reg
+ {
+ outcode($1, $2, &$4, $6.reg, &$6);
+ }
+/*
+ * RET
+ */
+| LTYPEA cond comma
+ {
+ outcode($1, $2, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTYPEB name ',' imm
+ {
+ outcode($1, Always, &$2, NREG, &$4);
+ }
+| LTYPEB name ',' con ',' imm
+ {
+ outcode($1, Always, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LTYPEC name '/' con ',' ximm
+ {
+ outcode($1, Always, &$2, $4, &$6);
+ }
+/*
+ * CASE
+ */
+| LTYPED cond reg comma
+ {
+ outcode($1, $2, &$3, NREG, &nullgen);
+ }
+/*
+ * word
+ */
+| LTYPEH comma ximm
+ {
+ outcode($1, Always, &nullgen, NREG, &$3);
+ }
+/*
+ * floating-point coprocessor
+ */
+| LTYPEI cond freg ',' freg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+| LTYPEK cond frcon ',' freg
+ {
+ outcode($1, $2, &$3, NREG, &$5);
+ }
+| LTYPEK cond frcon ',' LFREG ',' freg
+ {
+ outcode($1, $2, &$3, $5, &$7);
+ }
+| LTYPEL cond freg ',' freg comma
+ {
+ outcode($1, $2, &$3, $5.reg, &nullgen);
+ }
+/*
+ * MCR MRC
+ */
+| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset =
+ (0xe << 24) | /* opcode */
+ ($1 << 20) | /* MCR/MRC */
+ ($2 << 28) | /* scond */
+ (($3 & 15) << 8) | /* coprocessor number */
+ (($5 & 7) << 21) | /* coprocessor operation */
+ (($7 & 15) << 12) | /* arm register */
+ (($9 & 15) << 16) | /* Crn */
+ (($11 & 15) << 0) | /* Crm */
+ (($12 & 7) << 5) | /* coprocessor information */
+ (1<<4); /* must be set */
+ outcode(AWORD, Always, &nullgen, NREG, &g);
+ }
+/*
+ * MULL hi,lo,r1,r2
+ */
+| LTYPEM cond reg ',' reg ',' regreg
+ {
+ outcode($1, $2, &$3, $5.reg, &$7);
+ }
+/*
+ * MULA hi,lo,r1,r2
+ */
+| LTYPEN cond reg ',' reg ',' reg ',' spreg
+ {
+ $7.type = D_REGREG;
+ $7.offset = $9;
+ outcode($1, $2, &$3, $5.reg, &$7);
+ }
+/*
+ * END
+ */
+| LTYPEE comma
+ {
+ outcode($1, Always, &nullgen, NREG, &nullgen);
+ }
+
+cond:
+ {
+ $$ = Always;
+ }
+| cond LCOND
+ {
+ $$ = ($1 & ~C_SCOND) | $2;
+ }
+| cond LS
+ {
+ $$ = $1 | $2;
+ }
+
+comma:
+| ',' comma
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+ximm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' oreg
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' '*' '$' oreg
+ {
+ $$ = $4;
+ $$.type = D_OCONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| fcon
+
+fcon:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+reglist:
+ spreg
+ {
+ $$ = 1 << $1;
+ }
+| spreg '-' spreg
+ {
+ int i;
+ $$=0;
+ for(i=$1; i<=$3; i++)
+ $$ |= 1<<i;
+ for(i=$3; i<=$1; i++)
+ $$ |= 1<<i;
+ }
+| spreg comma reglist
+ {
+ $$ = (1<<$1) | $3;
+ }
+
+gen:
+ reg
+| ximm
+| shift
+| shift '(' spreg ')'
+ {
+ $$ = $1;
+ $$.reg = $3;
+ }
+| LPSR
+ {
+ $$ = nullgen;
+ $$.type = D_PSR;
+ $$.reg = $1;
+ }
+| LFCR
+ {
+ $$ = nullgen;
+ $$.type = D_FPCR;
+ $$.reg = $1;
+ }
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.offset = $1;
+ }
+| oreg
+| freg
+
+nireg:
+ ireg
+| name
+ {
+ $$ = $1;
+ if($1.name != D_EXTERN && $1.name != D_STATIC) {
+ }
+ }
+
+ireg:
+ '(' spreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+
+ioreg:
+ ireg
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+oreg:
+ name
+| name '(' sreg ')'
+ {
+ $$ = $1;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ }
+| ioreg
+
+imsr:
+ reg
+| imm
+| shift
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+reg:
+ spreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+regreg:
+ '(' spreg ',' spreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_REGREG;
+ $$.reg = $2;
+ $$.offset = $4;
+ }
+
+shift:
+ spreg '<' '<' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (0 << 5);
+ }
+| spreg '>' '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (1 << 5);
+ }
+| spreg '-' '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (2 << 5);
+ }
+| spreg LAT '>' rcon
+ {
+ $$ = nullgen;
+ $$.type = D_SHIFT;
+ $$.offset = $1 | $4 | (3 << 5);
+ }
+
+rcon:
+ spreg
+ {
+ if($$ < 0 || $$ >= 16)
+ print("register value out of range\n");
+ $$ = (($1&15) << 8) | (1 << 4);
+ }
+| con
+ {
+ if($$ < 0 || $$ >= 32)
+ print("shift value out of range\n");
+ $$ = ($1&31) << 7;
+ }
+
+sreg:
+ LREG
+| LPC
+ {
+ $$ = REGPC;
+ }
+| LR '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+spreg:
+ sreg
+| LSP
+ {
+ $$ = REGSP;
+ }
+
+creg:
+ LCREG
+| LC '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+frcon:
+ freg
+| fcon
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+oexpr:
+ {
+ $$ = 0;
+ }
+| ',' expr
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/5a/lex.c b/utils/5a/lex.c
new file mode 100644
index 00000000..2802f4f8
--- /dev/null
+++ b/utils/5a/lex.c
@@ -0,0 +1,689 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = '5';
+ thestring = "arm";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ case 't':
+ thechar = 't';
+ thestring = "thumb";
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+
+ "F", LF, 0,
+
+ "F0", LFREG, 0,
+ "F1", LFREG, 1,
+ "F2", LFREG, 2,
+ "F3", LFREG, 3,
+ "F4", LFREG, 4,
+ "F5", LFREG, 5,
+ "F6", LFREG, 6,
+ "F7", LFREG, 7,
+ "F8", LFREG, 8,
+ "F9", LFREG, 9,
+ "F10", LFREG, 10,
+ "F11", LFREG, 11,
+ "F12", LFREG, 12,
+ "F13", LFREG, 13,
+ "F14", LFREG, 14,
+ "F15", LFREG, 15,
+
+ "C", LC, 0,
+
+ "C0", LCREG, 0,
+ "C1", LCREG, 1,
+ "C2", LCREG, 2,
+ "C3", LCREG, 3,
+ "C4", LCREG, 4,
+ "C5", LCREG, 5,
+ "C6", LCREG, 6,
+ "C7", LCREG, 7,
+ "C8", LCREG, 8,
+ "C9", LCREG, 9,
+ "C10", LCREG, 10,
+ "C11", LCREG, 11,
+ "C12", LCREG, 12,
+ "C13", LCREG, 13,
+ "C14", LCREG, 14,
+ "C15", LCREG, 15,
+
+ "CPSR", LPSR, 0,
+ "SPSR", LPSR, 1,
+
+ "FPSR", LFCR, 0,
+ "FPCR", LFCR, 1,
+
+ ".EQ", LCOND, 0,
+ ".NE", LCOND, 1,
+ ".CS", LCOND, 2,
+ ".HS", LCOND, 2,
+ ".CC", LCOND, 3,
+ ".LO", LCOND, 3,
+ ".MI", LCOND, 4,
+ ".PL", LCOND, 5,
+ ".VS", LCOND, 6,
+ ".VC", LCOND, 7,
+ ".HI", LCOND, 8,
+ ".LS", LCOND, 9,
+ ".GE", LCOND, 10,
+ ".LT", LCOND, 11,
+ ".GT", LCOND, 12,
+ ".LE", LCOND, 13,
+ ".AL", LCOND, Always,
+
+ ".U", LS, C_UBIT,
+ ".S", LS, C_SBIT,
+ ".W", LS, C_WBIT,
+ ".P", LS, C_PBIT,
+ ".PW", LS, C_WBIT|C_PBIT,
+ ".WP", LS, C_WBIT|C_PBIT,
+
+ ".F", LS, C_FBIT,
+
+ ".IBW", LS, C_WBIT|C_PBIT|C_UBIT,
+ ".IAW", LS, C_WBIT|C_UBIT,
+ ".DBW", LS, C_WBIT|C_PBIT,
+ ".DAW", LS, C_WBIT,
+ ".IB", LS, C_PBIT|C_UBIT,
+ ".IA", LS, C_UBIT,
+ ".DB", LS, C_PBIT,
+ ".DA", LS, 0,
+
+ "@", LAT, 0,
+
+ "AND", LTYPE1, AAND,
+ "EOR", LTYPE1, AEOR,
+ "SUB", LTYPE1, ASUB,
+ "RSB", LTYPE1, ARSB,
+ "ADD", LTYPE1, AADD,
+ "ADC", LTYPE1, AADC,
+ "SBC", LTYPE1, ASBC,
+ "RSC", LTYPE1, ARSC,
+ "ORR", LTYPE1, AORR,
+ "BIC", LTYPE1, ABIC,
+
+ "SLL", LTYPE1, ASLL,
+ "SRL", LTYPE1, ASRL,
+ "SRA", LTYPE1, ASRA,
+
+ "MUL", LTYPE1, AMUL,
+ "MULA", LTYPEN, AMULA,
+ "DIV", LTYPE1, ADIV,
+ "MOD", LTYPE1, AMOD,
+
+ "MULL", LTYPEM, AMULL,
+ "MULAL", LTYPEM, AMULAL,
+ "MULLU", LTYPEM, AMULLU,
+ "MULALU", LTYPEM, AMULALU,
+
+ "MVN", LTYPE2, AMVN, /* op2 ignored */
+
+ "MOVB", LTYPE3, AMOVB,
+ "MOVBU", LTYPE3, AMOVBU,
+ "MOVH", LTYPE3, AMOVH,
+ "MOVHU", LTYPE3, AMOVHU,
+ "MOVW", LTYPE3, AMOVW,
+
+ "MOVD", LTYPE3, AMOVD,
+ "MOVDF", LTYPE3, AMOVDF,
+ "MOVDW", LTYPE3, AMOVDW,
+ "MOVF", LTYPE3, AMOVF,
+ "MOVFD", LTYPE3, AMOVFD,
+ "MOVFW", LTYPE3, AMOVFW,
+ "MOVWD", LTYPE3, AMOVWD,
+ "MOVWF", LTYPE3, AMOVWF,
+
+/*
+ "ABSF", LTYPEI, AABSF,
+ "ABSD", LTYPEI, AABSD,
+ "NEGF", LTYPEI, ANEGF,
+ "NEGD", LTYPEI, ANEGD,
+ "SQTF", LTYPEI, ASQTF,
+ "SQTD", LTYPEI, ASQTD,
+ "RNDF", LTYPEI, ARNDF,
+ "RNDD", LTYPEI, ARNDD,
+ "URDF", LTYPEI, AURDF,
+ "URDD", LTYPEI, AURDD,
+ "NRMF", LTYPEI, ANRMF,
+ "NRMD", LTYPEI, ANRMD,
+*/
+
+ "CMPF", LTYPEL, ACMPF,
+ "CMPD", LTYPEL, ACMPD,
+ "ADDF", LTYPEK, AADDF,
+ "ADDD", LTYPEK, AADDD,
+ "SUBF", LTYPEK, ASUBF,
+ "SUBD", LTYPEK, ASUBD,
+ "MULF", LTYPEK, AMULF,
+ "MULD", LTYPEK, AMULD,
+ "DIVF", LTYPEK, ADIVF,
+ "DIVD", LTYPEK, ADIVD,
+
+ "B", LTYPE4, AB,
+ "BL", LTYPE4, ABL,
+ "BX", LTYPEBX, ABX,
+
+ "BEQ", LTYPE5, ABEQ,
+ "BNE", LTYPE5, ABNE,
+ "BCS", LTYPE5, ABCS,
+ "BHS", LTYPE5, ABHS,
+ "BCC", LTYPE5, ABCC,
+ "BLO", LTYPE5, ABLO,
+ "BMI", LTYPE5, ABMI,
+ "BPL", LTYPE5, ABPL,
+ "BVS", LTYPE5, ABVS,
+ "BVC", LTYPE5, ABVC,
+ "BHI", LTYPE5, ABHI,
+ "BLS", LTYPE5, ABLS,
+ "BGE", LTYPE5, ABGE,
+ "BLT", LTYPE5, ABLT,
+ "BGT", LTYPE5, ABGT,
+ "BLE", LTYPE5, ABLE,
+ "BCASE", LTYPE5, ABCASE,
+
+ "SWI", LTYPE6, ASWI,
+
+ "CMP", LTYPE7, ACMP,
+ "TST", LTYPE7, ATST,
+ "TEQ", LTYPE7, ATEQ,
+ "CMN", LTYPE7, ACMN,
+
+ "MOVM", LTYPE8, AMOVM,
+
+ "SWPBU", LTYPE9, ASWPBU,
+ "SWPW", LTYPE9, ASWPW,
+
+ "RET", LTYPEA, ARET,
+ "RFE", LTYPEA, ARFE,
+
+ "TEXT", LTYPEB, ATEXT,
+ "GLOBL", LTYPEB, AGLOBL,
+ "DATA", LTYPEC, ADATA,
+ "CASE", LTYPED, ACASE,
+ "END", LTYPEE, AEND,
+ "WORD", LTYPEH, AWORD,
+ "NOP", LTYPEI, ANOP,
+
+ "MCR", LTYPEJ, 0,
+ "MRC", LTYPEJ, 1,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+int
+isreg(Gen *g)
+{
+
+ USED(g);
+ return 1;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, Always, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+
+ case D_REGREG:
+ Bputc(&obuf, a->offset);
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+ }
+}
+
+static int bcode[] =
+{
+ ABEQ,
+ ABNE,
+ ABCS,
+ ABCC,
+ ABMI,
+ ABPL,
+ ABVS,
+ ABVC,
+ ABHI,
+ ABLS,
+ ABGE,
+ ABLT,
+ ABGT,
+ ABLE,
+ AB,
+ ANOP,
+};
+
+void
+outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ /* hack to make B.NE etc. work: turn it into the corresponding conditional */
+ if(a == AB){
+ a = bcode[scond&0xf];
+ scond = (scond & ~0xf) | Always;
+ }
+
+ if(pass == 1)
+ goto out;
+jackpot:
+ sf = 0;
+ s = g1->sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g1->name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, scond);
+ Bputc(&obuf, reg);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, Always);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/5a/mkfile b/utils/5a/mkfile
new file mode 100644
index 00000000..211d6387
--- /dev/null
+++ b/utils/5a/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=5a
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../5c/5.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/5c/5.out.h b/utils/5c/5.out.h
new file mode 100644
index 00000000..ae856e28
--- /dev/null
+++ b/utils/5c/5.out.h
@@ -0,0 +1,197 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 16
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+#define ALLTHUMBS (1<<2)
+
+#define REGRET 0
+#define REGARG 0
+/* compiler allocates R1 up as temps */
+/* compiler allocates register variables R3 up */
+#define REGEXT 10
+/* compiler allocates external registers R10 down */
+#define REGTMP 11
+#define REGSB 12
+#define REGSP 13
+#define REGLINK 14
+#define REGPC 15
+
+#define REGTMPT 7 /* used by the loader for thumb code */
+
+#define NFREG 8
+#define FREGRET 0
+#define FREGEXT 7
+/* compiler allocates register variables F0 up */
+/* compiler allocates external registers F7 down */
+
+enum as
+{
+ AXXX,
+
+ AAND,
+ AEOR,
+ ASUB,
+ ARSB,
+ AADD,
+ AADC,
+ ASBC,
+ ARSC,
+ ATST,
+ ATEQ,
+ ACMP,
+ ACMN,
+ AORR,
+ ABIC,
+
+ AMVN,
+
+ AB,
+ ABL,
+
+/*
+ * Do not reorder or fragment the conditional branch
+ * opcodes, or the predication code will break
+ */
+ ABEQ,
+ ABNE,
+ ABCS,
+ ABHS,
+ ABCC,
+ ABLO,
+ ABMI,
+ ABPL,
+ ABVS,
+ ABVC,
+ ABHI,
+ ABLS,
+ ABGE,
+ ABLT,
+ ABGT,
+ ABLE,
+
+ AMOVWD,
+ AMOVWF,
+ AMOVDW,
+ AMOVFW,
+ AMOVFD,
+ AMOVDF,
+ AMOVF,
+ AMOVD,
+
+ ACMPF,
+ ACMPD,
+ AADDF,
+ AADDD,
+ ASUBF,
+ ASUBD,
+ AMULF,
+ AMULD,
+ ADIVF,
+ ADIVD,
+
+ ASRL,
+ ASRA,
+ ASLL,
+ AMULU,
+ ADIVU,
+ AMUL,
+ ADIV,
+ AMOD,
+ AMODU,
+
+ AMOVB,
+ AMOVBU,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMOVM,
+ ASWPBU,
+ ASWPW,
+
+ ANOP,
+ ARFE,
+ ASWI,
+ AMULA,
+
+ ADATA,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ ANAME,
+ ARET,
+ ATEXT,
+ AWORD,
+ ADYNT,
+ AINIT,
+ ABCASE,
+ ACASE,
+
+ AEND,
+
+ AMULL,
+ AMULAL,
+ AMULLU,
+ AMULALU,
+
+ ABX,
+ ABXRET,
+ ADWORD,
+
+ ASIGNAME,
+
+ ALAST,
+};
+
+/* scond byte */
+#define C_SCOND ((1<<4)-1)
+#define C_SBIT (1<<4)
+#define C_PBIT (1<<5)
+#define C_WBIT (1<<6)
+#define C_FBIT (1<<7) /* psr flags-only */
+#define C_UBIT (1<<7) /* up bit */
+
+/* type/name */
+#define D_GOK 0
+#define D_NONE 1
+
+/* type */
+#define D_BRANCH (D_NONE+1)
+#define D_OREG (D_NONE+2)
+#define D_CONST (D_NONE+7)
+#define D_FCONST (D_NONE+8)
+#define D_SCONST (D_NONE+9)
+#define D_PSR (D_NONE+10)
+#define D_REG (D_NONE+12)
+#define D_FREG (D_NONE+13)
+#define D_FILE (D_NONE+16)
+#define D_OCONST (D_NONE+17)
+#define D_FILE1 (D_NONE+18)
+
+#define D_SHIFT (D_NONE+19)
+#define D_FPCR (D_NONE+20)
+#define D_REGREG (D_NONE+21)
+
+/* name */
+#define D_EXTERN (D_NONE+3)
+#define D_STATIC (D_NONE+4)
+#define D_AUTO (D_NONE+5)
+#define D_PARAM (D_NONE+6)
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/5c/cgen.c b/utils/5c/cgen.c
new file mode 100644
index 00000000..65db14c4
--- /dev/null
+++ b/utils/5c/cgen.c
@@ -0,0 +1,1156 @@
+#include "gc.h"
+
+void
+cgen(Node *n, Node *nn, int inrel)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, t;
+ long v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod, 0);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn, 0);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED && l->complex < FNX) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod, 0);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod, 0);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod, 0);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod, 0);
+ } else {
+ cgen(r, &nod, 0);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case ODIV:
+ case OMOD:
+ if(nn != Z)
+ if((t = vlog(r)) >= 0) {
+ /* signed div/mod by constant power of 2 */
+ cgen(l, nn, 0);
+ gopcode(OGE, nodconst(0), nn, Z);
+ p1 = p;
+ if(o == ODIV) {
+ gopcode(OADD, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ gopcode(OASHR, nodconst(t), Z, nn);
+ } else {
+ gopcode(OSUB, nn, nodconst(0), nn);
+ gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ gopcode(OSUB, nn, nodconst(0), nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ }
+ break;
+ }
+ goto muldiv;
+
+ case OSUB:
+ if(nn != Z)
+ if(l->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(r, nn, 0);
+ gopcode(o, Z, l, nn);
+ break;
+ }
+ case OADD:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn, 0);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ muldiv:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod, 0);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1, 0);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod, 0);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1, 0);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[r->type->etype])
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1, 0);
+ } else {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1, 0);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+
+ regalloc(&nod, n, nn);
+ gmove(&nod2, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3, 0);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3, 0);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(o, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod, 0);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn, 0);
+
+ return;
+ }
+ if(REGARG >= 0)
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG >= 0)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r) && (v = r->vconst+nod.xoffset) > -4096 && v < 4096) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod, 0);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod, 0);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z, 0);
+ cgen(r, nn, 0);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type)) {
+ if(nocast(n->type, nn->type)) {
+ cgen(l, nn, 0);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod, 0);
+ regalloc(&nod1, n, &nod);
+ if(inrel)
+ gmover(&nod, &nod1);
+ else
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn, 0);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn, 0);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn, 0);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+ return;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r) && (v = r->vconst+t->xoffset) > -4096 && v < 4096) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ } else if(n->op == OINDREG) {
+ if((v = n->xoffset) > -4096 && v < 4096) {
+ n->op = OREGISTER;
+ cgen(n, t, 0);
+ t->xoffset += v;
+ n->op = OINDREG;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+reglpcgen(Node *n, Node *nn, int f)
+{
+ Type *t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(f)
+ reglcgen(n, nn, Z);
+ else {
+ regialloc(n, nn, Z);
+ lcgen(nn, n);
+ regind(n, nn);
+ }
+ nn->type = t;
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left, 0);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn, 0);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ regalloc(&nod, n, nn);
+ cgen(n, &nod, 0);
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ gopcode(o, nodfconst(0), &nod, Z);
+ } else
+ gopcode(o, nodconst(0), &nod, Z);
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z, 0);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod, 1);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(sconst(l)) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod, 1);
+ o = invrel[relindex(o)];
+ gopcode(o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(sconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod, 1);
+ gopcode(o, r, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1, 1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod, 1);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod, 1);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1, 1);
+ }
+ gopcode(o, &nod, &nod1, Z);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && nn->complex >= FNX) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn, 0);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z, 0);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z, 0);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z, 0);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 2) {
+ if(n->complex > nn->complex) {
+ reglpcgen(&nod1, n, 1);
+ reglpcgen(&nod2, nn, 1);
+ } else {
+ reglpcgen(&nod2, nn, 1);
+ reglpcgen(&nod1, n, 1);
+ }
+ regalloc(&nod3, &regnode, Z);
+ regalloc(&nod4, &regnode, Z);
+ nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg));
+ if(w == 2 && nod1.xoffset == 0)
+ gmovm(&nod1, &nod0, 0);
+ else {
+ gmove(&nod1, &nod3);
+ if(w == 2) {
+ nod1.xoffset += SZ_LONG;
+ gmove(&nod1, &nod4);
+ }
+ }
+ if(w == 2 && nod2.xoffset == 0)
+ gmovm(&nod0, &nod2, 0);
+ else {
+ gmove(&nod3, &nod2);
+ if(w == 2) {
+ nod2.xoffset += SZ_LONG;
+ gmove(&nod4, &nod2);
+ }
+ }
+ regfree(&nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ regfree(&nod4);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ reglpcgen(&nod1, n, 0);
+ reglpcgen(&nod2, nn, 0);
+ } else {
+ reglpcgen(&nod2, nn, 0);
+ reglpcgen(&nod1, n, 0);
+ }
+
+ m = 0;
+ for(c = 0; c < w && c < 4; c++) {
+ i = tmpreg();
+ if (i == 0)
+ break;
+ reg[i]++;
+ m |= 1<<i;
+ }
+ nod4 = *(nodconst(m));
+ if(w < 3*c) {
+ for (; w>c; w-=c) {
+ gmovm(&nod1, &nod4, 1);
+ gmovm(&nod4, &nod2, 1);
+ }
+ goto out;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ gopcode(OAS, nodconst(w/c), Z, &nod3);
+ w %= c;
+
+ pc1 = pc;
+ gmovm(&nod1, &nod4, 1);
+ gmovm(&nod4, &nod2, 1);
+
+ gopcode(OSUB, nodconst(1), Z, &nod3);
+ gopcode(OEQ, nodconst(0), &nod3, Z);
+ p->as = ABGT;
+ patch(p, pc1);
+ regfree(&nod3);
+
+out:
+ if (w) {
+ i = 0;
+ while (c>w) {
+ while ((m&(1<<i)) == 0)
+ i++;
+ m &= ~(1<<i);
+ reg[i] = 0;
+ c--;
+ i++;
+ }
+ nod4.vconst = m;
+ gmovm(&nod1, &nod4, 0);
+ gmovm(&nod4, &nod2, 0);
+ }
+ i = 0;
+ do {
+ while ((m&(1<<i)) == 0)
+ i++;
+ reg[i] = 0;
+ c--;
+ i++;
+ } while (c>0);
+ regfree(&nod1);
+ regfree(&nod2);
+}
diff --git a/utils/5c/enam.c b/utils/5c/enam.c
new file mode 100644
index 00000000..989b2760
--- /dev/null
+++ b/utils/5c/enam.c
@@ -0,0 +1,98 @@
+char* anames[] =
+{
+ "XXX",
+ "AND",
+ "EOR",
+ "SUB",
+ "RSB",
+ "ADD",
+ "ADC",
+ "SBC",
+ "RSC",
+ "TST",
+ "TEQ",
+ "CMP",
+ "CMN",
+ "ORR",
+ "BIC",
+ "MVN",
+ "B",
+ "BL",
+ "BEQ",
+ "BNE",
+ "BCS",
+ "BHS",
+ "BCC",
+ "BLO",
+ "BMI",
+ "BPL",
+ "BVS",
+ "BVC",
+ "BHI",
+ "BLS",
+ "BGE",
+ "BLT",
+ "BGT",
+ "BLE",
+ "MOVWD",
+ "MOVWF",
+ "MOVDW",
+ "MOVFW",
+ "MOVFD",
+ "MOVDF",
+ "MOVF",
+ "MOVD",
+ "CMPF",
+ "CMPD",
+ "ADDF",
+ "ADDD",
+ "SUBF",
+ "SUBD",
+ "MULF",
+ "MULD",
+ "DIVF",
+ "DIVD",
+ "SRL",
+ "SRA",
+ "SLL",
+ "MULU",
+ "DIVU",
+ "MUL",
+ "DIV",
+ "MOD",
+ "MODU",
+ "MOVB",
+ "MOVBU",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MOVM",
+ "SWPBU",
+ "SWPW",
+ "NOP",
+ "RFE",
+ "SWI",
+ "MULA",
+ "DATA",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "NAME",
+ "RET",
+ "TEXT",
+ "WORD",
+ "DYNT",
+ "INIT",
+ "BCASE",
+ "CASE",
+ "END",
+ "MULL",
+ "MULAL",
+ "MULLU",
+ "MULALU",
+ "BX",
+ "BXRET",
+ "DWORD",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/5c/gc.h b/utils/5c/gc.h
new file mode 100644
index 00000000..1231ac31
--- /dev/null
+++ b/utils/5c/gc.h
@@ -0,0 +1,349 @@
+#include "../cc/cc.h"
+#include "../5c/5.out.h"
+
+/*
+ * 5c/arm
+ * Arm 7500
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+
+#define R0ISZERO 0
+
+struct Adr
+{
+ long offset;
+ double dval;
+ char sval[NSNAME];
+ Ieee ieee;
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ char as;
+ char reg;
+ uchar scond;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN Multab multab[20];
+EXTERN int retok;
+EXTERN int hintabsize;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN char reg[NREG+NFREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+EXTERN int suppress;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 4
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+int bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*, int);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+int tmpreg(void);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmovm(Node*, Node*, int);
+void gmove(Node*, Node*);
+void gmover(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+int sval(long);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+int Rconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int shiftprop(Reg*);
+void constprop(Adr*, Adr*, Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+void predicate(void);
+int isbranch(Prog *);
+int predicable(Prog *p);
+int modifiescpsr(Prog *p);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "R" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/utils/5c/list.c b/utils/5c/list.c
new file mode 100644
index 00000000..d50f07db
--- /dev/null
+++ b/utils/5c/list.c
@@ -0,0 +1,304 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+char *extra [] = {
+ ".EQ", ".NE", ".CS", ".CC",
+ ".MI", ".PL", ".VS", ".VC",
+ ".HI", ".LS", ".GE", ".LT",
+ ".GT", ".LE", "", ".NV",
+};
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], sc[20];
+ Prog *p;
+ int a, s;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ s = p->scond;
+ strcpy(sc, extra[s & C_SCOND]);
+ if(s & C_SBIT)
+ strcat(sc, ".S");
+ if(s & C_PBIT)
+ strcat(sc, ".P");
+ if(s & C_WBIT)
+ strcat(sc, ".W");
+ if(s & C_UBIT) /* ambiguous with FBIT */
+ strcat(sc, ".U");
+ if(a == AMOVM) {
+ if(p->from.type == D_CONST)
+ sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to);
+ else
+ if(p->to.type == D_CONST)
+ sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to);
+ else
+ sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
+ } else
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ char *op;
+ int v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_SHIFT:
+ v = a->offset;
+ op = "<<>>->@>" + (((v>>5) & 3) << 1);
+ if(v & (1<<4))
+ sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+ else
+ sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+ if(a->reg != NREG)
+ sprint(str+strlen(str), "(R%d)", a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ sprint(str, "PSR");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(PSR)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ int i, v;
+
+ a = va_arg(fp->args, Adr*);
+ sprint(str, "GOK-reglist");
+ switch(a->type) {
+ case D_CONST:
+ if(a->reg != NREG)
+ break;
+ if(a->sym != S)
+ break;
+ v = a->offset;
+ strcpy(str, "");
+ for(i=0; i<NREG; i++) {
+ if(v & (1<<i)) {
+ if(str[0] == 0)
+ strcat(str, "[R");
+ else
+ strcat(str, ",R");
+ sprint(strchr(str, 0), "%d", i);
+ }
+ }
+ strcat(str, "]");
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/5c/mkenam b/utils/5c/mkenam
new file mode 100644
index 00000000..e1cbf710
--- /dev/null
+++ b/utils/5c/mkenam
@@ -0,0 +1,15 @@
+ed - ../5c/5.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/5c/mkfile b/utils/5c/mkfile
new file mode 100644
index 00000000..a0f53c45
--- /dev/null
+++ b/utils/5c/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=5c
+
+OFILES=\
+ cgen.$O\
+ enam.$O\
+ list.$O\
+ mul.$O\
+ peep.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+
+HFILES=\
+ gc.h\
+ 5.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/5c/mul.c b/utils/5c/mul.c
new file mode 100644
index 00000000..67370a62
--- /dev/null
+++ b/utils/5c/mul.c
@@ -0,0 +1,609 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int maxmulops = 3; /* max # of ops to replace mul with */
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=maxmulops; g++) {
+ if(g >= maxmulops && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/utils/5c/peep.c b/utils/5c/peep.c
new file mode 100644
index 00000000..4eded1dc
--- /dev/null
+++ b/utils/5c/peep.c
@@ -0,0 +1,1440 @@
+#include "gc.h"
+
+int xtramodes(Reg*, Adr*);
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
+ /*
+ * elide shift into D_SHIFT operand of subsequent instruction
+ */
+ if(shiftprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
+ if(regtyp(&p->to)) {
+ if(p->from.type == D_CONST)
+ constprop(&p->from, &p->to, r->s1);
+ else if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AEOR:
+ /*
+ * EOR -1,x,y => MVN x,y
+ */
+ if(p->from.type == D_CONST && p->from.offset == -1) {
+ p->as = AMVN;
+ p->from.type = D_REG;
+ if(p->reg != NREG)
+ p->from.reg = p->reg;
+ else
+ p->from.reg = p->to.reg;
+ p->reg = NREG;
+ }
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVW:
+ case AMOVB:
+ case AMOVBU:
+ if(p->from.type == D_OREG && p->from.offset == 0)
+ xtramodes(r, &p->from);
+ else if(p->to.type == D_OREG && p->to.offset == 0)
+ xtramodes(r, &p->to);
+ else
+ continue;
+ break;
+ case ACMP:
+ /*
+ * elide CMP $0,x if calculation of x can set condition codes
+ */
+ if(p->from.type != D_CONST || p->from.offset != 0)
+ continue;
+ r2 = r->s1;
+ if(r2 == R)
+ continue;
+ t = r2->prog->as;
+ switch(t) {
+ default:
+ continue;
+ case ABEQ:
+ case ABNE:
+ case ABMI:
+ case ABPL:
+ break;
+ case ABGE:
+ t = ABPL;
+ break;
+ case ABLT:
+ t = ABMI;
+ break;
+ case ABHI:
+ t = ABNE;
+ break;
+ case ABLS:
+ t = ABEQ;
+ break;
+ }
+ r1 = r;
+ do
+ r1 = uniqp(r1);
+ while (r1 != R && r1->prog->as == ANOP);
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->to.type != D_REG)
+ continue;
+ if(p1->to.reg != p->reg)
+ if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
+ continue;
+ switch(p1->as) {
+ default:
+ continue;
+ case AMOVW:
+ if(p1->from.type != D_REG)
+ continue;
+ case AAND:
+ case AEOR:
+ case AORR:
+ case ABIC:
+ case AMVN:
+ case ASUB:
+ case ARSB:
+ case AADD:
+ case AADC:
+ case ASBC:
+ case ARSC:
+ break;
+ }
+ p1->scond |= C_SBIT;
+ r2->prog->as = t;
+ excise(r);
+ continue;
+ }
+ }
+
+ predicate();
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->scond = zprog.scond;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG)
+ return 1;
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ABL:
+ return 0;
+
+ case ACMP:
+ case ACMN:
+ case AADD:
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDD:
+ case AADDF:
+ case ASUBD:
+ case ASUBF:
+ case AMULD:
+ case AMULF:
+ case ADIVD:
+ case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+
+ case AMOVM:
+ t = 1<<v2->reg;
+ if((p->from.type == D_CONST && (p->from.offset&t)) ||
+ (p->to.type == D_CONST && (p->to.offset&t)))
+ return 0;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant constants.
+ * $c1->v1
+ * ($c1->v2 s/$c1/v1)*
+ * set v1 return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+void
+constprop(Adr *c1, Adr *v1, Reg *r)
+{
+ Prog *p;
+
+ if(debug['C'])
+ print("constprop %D->%D\n", c1, v1);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['C'])
+ print("%P", p);
+ if(uniqp(r) == R) {
+ if(debug['C'])
+ print("; merge; return\n");
+ return;
+ }
+ if(p->as == AMOVW && copyas(&p->from, c1)) {
+ if(debug['C'])
+ print("; sub%D/%D", &p->from, v1);
+ p->from = *v1;
+ } else if(copyu(p, v1, A) > 1) {
+ if(debug['C'])
+ print("; %Dset; return\n", v1);
+ return;
+ }
+ if(debug['C'])
+ print("\n");
+ if(r->s2)
+ constprop(c1, v1, r->s2);
+ }
+}
+
+/*
+ * ASLL x,y,w
+ * .. (not use w, not set x y w)
+ * AXXX w,a,b (a != w)
+ * .. (not use w)
+ * (set w)
+ * ----------- changed to
+ * ..
+ * AXXX (x<<y),a,b
+ * ..
+ */
+#define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; }
+int
+shiftprop(Reg *r)
+{
+ Reg *r1;
+ Prog *p, *p1, *p2;
+ int n, o;
+ Adr a;
+
+ p = r->prog;
+ if(p->to.type != D_REG)
+ FAIL("BOTCH: result not reg");
+ n = p->to.reg;
+ a = zprog.from;
+ if(p->reg != NREG && p->reg != p->to.reg) {
+ a.type = D_REG;
+ a.reg = p->reg;
+ }
+ if(debug['H'])
+ print("shiftprop\n%P", p);
+ r1 = r;
+ for(;;) {
+ /* find first use of shift result; abort if shift operands or result are changed */
+ r1 = uniqs(r1);
+ if(r1 == R)
+ FAIL("branch");
+ if(uniqp(r1) == R)
+ FAIL("merge");
+ p1 = r1->prog;
+ if(debug['H'])
+ print("\n%P", p1);
+ switch(copyu(p1, &p->to, A)) {
+ case 0: /* not used or set */
+ if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
+ (a.type == D_REG && copyu(p1, &a, A) > 1))
+ FAIL("args modified");
+ continue;
+ case 3: /* set, not used */
+ FAIL("BOTCH: noref");
+ }
+ break;
+ }
+ /* check whether substitution can be done */
+ switch(p1->as) {
+ default:
+ FAIL("non-dpi");
+ case AAND:
+ case AEOR:
+ case AADD:
+ case AADC:
+ case AORR:
+ case ASUB:
+ case ARSB:
+ case ASBC:
+ case ARSC:
+ if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
+ if(p1->from.type != D_REG)
+ FAIL("can't swap");
+ p1->reg = p1->from.reg;
+ p1->from.reg = n;
+ switch(p1->as) {
+ case ASUB:
+ p1->as = ARSB;
+ break;
+ case ARSB:
+ p1->as = ASUB;
+ break;
+ case ASBC:
+ p1->as = ARSC;
+ break;
+ case ARSC:
+ p1->as = ASBC;
+ break;
+ }
+ if(debug['H'])
+ print("\t=>%P", p1);
+ }
+ case ABIC:
+ case ACMP:
+ case ACMN:
+ if(p1->reg == n)
+ FAIL("can't swap");
+ if(p1->reg == NREG && p1->to.reg == n)
+ FAIL("shift result used twice");
+ case AMVN:
+ if(p1->from.type == D_SHIFT)
+ FAIL("shift result used in shift");
+ if(p1->from.type != D_REG || p1->from.reg != n)
+ FAIL("BOTCH: where is it used?");
+ break;
+ }
+ /* check whether shift result is used subsequently */
+ p2 = p1;
+ if(p1->to.reg != n)
+ for (;;) {
+ r1 = uniqs(r1);
+ if(r1 == R)
+ FAIL("inconclusive");
+ p1 = r1->prog;
+ if(debug['H'])
+ print("\n%P", p1);
+ switch(copyu(p1, &p->to, A)) {
+ case 0: /* not used or set */
+ continue;
+ case 3: /* set, not used */
+ break;
+ default:/* used */
+ FAIL("reused");
+ }
+ break;
+ }
+ /* make the substitution */
+ p2->from.type = D_SHIFT;
+ p2->from.reg = NREG;
+ o = p->reg;
+ if(o == NREG)
+ o = p->to.reg;
+ switch(p->from.type){
+ case D_CONST:
+ o |= (p->from.offset&0x1f)<<7;
+ break;
+ case D_REG:
+ o |= (1<<4) | (p->from.reg<<8);
+ break;
+ }
+ switch(p->as){
+ case ASLL:
+ o |= 0<<5;
+ break;
+ case ASRL:
+ o |= 1<<5;
+ break;
+ case ASRA:
+ o |= 2<<5;
+ break;
+ }
+ p2->from.offset = o;
+ if(debug['H'])
+ print("\t=>%P\tSUCCEED\n", p2);
+ return 1;
+}
+
+Reg*
+findpre(Reg *r, Adr *v)
+{
+ Reg *r1;
+
+ for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
+ if(uniqs(r1) != r)
+ return R;
+ switch(copyu(r1->prog, v, A)) {
+ case 1: /* used */
+ case 2: /* read-alter-rewrite */
+ return R;
+ case 3: /* set */
+ case 4: /* set and used */
+ return r1;
+ }
+ }
+ return R;
+}
+
+Reg*
+findinc(Reg *r, Reg *r2, Adr *v)
+{
+ Reg *r1;
+ Prog *p;
+
+
+ for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
+ if(uniqp(r1) != r)
+ return R;
+ switch(copyu(r1->prog, v, A)) {
+ case 0: /* not touched */
+ continue;
+ case 4: /* set and used */
+ p = r1->prog;
+ if(p->as == AADD)
+ if(p->from.type == D_CONST)
+ if(p->from.offset > -4096 && p->from.offset < 4096)
+ return r1;
+ default:
+ return R;
+ }
+ }
+ return R;
+}
+
+int
+nochange(Reg *r, Reg *r2, Prog *p)
+{
+ Adr a[3];
+ int i, n;
+
+ if(r == r2)
+ return 1;
+ n = 0;
+ if(p->reg != NREG && p->reg != p->to.reg) {
+ a[n].type = D_REG;
+ a[n++].reg = p->reg;
+ }
+ switch(p->from.type) {
+ case D_SHIFT:
+ a[n].type = D_REG;
+ a[n++].reg = p->from.offset&0xf;
+ case D_REG:
+ a[n].type = D_REG;
+ a[n++].reg = p->from.reg;
+ }
+ if(n == 0)
+ return 1;
+ for(; r!=R && r!=r2; r=uniqs(r)) {
+ p = r->prog;
+ for(i=0; i<n; i++)
+ if(copyu(p, &a[i], A) > 1)
+ return 0;
+ }
+ return 1;
+}
+
+int
+findu1(Reg *r, Adr *v)
+{
+ for(; r != R; r = r->s1) {
+ if(r->active)
+ return 0;
+ r->active = 1;
+ switch(copyu(r->prog, v, A)) {
+ case 1: /* used */
+ case 2: /* read-alter-rewrite */
+ case 4: /* set and used */
+ return 1;
+ case 3: /* set */
+ return 0;
+ }
+ if(r->s2)
+ if (findu1(r->s2, v))
+ return 1;
+ }
+ return 0;
+}
+
+int
+finduse(Reg *r, Adr *v)
+{
+ Reg *r1;
+
+ for(r1=firstr; r1!=R; r1=r1->link)
+ r1->active = 0;
+ return findu1(r, v);
+}
+
+int
+xtramodes(Reg *r, Adr *a)
+{
+ Reg *r1, *r2, *r3;
+ Prog *p, *p1;
+ Adr v;
+
+ p = r->prog;
+ if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */
+ return 0;
+ v = *a;
+ v.type = D_REG;
+ r1 = findpre(r, &v);
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p1->to.type == D_REG && p1->to.reg == v.reg)
+ switch(p1->as) {
+ case AADD:
+ if(p1->from.type == D_REG ||
+ (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
+ (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
+ (p1->from.type == D_CONST &&
+ p1->from.offset > -4096 && p1->from.offset < 4096))
+ if(nochange(uniqs(r1), r, p1)) {
+ if(a != &p->from || v.reg != p->to.reg)
+ if (finduse(r->s1, &v)) {
+ if(p1->reg == NREG || p1->reg == v.reg)
+ /* pre-indexing */
+ p->scond |= C_WBIT;
+ else return 0;
+ }
+ switch (p1->from.type) {
+ case D_REG:
+ /* register offset */
+ a->type = D_SHIFT;
+ a->offset = p1->from.reg;
+ break;
+ case D_SHIFT:
+ /* scaled register offset */
+ a->type = D_SHIFT;
+ case D_CONST:
+ /* immediate offset */
+ a->offset = p1->from.offset;
+ break;
+ }
+ if(p1->reg != NREG)
+ a->reg = p1->reg;
+ excise(r1);
+ return 1;
+ }
+ break;
+ case AMOVW:
+ if(p1->from.type == D_REG)
+ if((r2 = findinc(r1, r, &p1->from)) != R) {
+ for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
+ ;
+ if(r3 == r) {
+ /* post-indexing */
+ p1 = r2->prog;
+ a->reg = p1->to.reg;
+ a->offset = p1->from.offset;
+ p->scond |= C_PBIT;
+ if(!finduse(r, &r1->prog->to))
+ excise(r1);
+ excise(r2);
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+ if(a != &p->from || a->reg != p->to.reg)
+ if((r1 = findinc(r, R, &v)) != R) {
+ /* post-indexing */
+ p1 = r1->prog;
+ a->offset = p1->from.offset;
+ p->scond |= C_PBIT;
+ excise(r1);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+ case AMOVM:
+ if(v->type != D_REG)
+ return 0;
+ if(p->from.type == D_CONST) { /* read reglist, read/rar */
+ if(s != A) {
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v)) {
+ if(p->scond&C_WBIT)
+ return 2;
+ return 1;
+ }
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ } else { /* read/rar, write reglist */
+ if(s != A) {
+ if(p->to.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->from, v)) {
+ if(p->scond&C_WBIT)
+ return 2;
+ if(p->to.offset&(1<<v->reg))
+ return 4;
+ return 1;
+ }
+ if(p->to.offset&(1<<v->reg))
+ return 3;
+ }
+ return 0;
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFD:
+ case AMOVDF:
+ if(p->scond&(C_WBIT|C_PBIT))
+ if(v->type == D_REG) {
+ if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
+ if(p->from.reg == v->reg)
+ return 2;
+ } else {
+ if(p->to.reg == v->reg)
+ return 2;
+ }
+ }
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+
+ case AADD: /* read, read, write */
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+
+ case ACMPF:
+ case ACMPD:
+ case ACMP:
+ case ACMN:
+ case ACASE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AB: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case ABL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+
+ case ACMP:
+ case ACMN:
+
+ case AADD:
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ return D_REG;
+
+ case ACMPF:
+ case ACMPD:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ } else if(v->type == D_CONST) { /* for constprop */
+ if(a->type == v->type)
+ if(a->name == v->name)
+ if(a->sym == v->sym)
+ if(a->reg == v->reg)
+ if(a->offset == v->offset)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG) {
+ if(a->type == D_OREG) {
+ if(v->reg == a->reg)
+ return 1;
+ } else if(a->type == D_SHIFT) {
+ if((a->offset&0xf) == v->reg)
+ return 1;
+ if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a2type(p) == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v)) {
+ if(a->type == D_SHIFT) {
+ if((a->offset&0xf) == v->reg)
+ a->offset = (a->offset&~0xf)|s->reg;
+ if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+ a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
+ } else
+ a->reg = s->reg;
+ }
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
+
+struct {
+ int opcode;
+ int notopcode;
+ int scond;
+ int notscond;
+} predinfo[] = {
+ { ABEQ, ABNE, 0x0, 0x1, },
+ { ABNE, ABEQ, 0x1, 0x0, },
+ { ABCS, ABCC, 0x2, 0x3, },
+ { ABHS, ABLO, 0x2, 0x3, },
+ { ABCC, ABCS, 0x3, 0x2, },
+ { ABLO, ABHS, 0x3, 0x2, },
+ { ABMI, ABPL, 0x4, 0x5, },
+ { ABPL, ABMI, 0x5, 0x4, },
+ { ABVS, ABVC, 0x6, 0x7, },
+ { ABVC, ABVS, 0x7, 0x6, },
+ { ABHI, ABLS, 0x8, 0x9, },
+ { ABLS, ABHI, 0x9, 0x8, },
+ { ABGE, ABLT, 0xA, 0xB, },
+ { ABLT, ABGE, 0xB, 0xA, },
+ { ABGT, ABLE, 0xC, 0xD, },
+ { ABLE, ABGT, 0xD, 0xC, },
+};
+
+typedef struct {
+ Reg *start;
+ Reg *last;
+ Reg *end;
+ int len;
+} Joininfo;
+
+enum {
+ Join,
+ Split,
+ End,
+ Branch,
+ Setcond,
+ Toolong
+};
+
+enum {
+ Falsecond,
+ Truecond,
+ Delbranch,
+ Keepbranch
+};
+
+int
+isbranch(Prog *p)
+{
+ return (ABEQ <= p->as) && (p->as <= ABLE);
+}
+
+int
+predicable(Prog *p)
+{
+ if (isbranch(p)
+ || p->as == ANOP
+ || p->as == AXXX
+ || p->as == ADATA
+ || p->as == AGLOBL
+ || p->as == AGOK
+ || p->as == AHISTORY
+ || p->as == ANAME
+ || p->as == ASIGNAME
+ || p->as == ATEXT
+ || p->as == AWORD
+ || p->as == ADYNT
+ || p->as == AINIT
+ || p->as == ABCASE
+ || p->as == ACASE)
+ return 0;
+ return 1;
+}
+
+/*
+ * Depends on an analysis of the encodings performed by 5l.
+ * These seem to be all of the opcodes that lead to the "S" bit
+ * being set in the instruction encodings.
+ *
+ * C_SBIT may also have been set explicitly in p->scond.
+ */
+int
+modifiescpsr(Prog *p)
+{
+ return (p->scond&C_SBIT)
+ || p->as == ATST
+ || p->as == ATEQ
+ || p->as == ACMN
+ || p->as == ACMP
+ || p->as == AMULU
+ || p->as == ADIVU
+ || p->as == AMUL
+ || p->as == ADIV
+ || p->as == AMOD
+ || p->as == AMODU
+ || p->as == ABL;
+}
+
+/*
+ * Find the maximal chain of instructions starting with r which could
+ * be executed conditionally
+ */
+int
+joinsplit(Reg *r, Joininfo *j)
+{
+ j->start = r;
+ j->last = r;
+ j->len = 0;
+ do {
+ if (r->p2 && (r->p1 || r->p2->p2link)) {
+ j->end = r;
+ return Join;
+ }
+ if (r->s1 && r->s2) {
+ j->end = r;
+ return Split;
+ }
+ j->last = r;
+ if (r->prog->as != ANOP)
+ j->len++;
+ if (!r->s1 && !r->s2) {
+ j->end = r->link;
+ return End;
+ }
+ if (r->s2) {
+ j->end = r->s2;
+ return Branch;
+ }
+ if (modifiescpsr(r->prog)) {
+ j->end = r->s1;
+ return Setcond;
+ }
+ r = r->s1;
+ } while (j->len < 4);
+ j->end = r;
+ return Toolong;
+}
+
+Reg *
+successor(Reg *r)
+{
+ if (r->s1)
+ return r->s1;
+ else
+ return r->s2;
+}
+
+void
+applypred(Reg *rstart, Joininfo *j, int cond, int branch)
+{
+ int pred;
+ Reg *r;
+
+ if(j->len == 0)
+ return;
+ if (cond == Truecond)
+ pred = predinfo[rstart->prog->as - ABEQ].scond;
+ else
+ pred = predinfo[rstart->prog->as - ABEQ].notscond;
+
+ for (r = j->start; ; r = successor(r)) {
+ if (r->prog->as == AB) {
+ if (r != j->last || branch == Delbranch)
+ excise(r);
+ else {
+ if (cond == Truecond)
+ r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
+ else
+ r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
+ }
+ }
+ else if (predicable(r->prog))
+ r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
+ if (r->s1 != r->link) {
+ r->s1 = r->link;
+ r->link->p1 = r;
+ }
+ if (r == j->last)
+ break;
+ }
+}
+
+void
+predicate(void)
+{
+ Reg *r;
+ int t1, t2;
+ Joininfo j1, j2;
+
+ for(r=firstr; r!=R; r=r->link) {
+ if (isbranch(r->prog)) {
+ t1 = joinsplit(r->s1, &j1);
+ t2 = joinsplit(r->s2, &j2);
+ if(j1.last->link != j2.start)
+ continue;
+ if(j1.end == j2.end)
+ if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
+ (t2 == Join && (t1 == Join || t1 == Setcond))) {
+ applypred(r, &j1, Falsecond, Delbranch);
+ applypred(r, &j2, Truecond, Delbranch);
+ excise(r);
+ continue;
+ }
+ if(t1 == End || t1 == Branch) {
+ applypred(r, &j1, Falsecond, Keepbranch);
+ excise(r);
+ continue;
+ }
+ }
+ }
+}
diff --git a/utils/5c/reg.c b/utils/5c/reg.c
new file mode 100644
index 00000000..19c8a7b6
--- /dev/null
+++ b/utils/5c/reg.c
@@ -0,0 +1,1157 @@
+#include "gc.h"
+
+void addsplits(void);
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AB:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ if(p->as == AMOVM) {
+ if(p->from.type == D_CONST)
+ z = p->from.offset;
+ else
+ z = p->to.offset;
+ for(i=0; z; i++) {
+ if(z&1)
+ regbits |= RtoB(i);
+ z >>= 1;
+ }
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] && debug['v']) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%B", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%B", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%B", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%B", r->calbehind);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == ABL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TVLONG:
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R0
+ * 1 R1
+ * ... ...
+ * 10 R10
+ */
+long
+RtoB(int r)
+{
+
+ if(r < 2 || r >= REGTMP)
+ return 0;
+ return 1L << r;
+}
+
+int
+BtoR(long b)
+{
+ b &= 0x07fcL;
+ if(b == 0)
+ return 0;
+ return bitno(b);
+}
+
+/*
+ * bit reg
+ * 18 F2
+ * 19 F3
+ * ... ...
+ * 23 F7
+ */
+long
+FtoB(int f)
+{
+
+ if(f < 2 || f > NFREG-1)
+ return 0;
+ return 1L << (f + 16);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0xfc0000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16;
+}
diff --git a/utils/5c/sgen.c b/utils/5c/sgen.c
new file mode 100644
index 00000000..b20865d9
--- /dev/null
+++ b/utils/5c/sgen.c
@@ -0,0 +1,613 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG >= 0) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ }
+ }
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int o, f;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z, 0);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod, 0);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod, 0);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ supgen(n->right->left);
+ gen(n->right->right);
+ }
+ else {
+ gen(n->right->left);
+ supgen(n->right->right);
+ }
+ }
+ else {
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ t = vlog(l);
+ if(t >= 0) {
+ n->op = OASHL;
+ n->left = r;
+ n->right = l;
+ r = l;
+ l = n->left;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ case OEQ:
+ case ONE:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+ return 0;
+}
diff --git a/utils/5c/swt.c b/utils/5c/swt.c
new file mode 100644
index 00000000..4c2b33ec
--- /dev/null
+++ b/utils/5c/swt.c
@@ -0,0 +1,757 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+ Node tn;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8lux\n", i, iq[i].val);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ regalloc(&tn, &regnode, Z);
+ swit1(iq, nc, def, n, &tn);
+ regfree(&tn);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n, Node *tn)
+{
+ C1 *r;
+ int i;
+ long v;
+ Prog *sp;
+
+ if(nc >= 3) {
+ i = (q+nc-1)->val - (q+0)->val;
+ if(i > 0 && i < nc*2)
+ goto direct;
+ }
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8lux\n", q->val);
+ gopcode(OEQ, nodconst(q->val), n, Z);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8lux\n", r->val);
+ gopcode(OGT, nodconst(r->val), n, Z);
+ sp = p;
+ gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */
+ patch(p, r->label);
+ swit1(q, i, def, n, tn);
+
+ if(debug['W'])
+ print("case < %.8lux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n, tn);
+ return;
+
+direct:
+ v = q->val;
+ if(v != 0)
+ gopcode(OSUB, nodconst(v), Z, n);
+ gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z);
+ patch(p, def);
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8lux\n", q->val);
+ while(q->val != v) {
+ nextpc();
+ p->as = ABCASE;
+ patch(p, def);
+ v++;
+ }
+ nextpc();
+ p->as = ABCASE;
+ patch(p, q->label);
+ q++;
+ v++;
+ }
+ gbranch(OGOTO); /* so that regopt() won't be confused */
+ patch(p, def);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1, 0);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v, vs;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ if(debug['M'] && debug['v'])
+ print("%L multiply: %ld\n", n->lineno, v);
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1, 0);
+ vs = v;
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ if(vs < 0) {
+ gopcode(OAS, &nod1, Z, &nod1);
+ gopcode(OSUB, &nod1, nodconst(0), nn);
+ } else
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z, 0);
+ if(r != Z)
+ cgen(r, Z, 0);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+
+ if(a->op == OCONST && typev[a->type->etype]) {
+ if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+
+ bf[0] = p->as;
+ bf[1] = p->scond;
+ bf[2] = p->reg;
+ bf[3] = p->lineno;
+ bf[4] = p->lineno>>8;
+ bf[5] = p->lineno>>16;
+ bf[6] = p->lineno>>24;
+ bp = zaddr(bf+7, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ ulong sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ long l;
+ Ieee e;
+
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ }
+ return bp;
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael2);
+ o = align(o, t, Ael1);
+ w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v = round(v, SZ_LONG);
+ if(v > max)
+ return v;
+ return max;
+}
diff --git a/utils/5c/txt.c b/utils/5c/txt.c
new file mode 100644
index 00000000..d1025e7f
--- /dev/null
+++ b/utils/5c/txt.c
@@ -0,0 +1,1249 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ Type *t;
+
+ thechar = '5';
+ thestring = "arm";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+ zprog.scond = 0xE;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ memset(reg, 0, sizeof(reg));
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(reg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NFREG; i++)
+ if(reg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z, 0);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesuv[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1, 0);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1, 0);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1, 0);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1, 0);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+int
+tmpreg(void)
+{
+ int i;
+
+ for(i=REGRET+1; i<NREG; i++)
+ if(reg[i] == 0)
+ return i;
+ diag(Z, "out of fixed registers");
+ return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<NREG; i++) {
+ if(j >= NREG)
+ j = REGRET+1;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NFREG)
+ goto out;
+ }
+ j = 0*2 + NREG;
+ for(i=NREG; i<NREG+NFREG; i++) {
+ if(j >= NREG+NFREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ nodreg(n, tn, 0);
+ return;
+out:
+ reg[i]++;
+/* lasti++; *** StrongARM does register forwarding */
+ if(lasti >= 5)
+ lasti = 0;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_LONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmovm(Node *f, Node *t, int w)
+{
+ gins(AMOVM, f, t);
+ p->scond |= C_UBIT;
+ if(w)
+ p->scond |= C_WBIT;
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ }
+
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ a = AMOVW;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ }
+ if(typechlp[ft] && typeilp[tt])
+ regalloc(&nod, t, t);
+ else
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TVLONG:
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ a = AMOVD;
+ if(ft == TFLOAT)
+ a = AMOVFD;
+ break;
+ case TFLOAT:
+ a = AMOVDF;
+ if(ft == TFLOAT)
+ a = AMOVF;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVDW;
+ if(ft == TFLOAT)
+ a = AMOVFW;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVDW;
+ if(ft == TFLOAT)
+ a = AMOVFW;
+ break;
+ }
+ break;
+ case TUINT:
+ case TINT:
+ case TULONG:
+ case TLONG:
+ case TIND:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ gins(AMOVWD, f, t);
+ if(ft == TULONG) {
+ }
+ return;
+ case TFLOAT:
+ gins(AMOVWF, f, t);
+ if(ft == TULONG) {
+ }
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TUINT:
+ case TINT:
+ case TULONG:
+ case TLONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AMOVF || a == AMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gmover(Node *f, Node *t)
+{
+ int ft, tt, a;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ a = AGOK;
+ if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
+ switch(tt){
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ }
+ }
+ if(a == AGOK)
+ gmove(f, t);
+ else
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et;
+ Adr ta;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADD;
+ if(et == TFLOAT)
+ a = AADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ if(f2 && f2->op == OCONST) {
+ Node *t = f1;
+ f1 = f2;
+ f2 = t;
+ a = ARSB;
+ } else
+ a = ASUB;
+ if(et == TFLOAT)
+ a = ASUBF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ASUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AEOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ break;
+
+ case OFUNC:
+ a = ABL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ a = AMUL;
+ if(et == TFLOAT)
+ a = AMULF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AMULD;
+ break;
+
+ case OASDIV:
+ case ODIV:
+ a = ADIV;
+ if(et == TFLOAT)
+ a = ADIVF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ADIVD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ a = AMOD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULU;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ a = AMODU;
+ break;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVU;
+ break;
+
+ case OCASE:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMP;
+ if(et == TFLOAT)
+ a = ACMPF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ACMPD;
+ nextpc();
+ p->as = a;
+ naddr(f1, &p->from);
+ if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
+ p->as = ACMN;
+ p->from.offset = -p->from.offset;
+ }
+ raddr(f2, p);
+ switch(o) {
+ case OEQ:
+ a = ABEQ;
+ break;
+ case ONE:
+ a = ABNE;
+ break;
+ case OLT:
+ a = ABLT;
+ break;
+ case OLE:
+ a = ABLE;
+ break;
+ case OGE:
+ a = ABGE;
+ break;
+ case OGT:
+ a = ABGT;
+ break;
+ case OLO:
+ a = ABLO;
+ break;
+ case OLS:
+ a = ABLS;
+ break;
+ case OHS:
+ a = ABHS;
+ break;
+ case OHI:
+ a = ABHI;
+ break;
+ case OCASE:
+ nextpc();
+ p->as = ACASE;
+ p->scond = 0x9;
+ naddr(f2, &p->from);
+ a = ABHI;
+ break;
+ }
+ f1 = Z;
+ f2 = Z;
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AB;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ if(a == ATEXT)
+ p->reg = (profileflg ? 0 : NOPROF);
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= (vlong)(-32766) && vv < (vlong)32766)
+ return 1;
+ /*
+ * should be specialised for constant values which will
+ * fit in different instructionsl; for now, let 5l
+ * sort it out
+ */
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+sval(long v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return 1;
+ if((~v & ~0xff) == 0)
+ return 1;
+ v = (v<<2) | ((ulong)v>>30);
+ }
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= REGEXT-4)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= NFREG-1)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/5coff/5coff.c b/utils/5coff/5coff.c
new file mode 100644
index 00000000..cae73108
--- /dev/null
+++ b/utils/5coff/5coff.c
@@ -0,0 +1,316 @@
+#include "auxi.h"
+
+#define RND(x, y) ((((x)+(y)-1)/(y))*(y))
+
+char *cmd;
+int sflag, dflag;
+
+int ifd, ofd;
+Fhdr ihdr;
+
+long HEADR, INITTEXT, INITDAT, INITRND, INITENTRY;
+long textsize, datsize, bsssize;
+
+int cout;
+int thumb;
+
+static void get_file(char *);
+static void put_file(char *);
+static void usage(char *);
+static long strxtol(char *);
+static void readsyms(void);
+
+char *fail = "error";
+
+void
+main(int argc, char *argv[])
+{
+ char *a, *ifile, *ofile;
+
+ cmd = argv[0];
+
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = -1;
+
+ ARGBEGIN {
+ /*
+ * Options without args
+ */
+ case 's':
+ sflag = 1;
+ break;
+ /*
+ * Options with args
+ */
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = strxtol(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = strxtol(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = strxtol(a);
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = strxtol(a);
+ break;
+ case 'd':
+ dflag |= strxtol(ARGF());
+ break;
+ default:
+ usage("Invalid option");
+ } ARGEND
+
+ if (argc != 2)
+ usage("Wrong number of arguments");
+
+ ifile = argv[0];
+ ofile = argv[1];
+
+ get_file(ifile);
+ put_file(ofile);
+ exits(0);
+}
+
+char usagemsg[] =
+"usage: %s options infile outfile\n\t options (for outfile): -H[1234] -s -T<text> -D<data> -R<rnd> -E<entry>\n";
+
+static void
+usage(char *msg)
+{
+ fprint(2, "***Error: %s\n", msg);
+ fprint(2, usagemsg, cmd);
+ exits("usage");
+}
+
+static long
+strxtol(char *s)
+{
+ char *es;
+ int base = 0;
+ long r;
+
+ if (*s == '0')
+ if (*++s == 'x'){
+ base = 16;
+ s++;
+ }
+ else
+ base = 8;
+ r = strtol(s, &es, base);
+ if (*es)
+ usage("bad number");
+ return(r);
+}
+
+static void
+get_file(char *ifile)
+{
+ int h;
+
+ ifd = open(ifile, OREAD);
+ if (ifd < 0) {
+ fprint(2, "5coff: open %s: %r\n", ifile);
+ exits("open");
+ }
+ h = crackhdr(ifd, &ihdr);
+ if (!h || dflag){
+ fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, ihdr.type, ihdr.name);
+ fprint(2, "txt %lux, ent %lux, txtsz %lux, dataddr %lux\n",
+ ihdr.txtaddr, ihdr.entry, ihdr.txtsz, ihdr.dataddr);
+ }
+ if (!h)
+ usage("File type not recognized");
+ machbytype(ihdr.type);
+ if (dflag)
+ fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize);
+
+ HEADR = 22+28+3*48;
+ if(INITTEXT == -1)
+ INITTEXT = ihdr.txtaddr;
+ else
+ ihdr.txtaddr = INITTEXT;
+ if(INITDAT == -1)
+ INITDAT = ihdr.dataddr;
+ else
+ ihdr.dataddr = INITDAT;
+ if(INITENTRY == -1)
+ INITENTRY = ihdr.entry;
+ else
+ ihdr.entry = INITENTRY;
+ textsize = ihdr.txtsz;
+ datsize = ihdr.datsz;
+ bsssize = ihdr.bsssz;
+ if(INITRND > 0)
+ ihdr.dataddr = INITDAT = RND(INITTEXT+textsize, INITRND);
+ if(0){
+ INITTEXT = INITENTRY;
+ INITDAT = RND(INITTEXT+textsize, 4);
+ }
+ if(0){
+ print("H=%lux T=%lux D=%lux t=%lux d=%lux b=%lux e=%lux\n", HEADR, INITTEXT, INITDAT, textsize, datsize, bsssize, INITENTRY);
+ print("%lux %lux %lux %lux %lux %lux\n", ihdr.txtaddr, ihdr.dataddr, ihdr.entry, ihdr.txtsz, ihdr.datsz, ihdr.bsssz);
+ }
+
+ readsyms();
+}
+
+#define WB 128
+#define WSAFE (WB-4)
+char Wbuf[WB];
+char *wp = Wbuf;
+
+void
+cflush(void)
+{
+ if(wp > Wbuf)
+ write(ofd, Wbuf, wp-Wbuf);
+ wp = Wbuf;
+}
+
+void
+lput(long l)
+{
+ wp[0] = l>>24;
+ wp[1] = l>>16;
+ wp[2] = l>>8;
+ wp[3] = l;
+ wp += 4;
+ if(wp >= Wbuf+WSAFE)
+ cflush();
+}
+
+void
+cput(int l)
+{
+ wp[0] = l;
+ wp += 1;
+ if(wp >= Wbuf+WSAFE)
+ cflush();
+}
+
+void
+hputl(int l)
+{
+ wp[1] = l>>8;
+ wp[0] = l;
+ wp += 2;
+ if(wp >= Wbuf+WSAFE)
+ cflush();
+}
+
+void
+lputl(long l)
+{
+ wp[3] = l>>24;
+ wp[2] = l>>16;
+ wp[1] = l>>8;
+ wp[0] = l;
+ wp += 4;
+ if(wp >= Wbuf+WSAFE)
+ cflush();
+}
+
+static void
+copyseg(long sz)
+{
+ char buf[1024];
+
+ cflush();
+ while (sz > 0){
+ long n;
+ long r;
+
+ n = sz;
+ if (n > sizeof buf)
+ n = sizeof buf;
+ sz -= n;
+
+ if ((r = read(ifd, buf, n)) != n){
+ fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(ifd, 0, 1));
+ perror("Premature eof");
+ exits(fail);
+ }
+ if ((r = write(ofd, buf, n)) != n){
+ fprint(2, "%ld = write(...%ld)\n", r, n);
+ perror("Write error!");
+ exits(fail);
+ }
+ }
+ cflush();
+}
+
+static void
+put_file(char *ofile)
+{
+ ofd = create(ofile, OWRITE, 0666);
+ if (ofd < 0) {
+ fprint(2, "5coff: create %s: %r\n", ofile);
+ exits("create");
+ }
+ cout = ofd;
+
+ /* TBS lput for Plan9 header before ? */
+
+ seek(ifd, ihdr.txtoff, 0);
+ seek(ofd, HEADR, 0);
+ copyseg(ihdr.txtsz);
+
+ seek(ifd, ihdr.datoff, 0);
+ seek(ofd, HEADR+textsize, 0);
+ copyseg(ihdr.datsz);
+
+ seek(ofd, HEADR+textsize+datsize, 0);
+ coffsym();
+ cflush();
+ cofflc();
+ cflush();
+
+ seek(ofd, 0, 0);
+ coffhdr();
+ cflush();
+
+ close(ifd);
+ close(ofd);
+}
+
+long
+entryvalue(void)
+{
+ return INITENTRY;
+}
+
+void
+diag(char *s, ...)
+{
+ fprint(2, "%s\n", s);
+ exits("error");
+}
+
+static void
+readsyms(void)
+{
+ int i;
+ long n;
+ Sym *s;
+
+ if(sflag)
+ return;
+ n = syminit(ifd, &ihdr);
+ beginsym();
+ for(i = 0; i < n; i++){
+ s = getsym(i);
+ newsym(i, s->name, s->value, s->type);
+ }
+ endsym();
+}
diff --git a/utils/5coff/NOTICE b/utils/5coff/NOTICE
new file mode 100644
index 00000000..3b08f95f
--- /dev/null
+++ b/utils/5coff/NOTICE
@@ -0,0 +1,27 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 2001-2003 Vita Nuova Holdings Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/utils/5coff/auxi.c b/utils/5coff/auxi.c
new file mode 100644
index 00000000..93e56c29
--- /dev/null
+++ b/utils/5coff/auxi.c
@@ -0,0 +1,251 @@
+#include "auxi.h"
+
+Prog *firstp, *textp, *curtext, *lastp, *etextp;
+Symx *hash[NHASH];
+Auto *lasta;
+long autosize;
+int version = 0;
+
+static int
+private(char *s)
+{
+ return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0;
+}
+
+static int
+zlen(char *s)
+{
+ int i;
+
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2)
+ ;
+ i++;
+ return i+1;
+}
+
+static Symx*
+allocsym(char *symb, int l, int v)
+{
+ Symx *s;
+
+ s = malloc(sizeof(Symx));
+ s->name = malloc(l);
+ memmove(s->name, symb, l);
+ s->name[l-1] = '\0';
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->link = nil;
+ return s;
+}
+
+Symx*
+lookupsym(char *symb, int v)
+{
+ Symx *s, **as;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != nil; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+ s = allocsym(symb, l, v);
+ for(as = &hash[h]; *as != nil; as = &((*as)->link))
+ ;
+ *as = s;
+ // s->link = hash[h];
+ // hash[h] = s;
+ return s;
+}
+
+static void
+addauto(Auto **aut, Symx *s, int t, long v)
+{
+ Auto *a, **aa;
+
+ a = (Auto*)malloc(sizeof(Auto));
+ a->asym = s;
+ a->link = nil;
+ a->aoffset = v;
+ a->type = t;
+ for(aa = aut; *aa != nil; aa = &((*aa)->link))
+ ;
+ *aa = a;
+}
+
+static Prog*
+newprog(int as, long pc, long ln)
+{
+ Prog *p;
+
+ p = (Prog *)malloc(sizeof(Prog));
+ p->as = as;
+ p->pc = pc;
+ p->line = ln;
+ p->link = p->cond = P;
+ if(firstp == P)
+ firstp = p;
+ else
+ lastp->link = p;
+ lastp = p;
+ if(as == ATEXT){
+ if(textp == P)
+ textp = p;
+ else
+ etextp->cond = p;
+ etextp = p;
+ }
+ return p;
+}
+
+static int
+line(long pc)
+{
+ char buf[1024], *s;
+
+ // return pc2line(pc);
+ if(fileline(buf, sizeof(buf), pc)){
+ for(s = buf; *s != ':' && *s != '\0'; s++)
+ ;
+ if(*s != ':')
+ return -1;
+ return atoi(s+1);
+ }
+ return -1;
+}
+
+static void
+lines(long v)
+{
+ long ll, nl, pc;
+ if(etextp != P){
+ ll = 0;
+ for(pc = etextp->pc; pc < v; pc += 4){
+ nl = line(pc);
+ if(nl != -1 && nl != ll){
+ newprog(ATEXT-1, pc, nl);
+ ll = nl;
+ }
+ }
+ pc -= 4;
+ if(lastp->pc != pc){
+ nl = line(pc);
+ if(nl != -1)
+ newprog(ATEXT-1, pc, nl);
+ }
+ }
+}
+
+void
+beginsym(void)
+{
+}
+
+/* create the same structures as in 5l so we can use same coff.c source file */
+void
+newsym(int i, char *nm, long v, int t)
+{
+ long l, ver;
+ char *os;
+ Symx *s;
+ Prog *p;
+
+ if(i == 0 && (t == 't' || t == 'T') && strcmp(nm, "etext") == 0)
+ return;
+ if(nm[0] == '.' && private(nm+1))
+ return;
+// print("%s %ld %c\n", nm, v, t);
+ ver = 0;
+ if(t == 't' || t == 'l' || t == 'd' || t == 'b'){
+ ver = ++version;
+ if(ver == 0)
+ diag("0 version for static");
+ }
+ if(t == 'a' || t == 'p')
+ s = allocsym(nm, strlen(nm)+1, 0);
+ else if(t == 'z' || t == 'Z')
+ s = allocsym(nm, zlen(nm), 0);
+ else if(t != 'm'){
+ s = lookupsym(nm, ver);
+ if(s->type != 0)
+ diag("seen sym before in newsym");
+ s->value = v;
+ }
+ else
+ s = nil;
+ switch(t){
+ case 'T':
+ case 'L':
+ case 't':
+ case 'l':
+ lines(v);
+ if(t == 'l' || t == 'L')
+ s->type = SLEAF;
+ else
+ s->type = STEXT;
+ p = newprog(ATEXT, v, line(v));
+ p->from.sym = s;
+ p->to.autom = lasta;
+ lasta = nil;
+ break;
+ case 'D':
+ case 'd':
+ s->type = SDATA;
+ s->value -= INITDAT;
+ break;
+ case 'B':
+ case 'b':
+ s->type = SBSS;
+ s->value -= INITDAT;
+ break;
+ case 'f':
+ // version++;
+ s->type = SFILE;
+ os = s->name;
+ l = strlen(os)+1;
+ s->name = malloc(l+1);
+ s->name[0] = '>';
+ memmove(s->name+1, os, l);
+ free(os);
+ break;
+/*
+ case 'f'+'a'-'A':
+ s->type = SFILE;
+ break;
+*/
+ case 'z':
+ addauto(&lasta, s, D_FILE, v);
+ break;
+ case 'Z':
+ addauto(&lasta, s, D_FILE1, v);
+ break;
+ case 'a':
+ addauto(&(etextp->to.autom), s, D_AUTO, -v);
+ break;
+ case 'p':
+ addauto(&(etextp->to.autom), s, D_PARAM, v);
+ break;
+ case 'm':
+ etextp->to.offset = v-4;
+ autosize = v;
+ break;
+ default:
+ diag("bad case in newsym");
+ break;
+ }
+}
+
+void
+endsym(void)
+{
+ lines(INITTEXT+textsize);
+}
diff --git a/utils/5coff/auxi.h b/utils/5coff/auxi.h
new file mode 100644
index 00000000..e9907523
--- /dev/null
+++ b/utils/5coff/auxi.h
@@ -0,0 +1,46 @@
+#define COFFCVT
+#define Sym Symx
+#include "../5l/l.h"
+#undef Sym
+#include <mach.h>
+
+/*
+ * auxi.c
+ */
+extern Symx *hash[NHASH];
+Symx *lookupsym(char*, int);
+void beginsym(void);
+void endsym(void);
+void newsym(int, char*, long, int);
+
+extern long autosize;
+extern Prog *firstp, *textp, *curtext, *lastp, *etextp;
+
+/*
+ * coff.c
+ */
+void coffhdr(void);
+void coffsym(void);
+void cofflc(void);
+void endsym(void);
+
+/*
+ * 5coff.c
+ */
+void cflush(void);
+void lput(long);
+void cput(int);
+void hputl(int);
+void lputl(long);
+long entryvalue(void);
+void diag(char*, ...);
+extern long HEADR; /* length of header */
+extern long INITDAT; /* data location */
+extern long INITRND; /* data round above text location */
+extern long INITTEXT; /* text location */
+extern long INITENTRY; /* entry point */
+extern long textsize;
+extern long datsize;
+extern long bsssize;
+extern int cout;
+extern int thumb;
diff --git a/utils/5coff/coff.c b/utils/5coff/coff.c
new file mode 100644
index 00000000..7a057ea5
--- /dev/null
+++ b/utils/5coff/coff.c
@@ -0,0 +1,642 @@
+#include "auxi.h"
+
+/*
+ * in some embedded coff files, edata and end have type 0 not 4,
+ * and file value is pointer to next file sym (as here), but the last one
+ * points to an external symbol, not 0 as here.
+ */
+
+#define C_NULL 0
+#define C_AUTO 1
+#define C_EXT 2
+#define C_STAT 3
+#define C_ARG 9
+#define C_FCN 101
+#define C_FILE 103
+
+#define T_VOID 0
+#define T_CHAR 2
+#define T_SHORT 3
+#define T_INT 4
+#define T_LONG 5
+
+#define DT_NON 0
+#define DT_PTR 1
+#define DT_FCN 2
+#define DT_ARY 3
+
+#define T(a, b) (((a)<<4)|b)
+
+#define DOTTEXT ".text"
+#define DOTDATA ".data"
+#define DOTBSS ".bss"
+#define DOTBF ".bf"
+#define DOTEF ".ef"
+
+#define SINDEX(s) (*((long*)(&s->become)))
+#define LINDEX(s) (*((long*)(&s->used)))
+
+typedef struct Hist Hist;
+
+struct Hist{
+ Auto *a;
+ Hist *n;
+};
+
+static int nsym, nlc, lines;
+
+static void cofflcsz(void);
+
+static Hist *freeh, *curh;
+
+static void
+dohist(Auto *a)
+{
+ Hist *h, **ha;
+
+ if(a->aoffset == 1){ /* new file */
+ for(ha = &curh; *ha != nil; ha = &((*ha)->n))
+ ;
+ *ha = freeh;
+ freeh = curh;
+ curh = nil;
+ }
+ if(freeh != nil){
+ h = freeh;
+ freeh = freeh->n;
+ }
+ else
+ h = malloc(sizeof(Hist));
+ h->a = a;
+ h->n = nil;
+ for(ha = &curh; *ha != nil; ha = &((*ha)->n))
+ ;
+ *ha = h;
+}
+
+static long
+lineno(long n)
+{
+ long o, d;
+ Hist *h;
+
+ if(1)
+ return n; /* now using fileline() not pc2line() */
+
+ if(curh == nil)
+ return 0;
+ o = curh->a->aoffset-1;
+ d = 1;
+ for(h = curh->n; d && h != nil; h = h->n){
+ if(h->a->asym->name[1] || h->a->asym->name[2]){
+ if(h->a->type == D_FILE1) {
+ ;
+ }
+ else if(d == 1 && n < h->a->aoffset)
+ break;
+ else if(d++ == 1)
+ o -= h->a->aoffset;
+ }
+ else if(--d == 1)
+ o += h->a->aoffset;
+ }
+ return n-o;
+}
+
+static char *
+filelookup(int k)
+{
+ int i;
+ Symx *s;
+
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->type == SFILE && k == s->value)
+ return s->name+1;
+ }
+ }
+ return "";
+}
+
+static char*
+filename(char *s)
+{
+ int j, k, l;
+ static char buf[256];
+
+ buf[0] = '\0';
+ if(s[0] != 0)
+ diag("bad filename");
+ for(j = 1; ; j += 2){
+ k = (s[j]<<8)|s[j+1];
+ if(k == 0)
+ break;
+ l = strlen(buf);
+ if(l != 0 && buf[l-1] != '/')
+ strcat(buf, "/");
+ strcat(buf, filelookup(k));
+ }
+ return buf;
+}
+
+static void
+sput(char *s, int n)
+{
+ int i;
+
+ for(i = 0; i < n && s != nil && *s != '\0'; i++, s++)
+ cput(*s);
+ for( ; i < n; i++)
+ cput(0);
+}
+
+static void
+coffsect(char *s, long a, long sz, long o, long lp, long nl, long f)
+{
+ if(0)
+ print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz);
+ sput(s, 8); /* name <= 8 chars in len */
+ lputl(a); /* pa */
+ lputl(a); /* va */
+ lputl(sz); /* size */
+ lputl(o); /* file offset */
+ lputl(0); /* reloc */
+ lputl(lp); /* line nos */
+ lputl(0); /* no reloc entries */
+ lputl(nl); /* no line no entries */
+ lputl(f); /* flags */
+ hputl(0); /* reserved */
+ hputl(0); /* mem page no */
+}
+
+void
+coffhdr(void)
+{
+ if(0){
+ print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize);
+ print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT);
+ }
+
+ /*
+ * file header
+ */
+ hputl(0xc2); /* version ID */
+ hputl(3); /* no section hdrs */
+ lputl(0); /* date stamp */
+ lputl(HEADR+textsize+datsize+6*nlc); /* sym table */
+ lputl(nsym); /* no sym table entries */
+ hputl(28); /* size optional hdr */
+ hputl(0x0103); /* flags */
+ hputl(0x97); /* target ID */
+ /*
+ * optional file header
+ */
+ hputl(0x108); /* magic */
+ hputl(0); /* version stamp */
+ lputl(textsize); /* text size */
+ lputl(datsize); /* data size */
+ lputl(bsssize); /* bss size */
+ lputl(entryvalue()); /* entry pt */
+ lputl(INITTEXT); /* text start */
+ lputl(INITDAT); /* data start */
+ /*
+ * sections
+ */
+ coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20);
+ coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40);
+ coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80);
+}
+
+static int
+private(char *s)
+{
+ return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0;
+}
+
+static long stoff = 4;
+
+static long
+stput(char *s)
+{
+ long r;
+
+ r = stoff;
+ stoff += strlen(s)+1;
+ return r;
+}
+
+static long
+strput(char *s)
+{
+ int l;
+
+ if((l = strlen(s)) > 8){
+ if(*s == '.' && private(s+1))
+ return 0;
+ while(*s)
+ cput(*s++);
+ cput(*s);
+ return l+1;
+ }
+ return 0;
+}
+
+static void
+stflush(void)
+{
+ int i;
+ long o;
+ Prog *p;
+ Auto *a, *f;
+ Symx *s;
+ char *fn, file[256];
+
+ lputl(stoff);
+ o = 4;
+ for(p = firstp; p != P; p = p->link){
+ if(p->as == ATEXT){
+ f = nil;
+ fn = nil;
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_FILE){
+ f = a;
+ break;
+ }
+ }
+ if(f != nil)
+ fn = filename(f->asym->name);
+ if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
+ strcpy(file, fn);
+ o += strput(file);
+ }
+ o += strput(p->from.sym->name);
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_AUTO || a->type == D_PARAM)
+ o += strput(a->asym->name);
+ }
+ }
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
+ o += strput(s->name);
+ }
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
+ o += strput(s->name);
+ }
+ }
+ if(o != stoff)
+ diag("bad stflush offset");
+}
+
+static int
+putsect(Symx *s)
+{
+ int sz, ln;
+
+ sz = ln = 0;
+ // isn't this repetition ?
+ if(strcmp(s->name, DOTTEXT) == 0){
+ sz = textsize;
+ ln = nlc;
+ }
+ else if(strcmp(s->name, DOTDATA) == 0)
+ sz = datsize;
+ else if(strcmp(s->name, DOTBSS) == 0)
+ sz = bsssize;
+ else
+ diag("bad putsect sym");
+ lputl(sz);
+ hputl(0);
+ hputl(ln);
+ sput(nil, 10);
+ return 1;
+}
+
+static int
+putfun(Symx *s)
+{
+ /* lputl(SINDEX(s)+2); */
+ lputl(0);
+ lputl(0); /* patched later */
+ lputl(HEADR+textsize+datsize+LINDEX(s));
+ lputl(0); /* patched later */
+ sput(nil, 2);
+ return 1;
+}
+
+static int
+putbf(int lno)
+{
+ lputl(0);
+ hputl(lno);
+ hputl(lines);
+ lputl(autosize);
+ lputl(0); /* patched later */
+ sput(nil, 2);
+ return 1;
+}
+
+static int
+putef(int lno)
+{
+ sput(nil, 4);
+ hputl(lno);
+ sput(nil, 12);
+ return 1;
+}
+
+static int
+putsym(Symx *s, int sc, int t, int lno)
+{
+ long v;
+
+ if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1)))
+ return 0;
+ if(0)
+ print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t);
+ if(strlen(s->name) <= 8)
+ sput(s->name, 8);
+ else{
+ lputl(0);
+ lputl(stput(s->name));
+ }
+ /* value */
+ v = s->value;
+ if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS)
+ lputl(INITDAT+v);
+ else if(sc == C_AUTO)
+ lputl(autosize+v);
+ else if(sc == C_ARG)
+ lputl(autosize+v+4);
+ else
+ lputl(v);
+ switch(s->type){ /* section number */
+ case STEXT:
+ case SLEAF:
+ hputl(1);
+ break;
+ case SDATA:
+ case SDATA1:
+ hputl(2);
+ break;
+ case SBSS:
+ hputl(3);
+ break;
+ case SFILE:
+ hputl(-2);
+ break;
+ default:
+ diag("type %d in putsym", s->type);
+ break;
+ }
+ hputl(t); /* type */
+ cput(sc); /* storage class */
+ /* aux entries */
+ if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){ /* section */
+ cput(1);
+ return 1+putsect(s);
+ }
+ else if((t>>4) == DT_FCN){ /* function */
+ cput(1);
+ return 1+putfun(s);
+ }
+ else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){ /* bf */
+ cput(1);
+ return 1+putbf(lno);
+ }
+ else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){ /* ef */
+ cput(1);
+ return 1+putef(lno);
+ }
+ cput(0); /* 0 aux entry */
+ return 1;
+}
+
+static Symx*
+defsym(char *p, int t, long v)
+{
+ Symx *s;
+
+ s = lookupsym(p, 0);
+ if(s->type == SDATA || s->type == SBSS)
+ return nil; /* already output */
+ if(s->type == 0 || s->type == SXREF){
+ s->type = t;
+ s->value = v;
+ }
+ return s;
+}
+
+static int
+specsym(char *p, int t, long v, int c)
+{
+ return putsym(defsym(p, t, v), c, T_VOID, 0);
+}
+
+static int
+cclass(Symx *s)
+{
+/*
+ if(s->version > 0 && dclass == D_EXTERN)
+ diag("%s: version %d dclass EXTERN", s->name, s->version);
+ if(s->version == 0 && dclass == D_STATIC)
+ diag("%s: version %d dclass STATIC", s->name, s->version);
+*/
+ return s->version > 0 ? C_STAT : C_EXT;
+}
+
+static void
+patchsym(long i, long o, long v)
+{
+ long oo;
+
+ cflush();
+ oo = seek(cout, 0, 1);
+ seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0);
+ lputl(v);
+ cflush();
+ seek(cout, oo, 0);
+}
+
+void
+coffsym(void)
+{
+ int i;
+ long ns, lno, lpc, v, vs, lastf;
+ Prog *p;
+ Auto *a, *f;
+ Symx *s, *bf, *ef, ts;
+ char *fn, file[256];
+
+ file[0] = '\0';
+ cofflcsz();
+ seek(cout, 6*nlc, 1); /* advance over line table */
+ ns = 0;
+ lpc = -1;
+ lno = -1;
+ lastf = -1;
+ bf = defsym(DOTBF, STEXT, 0);
+ ef = defsym(DOTEF, STEXT, 0);
+ for(p = firstp; p != P; p = p->link){
+ setarch(p);
+ if(p->as != ATEXT){
+ if(p->line != 0)
+ lno = lineno(p->line);
+ }
+ if(p->as == ATEXT){
+ curtext = p;
+ autosize = p->to.offset+4;
+ if(lpc >= 0){
+ ef->value = lpc;
+ ns += putsym(ef, C_FCN, T_VOID, lno);
+ }
+ f = nil;
+ fn = nil;
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_FILE || a->type == D_FILE1)
+ dohist(a);
+ if(f == nil && a->type == D_FILE)
+ f = a; /* main filename */
+ }
+ if(f != nil)
+ fn = filename(f->asym->name);
+ if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
+ strcpy(file, fn);
+ ts.name = file;
+ ts.type = SFILE;
+ ts.value = 0;
+ if(lastf >= 0)
+ patchsym(lastf, 8, ns);
+ lastf = ns;
+ ns += putsym(&ts, C_FILE, T_VOID, 0);
+ }
+ if(p->link != P && p->link->line != 0)
+ lno = lineno(p->link->line);
+ else if(p->line != 0)
+ lno = lineno(p->line);
+ s = p->from.sym;
+ SINDEX(s) = ns;
+ ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0);
+ if(p->cond != P)
+ lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1;
+ else
+ lines = 0;
+ bf->value = p->pc;
+ ns += putsym(bf, C_FCN, T_VOID, lno);
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_AUTO || a->type == D_PARAM){
+ ts.name = a->asym->name;
+ ts.type = STEXT;
+ ts.value = a->aoffset;
+ ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0);
+ }
+ }
+ }
+ lpc = p->pc;
+ }
+ if(lpc >= 0){
+ ef->value = lpc;
+ ns += putsym(ef, C_FCN, T_VOID, lno);
+ }
+ /* patch up */
+ for(p = textp; p != P; p = p->cond){
+ s = p->from.sym;
+ if(p->cond != P){
+ v = SINDEX(p->cond->from.sym);
+ vs = p->cond->pc - p->pc;
+ }
+ else{
+ v = 0;
+ vs = INITTEXT+textsize-p->pc;
+ }
+ patchsym(SINDEX(s)+1, 4, 8*vs);
+ patchsym(SINDEX(s)+1, 12, v);
+ patchsym(SINDEX(s)+3, 12, v);
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
+ ns += putsym(s, cclass(s), T_INT, 0);
+ }
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
+ ns += putsym(s, cclass(s), T_INT, 0);
+ }
+ }
+ ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT);
+ ns += specsym(DOTDATA, SDATA, 0, C_STAT);
+ ns += specsym(DOTBSS, SBSS, datsize, C_STAT);
+ ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT);
+ ns += specsym("edata", SDATA, datsize, C_EXT);
+ ns += specsym("end", SBSS, datsize+bsssize, C_EXT);
+ nsym = ns;
+ stflush();
+}
+
+void
+cofflc(void)
+{
+ long olc, nl;
+ Symx *s;
+ Prog *p;
+ Auto *a;
+
+ cflush();
+ seek(cout, HEADR+textsize+datsize, 0);
+ nl = 0;
+ /* opc = INITTEXT; */
+ olc = 0;
+ for(p = firstp; p != P; p = p->link){
+ setarch(p);
+ if(p->as == ATEXT){
+ curtext = p;
+ s = p->from.sym;
+ /* opc = p->pc; */
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_FILE || a->type == D_FILE1)
+ dohist(a);
+ }
+ lputl(SINDEX(s));
+ hputl(0);
+ nl++;
+ continue;
+ }
+ if(p->line == 0 || p->line == olc || p->as == ANOP)
+ continue;
+ lputl(p->pc);
+ hputl(lineno(p->line));
+ nl++;
+ olc = p->line;
+ }
+ if(nl != nlc)
+ diag("bad line count in cofflc()");
+ nlc = nl;
+}
+
+static void
+cofflcsz(void)
+{
+ long olc, nl;
+ Prog *p;
+
+ nl = 0;
+ olc = 0;
+ for(p = firstp; p != P; p = p->link){
+ if(p->as == ATEXT){
+ LINDEX(p->from.sym) = nl;
+ nl++;
+ continue;
+ }
+ if(p->line == 0 || p->line == olc || p->as == ANOP)
+ continue;
+ nl++;
+ olc = p->line;
+ }
+ nlc = nl;
+}
diff --git a/utils/5coff/mkfile b/utils/5coff/mkfile
new file mode 100644
index 00000000..22d389ba
--- /dev/null
+++ b/utils/5coff/mkfile
@@ -0,0 +1,23 @@
+<../../mkconfig
+
+TARG=5coff
+
+OFILES= 5coff.$O\
+ coff.$O\
+ auxi.$O\
+
+HFILES=\
+ a.out.h\
+ bio.h\
+ mach.h\
+
+LIBS=mach bio 9 # order matters.
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+$O.readcoff: readcoff.$O
+ $LD $LDFLAGS -o $target readcoff.$O $libs $SYSLIBS
diff --git a/utils/5coff/readcoff.c b/utils/5coff/readcoff.c
new file mode 100644
index 00000000..aa74ecc1
--- /dev/null
+++ b/utils/5coff/readcoff.c
@@ -0,0 +1,298 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+int fd;
+static void readf(void);
+
+static void
+usage(char *msg)
+{
+ fprint(2, "***Error: %s\n", msg);
+ exits("usage");
+}
+
+static int
+cget(void)
+{
+ uchar b[1];
+
+ if(read(fd, b, 1) != 1){
+ fprint(2, "bad cget\n");
+ exits("cget");
+ }
+ return b[0];
+}
+
+static int
+hget(void)
+{
+ uchar b[2];
+
+ if(read(fd, b, 2) != 2){
+ fprint(2, "bad hget\n");
+ exits("hget");
+ }
+ return b[1]<<8 | b[0];
+}
+
+static int
+lget(void)
+{
+ uchar b[4];
+
+ if(read(fd, b, 4) != 4){
+ fprint(2, "bad lget\n");
+ exits("lget");
+ }
+ return b[3]<<24 | b[2]<<16 | b[1]<<8 | b[0];
+}
+
+static char *
+sget(char *st)
+{
+ int i;
+ static uchar buf[8+1];
+
+ for(i = 0; i < 8+1; i++)
+ buf[i] = 0;
+ if(read(fd, buf, 8) != 8){
+ fprint(2, "bad sget\n");
+ exits("sget");
+ }
+ if(buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+ return st+(buf[7]<<24|buf[6]<<16|buf[5]<<8|buf[4]);
+ return (char*)buf;
+}
+
+void
+main(int argc, char *argv[])
+{
+ if (argc != 2)
+ usage("Wrong number of arguments");
+
+ fd = open(argv[1], OREAD);
+ if (fd < 0) {
+ fprint(2, "5coff: open %s: %r\n", argv[1]);
+ exits("open");
+ }
+ readf();
+ exits(0);
+}
+
+static void
+section(int i, char *st, int *linoff, int *linn)
+{
+ int pa, va, sz, off, rel, lin, nrel, nlin, f, res, pno;
+ char *nm;
+
+ nm = sget(st);
+ pa = lget();
+ va = lget();
+ sz = lget();
+ off = lget();
+ rel = lget();
+ lin = lget();
+ nrel = lget();
+ nlin = lget();
+ f = lget();
+ res = hget();
+ pno = hget();
+ print("sect %d %s: pa=0x%x va=0x%x sz=%d off=%d rel=%d lin=%d nrel=%d nlin=%d f=0x%x res=%d pno=%d\n", i, nm, pa, va, sz, off, rel, lin, nrel, nlin, f, res, pno);
+ *linoff = lin;
+ *linn = nlin;
+}
+
+static void
+opthdr(void)
+{
+ int mag, ver, textsz, datasz, bsssz, entry, text, data;
+
+ mag = hget();
+ ver = hget();
+ textsz = lget();
+ datasz = lget();
+ bsssz = lget();
+ entry = lget();
+ text = lget();
+ data = lget();
+ print("opt: mag=0x%x ver=%d txtsz=%d datsz=%d bsssz=%d ent=0x%x txt=0x%x dat=0x%x\n", mag, ver, textsz, datasz, bsssz, entry, text, data);
+}
+
+static void
+readhdr(int *o, int *ns, int *sy, int *nsy)
+{
+ int vid, nsec, date, sym, nsym, opt, f, tid;
+
+ vid = hget();
+ nsec = hget();
+ date = lget();
+ sym = lget();
+ nsym = lget();
+ opt = hget();
+ f = hget();
+ tid = hget();
+ print("hdr: vid=0x%x nsect=%d date=%d sym=%d nsym=%d opt=%d f=0x%x tid=0x%x\n", vid, nsec, date, sym, nsym, opt, f, tid);
+ *o = opt;
+ *ns = nsec;
+ *sy = sym;
+ *nsy = nsym;
+}
+
+static void
+readauxsect(int i)
+{
+ int sz, nrel, ln;
+
+ sz = lget();
+ nrel = hget();
+ ln = hget();
+ lget();
+ hget();
+ lget();
+ print("sym auxsect %d: sz=%d nrel=%d ln=%d\n", i, sz, nrel, ln);
+}
+
+static void
+readauxfun(int i)
+{
+ int ind, sz, fpln, nind;
+
+ ind = lget();
+ sz = lget();
+ fpln = lget();
+ nind = lget();
+ hget();
+ print("sym auxfun %d: ind=%d sz=%d fpln=%d nind=%d\n", i, ind, sz, fpln, nind);
+}
+
+static void
+readauxbf(int i)
+{
+ int rsav, lno, lns, fsz, nind;
+
+ rsav = lget();
+ lno = hget();
+ lns = hget();
+ fsz = lget();
+ nind = lget();
+ hget();
+ print("sym auxbf %d: rsav=%x lno=%d lns=%d fsz=%d nind=%d\n", i, rsav, lno, lns, fsz, nind);
+}
+
+static void
+readauxef(int i)
+{
+ int lno;
+
+ lget();
+ lno = hget();
+ lget();
+ lget();
+ lget();
+ print("sym auxef %d: lno=%d\n", i, lno);
+}
+
+static void
+readauxother(int i)
+{
+ lget();
+ lget();
+ hget();
+ lget();
+ lget();
+ print("sym auxother %d\n", i);
+}
+
+static int
+readsym(int i, char *st)
+{
+ int v, s, t, c, aux;
+ char *nm;
+
+ nm = sget(st);
+ v = lget();
+ s = hget();
+ t = hget();
+ c = cget();
+ aux = cget();
+ print("sym %d %s: val=%d sec=%d type=%d class=%d aux=%d\n", i, nm, v, s, t, c, aux);
+ if(aux){
+ i++;
+ if(strcmp(nm, ".text") == 0 || strcmp(nm, ".data") == 0 || strcmp(nm, ".bss") == 0)
+ readauxsect(i);
+ else if(strcmp(nm, ".bf") == 0)
+ readauxbf(i);
+ else if(strcmp(nm, ".ef") == 0)
+ readauxef(i);
+ else if((t&0x30) == 0x20) // will do
+ readauxfun(i);
+ else
+ readauxother(i);
+ return 1;
+ }
+ return 0;
+}
+
+static char *
+readstr(int n)
+{
+ char *s = malloc(n);
+
+ if(read(fd, s+4, n-4) != n-4){
+ fprint(2, "bad readstr\n");
+ exits("sget");
+ }
+ return s;
+}
+
+static void
+readln(int i)
+{
+ int a, l;
+
+ a = lget();
+ l = hget();
+ if(l == 0)
+ print("line %d: sym=%d\n", i, a);
+ else
+ print("line %d: addr=0x%x line=%d\n", i, a, l);
+}
+
+static void
+readf()
+{
+ int i, opt, nsec, sym, nsym, stoff, strsz, linoff, nlin, lino, linn;
+ char *st;
+
+ seek(fd, 0, 0);
+ readhdr(&opt, &nsec, &sym, &nsym);
+ if(opt)
+ opthdr();
+ stoff = sym+18*nsym;
+ seek(fd, stoff, 0);
+ strsz = lget();
+ st = readstr(strsz);
+ linoff = nlin = 0;
+ seek(fd, 22+28, 0);
+ for(i = 0; i < nsec; i++){
+ section(i, st, &lino, &linn);
+ if(linn != 0){
+ if(nlin == 0){
+ nlin = linn;
+ linoff = lino;
+ }
+ else
+ print("multiple line no. tables\n");
+ }
+ }
+ seek(fd, sym, 0);
+ for(i = 0; i < nsym; i++)
+ i += readsym(i, st);
+ print("strsz = %d\n", strsz);
+ if(nlin != 0){
+ seek(fd, linoff, 0);
+ for(i = 0; i < nlin; i++)
+ readln(i);
+ }
+}
diff --git a/utils/5cv/5cv.c b/utils/5cv/5cv.c
new file mode 100644
index 00000000..1edbf6c6
--- /dev/null
+++ b/utils/5cv/5cv.c
@@ -0,0 +1,353 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+char *Cmd;
+int Hdrtype;
+int Strip;
+long Txtaddr = -1;
+
+int Ofd;
+int Ifd;
+Fhdr Ihdr;
+
+int Debug;
+
+static void get_file(char *);
+static void put_file(char *);
+static void Usage(char *);
+static long strxtol(char *);
+
+char *fail = "error";
+
+void
+main(int argc, char *argv[])
+{
+ char *ifile, *ofile;
+
+ Cmd = argv[0];
+ Hdrtype = 2;
+
+ ARGBEGIN {
+ /*
+ * Options without args
+ */
+ case 's':
+ Strip = 1;
+ break;
+ /*
+ * Options with args
+ */
+ case 'T':
+ Txtaddr = strxtol(ARGF());
+ break;
+ case 'H':
+ Hdrtype = strxtol(ARGF());
+ break;
+ case 'D':
+ Debug |= strxtol(ARGF());
+ break;
+ default:
+ Usage("Invalid option");
+ } ARGEND
+
+ if (argc != 2)
+ Usage("Wrong number of arguments");
+
+ ifile = argv[0];
+ ofile = argv[1];
+
+ get_file(ifile);
+ put_file(ofile);
+ exits(0);
+}
+
+char usagemsg[] =
+"Usage: %s options infile outfile\n\t options (for outfile): -H[123456] -s -T<text> \n";
+
+static void
+Usage(char *msg)
+{
+ fprint(2, "***Error: %s\n", msg);
+ fprint(2, usagemsg, Cmd);
+ exits("usage");
+}
+
+static long
+strxtol(char *s)
+{
+ char *es;
+ int base = 0;
+ long r;
+
+ if (*s == '0')
+ if (*++s == 'x'){
+ base = 16;
+ s++;
+ }
+ else
+ base = 8;
+ r = strtol(s, &es, base);
+ if (*es)
+ Usage("bad number");
+ return(r);
+}
+
+static void
+get_file(char *ifile)
+{
+ int h;
+ int d;
+
+ Ifd = open(ifile, OREAD);
+ if (Ifd < 0) {
+ fprint(2, "5cv: open %s: %r\n", ifile);
+ exits("open");
+ }
+ h = crackhdr(Ifd, &Ihdr);
+ if (!h || Debug){
+ fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, Ihdr.type, Ihdr.name);
+ fprint(2, "txt %lux, ent %lux, txtsz %lux, dataddr %lux\n",
+ Ihdr.txtaddr, Ihdr.entry, Ihdr.txtsz, Ihdr.dataddr);
+ }
+ if (!h)
+ Usage("File type not recognized");
+ machbytype(Ihdr.type);
+ if (Debug)
+ fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize);
+
+ if (Txtaddr != -1){
+ d = Txtaddr - Ihdr.txtaddr;
+ Ihdr.txtaddr += d;
+ Ihdr.dataddr = Ihdr.txtaddr + Ihdr.txtsz;
+ }
+}
+
+char Wbuf[128];
+char *wp = Wbuf;
+
+void
+lput(long l)
+{
+ wp[0] = l>>24;
+ wp[1] = l>>16;
+ wp[2] = l>>8;
+ wp[3] = l;
+ wp += 4;
+}
+
+void
+lputl(long l)
+{
+ wp[3] = l>>24;
+ wp[2] = l>>16;
+ wp[1] = l>>8;
+ wp[0] = l;
+ wp += 4;
+}
+
+static void
+copyseg(long sz)
+{
+ char buf[1024];
+
+ while (sz > 0){
+ long n;
+ long r;
+
+ n = sz;
+ if (n > sizeof buf)
+ n = sizeof buf;
+ sz -= n;
+
+ if ((r = read(Ifd, buf, n)) != n){
+ fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(Ifd, 0, 1));
+ perror("Premature eof");
+ exits(fail);
+ }
+ if ((r = write(Ofd, buf, n)) != n){
+ fprint(2, "%ld = write(...%ld)\n", r, n);
+ perror("Write error!");
+ exits(fail);
+ }
+ }
+}
+
+static void
+zero(long sz)
+{
+ char buf[1024];
+
+ memset(buf, 0, sizeof buf);
+ while (sz > 0){
+ long n;
+ long r;
+
+ n = sz;
+ if (n > sizeof buf)
+ n = sizeof buf;
+ sz -= n;
+
+ if ((r = write(Ofd, buf, n)) != n){
+ fprint(2, "%ld = write(...%ld)\n", r, n);
+ perror("Write error!");
+ exits(fail);
+ }
+ }
+}
+
+static long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
+
+static void
+put_file(char *ofile)
+{
+ int ii;
+ long doff;
+ long dsize;
+ long hlen;
+ long pad;
+
+ Ofd = create(ofile, OWRITE, 0666);
+ if (Ofd < 0) {
+ fprint(2, "5cv: create %s: %r\n", ofile);
+ exits("create");
+ }
+
+ pad = 0;
+
+ switch(Hdrtype) {
+ case 1: /* aif for risc os */
+ Strip = 1;
+ hlen = 128;
+ lputl(0xe1a00000); /* NOP - decompress code */
+ lputl(0xe1a00000); /* NOP - relocation code */
+ lputl(0xeb000000 + 12); /* BL - zero init code */
+ lputl(0xeb000000 +
+ (Ihdr.entry
+ - Ihdr.txtaddr
+ + hlen
+ - 12
+ - 8) / 4); /* BL - entry code */
+
+ lputl(0xef000011); /* SWI - exit code */
+ doff = Ihdr.txtsz+hlen;
+ lputl(doff); /* text size */
+ dsize = Ihdr.datsz;
+ lputl(dsize); /* data size */
+ lputl(0); /* sym size */
+
+ lputl(Ihdr.bsssz); /* bss size */
+ lputl(0); /* sym type */
+ lputl(Ihdr.txtaddr-hlen); /* text addr */
+ lputl(0); /* workspace - ignored */
+
+ lputl(32); /* addr mode / data addr flag */
+ lputl(0); /* data addr */
+ for(ii=0; ii<2; ii++)
+ lputl(0); /* reserved */
+
+ for(ii=0; ii<15; ii++)
+ lputl(0xe1a00000); /* NOP - zero init code */
+ lputl(0xe1a0f00e); /* B (R14) - zero init return */
+ break;
+
+ case 2: /* plan 9 */
+ hlen = 32;
+ doff = hlen + Ihdr.txtsz;
+ dsize = Ihdr.datsz;
+ lput(0x647); /* magic */
+ lput(Ihdr.txtsz); /* sizes */
+ lput(Ihdr.datsz);
+ lput(Ihdr.bsssz);
+ if (Strip) /* nsyms */
+ lput(0);
+ else
+ lput(Ihdr.symsz);
+ lput(Ihdr.entry); /* va of entry */
+ lput(0L);
+ lput(Ihdr.lnpcsz);
+ break;
+
+ case 3: /* boot for NetBSD */
+ hlen = 32;
+ doff = rnd(hlen+Ihdr.txtsz, 4096);
+ dsize = rnd(Ihdr.datsz, 4096);
+ lput((143<<16)|0413); /* magic */
+ lputl(doff);
+ lputl(dsize);
+ lputl(Ihdr.bsssz);
+ if (Strip) /* nsyms */
+ lputl(0);
+ else
+ lputl(Ihdr.symsz);
+ lputl(Ihdr.entry); /* va of entry */
+ lputl(0L);
+ lputl(0L);
+ break;
+ case 4: /* no header, stripped, padded to 2K, for serial bootstrap */
+ hlen = 0;
+ Strip = 1;
+ doff = hlen + Ihdr.txtsz;
+ dsize = Ihdr.datsz;
+ pad = 2048;
+ break;
+ case 5: /* no header, stripped, for all sorts */
+ hlen = 0;
+ Strip = 1;
+ doff = hlen + Ihdr.txtsz;
+ dsize = Ihdr.datsz;
+ break;
+ case 6: /* fake EPOC IMG format header */
+ hlen = 256;
+ *wp++ = 'E';
+ *wp++ = 'P';
+ Strip = 1;
+ doff = hlen + Ihdr.txtsz;
+ dsize = Ihdr.datsz;
+ break;
+ default:
+ Usage("Bad -Htype");
+ return;
+ }
+ write(Ofd, Wbuf, hlen);
+
+ seek(Ifd, Ihdr.txtoff, 0);
+ copyseg(Ihdr.txtsz);
+
+ seek(Ifd, Ihdr.datoff, 0);
+ seek(Ofd, doff, 0);
+ copyseg(Ihdr.datsz);
+
+ if (!Strip) {
+ /* Write symbols */
+ seek(Ofd, doff + dsize, 0);
+ if (Ihdr.symsz){
+ seek(Ifd, Ihdr.symoff, 0);
+ copyseg(Ihdr.symsz);
+ }
+ if (Hdrtype == 2)
+ copyseg(Ihdr.lnpcsz);
+ }
+
+ if (pad) {
+ if (doff + Ihdr.datsz > pad) {
+ perror("Too big!");
+ exits(fail);
+ }
+ else if (doff + Ihdr.datsz < pad)
+ zero(pad - (doff + Ihdr.datsz));
+ }
+}
diff --git a/utils/5cv/mkfile b/utils/5cv/mkfile
new file mode 100644
index 00000000..3b544bc6
--- /dev/null
+++ b/utils/5cv/mkfile
@@ -0,0 +1,18 @@
+<../../mkconfig
+
+TARG=5cv
+
+OFILES= 5cv.$O\
+
+HFILES=\
+ a.out.h\
+ bio.h\
+ mach.h\
+
+LIBS=mach bio 9 # order matters.
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/5l/Nt.c b/utils/5l/Nt.c
new file mode 100644
index 00000000..73c6f795
--- /dev/null
+++ b/utils/5l/Nt.c
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/5l/Plan9.c b/utils/5l/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/5l/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/5l/Posix.c b/utils/5l/Posix.c
new file mode 100644
index 00000000..0da0ee0c
--- /dev/null
+++ b/utils/5l/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fails if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
diff --git a/utils/5l/asm.c b/utils/5l/asm.c
new file mode 100644
index 00000000..fbb1397b
--- /dev/null
+++ b/utils/5l/asm.c
@@ -0,0 +1,1793 @@
+#include "l.h"
+
+long OFFSET;
+
+static Prog *PP;
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ switch(s->type) {
+ case STEXT:
+ case SLEAF:
+ break;
+ case SDATA:
+ if(dlm)
+ return s->value+INITDAT;
+ default:
+ diag("entry not text: %s", s->name);
+ }
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long t, etext;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asm\n", cputime());
+ Bflush(&bso);
+ OFFSET = HEADR;
+ seek(cout, OFFSET, 0);
+ pc = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ }
+ if(p->pc != pc) {
+ diag("phase error %lux sb %lux",
+ p->pc, pc);
+ if(!debug['a'])
+ prasm(curp);
+ pc = p->pc;
+ }
+ curp = p;
+ o = oplook(p); /* could probably avoid this call */
+ if(thumb)
+ thumbasmout(p, o);
+ else
+ asmout(p, o);
+ pc += o->size;
+ }
+ while(pc-INITTEXT < textsize) {
+ cput(0);
+ pc++;
+ }
+
+ if(debug['a'])
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ cflush();
+
+ /* output strings in text segment */
+ etext = INITTEXT + textsize;
+ for(t = pc; t < etext; t += sizeof(buf)-100) {
+ if(etext-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100, 1);
+ else
+ datblk(t, etext-t, 1);
+ }
+
+ curtext = P;
+ switch(HEADTYPE) {
+ case 0:
+ case 1:
+ case 2:
+ case 5:
+ OFFSET = HEADR+textsize;
+ seek(cout, OFFSET, 0);
+ break;
+ case 3:
+ OFFSET = rnd(HEADR+textsize, 4096);
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ if(dlm){
+ char buf[8];
+
+ write(cout, buf, INITDAT-textsize);
+ textsize = INITDAT;
+ }
+ for(t = 0; t < datsize; t += sizeof(buf)-100) {
+ if(datsize-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100, 0);
+ else
+ datblk(t, datsize-t, 0);
+ }
+ cflush();
+
+ symsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ case 0:
+ case 1:
+ case 4:
+ case 5:
+ debug['s'] = 1;
+ break;
+ case 2:
+ OFFSET = HEADR+textsize+datsize;
+ seek(cout, OFFSET, 0);
+ break;
+ case 3:
+ OFFSET += rnd(datsize, 4096);
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ if(!debug['s'])
+ asmthumbmap();
+ if(dlm)
+ asmdyn();
+ cflush();
+ }
+ else if(dlm){
+ seek(cout, HEADR+textsize+datsize, 0);
+ asmdyn();
+ cflush();
+ }
+
+ curtext = P;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f header\n", cputime());
+ Bflush(&bso);
+ OFFSET = 0;
+ seek(cout, OFFSET, 0);
+ switch(HEADTYPE) {
+ case 0: /* no header */
+ break;
+ case 1: /* aif for risc os */
+ lputl(0xe1a00000); /* NOP - decompress code */
+ lputl(0xe1a00000); /* NOP - relocation code */
+ lputl(0xeb000000 + 12); /* BL - zero init code */
+ lputl(0xeb000000 +
+ (entryvalue()
+ - INITTEXT
+ + HEADR
+ - 12
+ - 8) / 4); /* BL - entry code */
+
+ lputl(0xef000011); /* SWI - exit code */
+ lputl(textsize+HEADR); /* text size */
+ lputl(datsize); /* data size */
+ lputl(0); /* sym size */
+
+ lputl(bsssize); /* bss size */
+ lputl(0); /* sym type */
+ lputl(INITTEXT-HEADR); /* text addr */
+ lputl(0); /* workspace - ignored */
+
+ lputl(32); /* addr mode / data addr flag */
+ lputl(0); /* data addr */
+ for(t=0; t<2; t++)
+ lputl(0); /* reserved */
+
+ for(t=0; t<15; t++)
+ lputl(0xe1a00000); /* NOP - zero init code */
+ lputl(0xe1a0f00e); /* B (R14) - zero init return */
+ break;
+ case 2: /* plan 9 */
+ if(dlm)
+ lput(0x80000000|0x647); /* magic */
+ else
+ lput(0x647); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case 3: /* boot for NetBSD */
+ lput((143<<16)|0413); /* magic */
+ lputl(rnd(HEADR+textsize, 4096));
+ lputl(rnd(datsize, 4096));
+ lputl(bsssize);
+ lputl(symsize); /* nsyms */
+ lputl(entryvalue()); /* va of entry */
+ lputl(0L);
+ lputl(0L);
+ break;
+ case 4: /* boot for IXP1200 */
+ break;
+ case 5: /* boot for ipaq */
+ lputl(0xe3300000); /* nop */
+ lputl(0xe3300000); /* nop */
+ lputl(0xe3300000); /* nop */
+ lputl(0xe3300000); /* nop */
+ break;
+ }
+ cflush();
+ if(debug['c']){
+ print("textsize=%ld\n", textsize);
+ print("datsize=%ld\n", datsize);
+ print("bsssize=%ld\n", bsssize);
+ print("symsize=%ld\n", symsize);
+ print("lcsize=%ld\n", lcsize);
+ print("total=%ld\n", textsize+datsize+bsssize+symsize+lcsize);
+ }
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s; s++){
+ cput(*s);
+ n--;
+ }
+ for(; n > 0; n--)
+ cput(0);
+}
+
+void
+cput(int c)
+{
+ cbp[0] = c;
+ cbp++;
+ cbc--;
+ if(cbc <= 0)
+ cflush();
+}
+
+/*
+void
+cput(long c)
+{
+ *cbp++ = c;
+ if(--cbc <= 0)
+ cflush();
+}
+*/
+
+void
+wput(long l)
+{
+
+ cbp[0] = l>>8;
+ cbp[1] = l;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+hput(long l)
+{
+
+ cbp[0] = l>>8;
+ cbp[1] = l;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+lput(long l)
+{
+
+ cbp[0] = l>>24;
+ cbp[1] = l>>16;
+ cbp[2] = l>>8;
+ cbp[3] = l;
+ cbp += 4;
+ cbc -= 4;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+lputl(long l)
+{
+
+ cbp[3] = l>>24;
+ cbp[2] = l>>16;
+ cbp[1] = l>>8;
+ cbp[0] = l;
+ cbp += 4;
+ cbc -= 4;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ /* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+nopstat(char *f, Count *c)
+{
+ if(c->outof)
+ Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
+ c->outof - c->count, c->outof,
+ (double)(c->outof - c->count)/c->outof);
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SSTRING:
+ putsymb(s->name, 'T', s->value, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->cond) {
+ s = p->from.sym;
+ if(s->type != STEXT && s->type != SLEAF)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+ else
+ putsymb(s->name, 'L', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+4, 0);
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+putsymb(char *s, int t, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ lput(v);
+ if(ver)
+ t += 'a' - 'A';
+ cput(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ cput(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ cput(s[i]);
+ cput(s[i+1]);
+ }
+ cput(0);
+ cput(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ cput(s[i]);
+ cput(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, s);
+ }
+}
+
+#define MINLC 4
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ cput(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ cput(0); /* 0 vv +lc */
+ cput(s>>24);
+ cput(s>>16);
+ cput(s>>8);
+ cput(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ cput(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ cput(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ cput(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+static void
+outt(long f, long l)
+{
+ if(debug['L'])
+ Bprint(&bso, "tmap: %lux-%lux\n", f, l);
+ lput(f);
+ lput(l);
+}
+
+void
+asmthumbmap(void)
+{
+ long pc, lastt;
+ Prog *p;
+
+ if(!seenthumb)
+ return;
+ pc = 0;
+ lastt = -1;
+ for(p = firstp; p != P; p = p->link){
+ pc = p->pc - INITTEXT;
+ if(p->as == ATEXT){
+ setarch(p);
+ if(thumb){
+ if(p->from.sym->foreign){ // 8 bytes of ARM first
+ if(lastt >= 0){
+ outt(lastt, pc-1);
+ lastt = -1;
+ }
+ pc += 8;
+ }
+ if(lastt < 0)
+ lastt = pc;
+ }
+ else{
+ if(p->from.sym->foreign){ // 4 bytes of THUMB first
+ if(lastt < 0)
+ lastt = pc;
+ pc += 4;
+ }
+ if(lastt >= 0){
+ outt(lastt, pc-1);
+ lastt = -1;
+ }
+ }
+ }
+ }
+ if(lastt >= 0)
+ outt(lastt, pc+1);
+}
+
+void
+datblk(long s, long n, int str)
+{
+ Sym *v;
+ Prog *p;
+ char *cast;
+ long a, l, fl, j, d;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ if(str != (p->from.sym->type == SSTRING))
+ continue;
+ curp = p;
+ a = p->from.sym->value + p->from.offset;
+ l = a - s;
+ c = p->reg;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ default:
+ diag("unknown mode in initialization%P", p);
+ break;
+
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(p->to.ieee);
+ cast = (char*)&fl;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.sval[i];
+ l++;
+ }
+ break;
+
+ case D_CONST:
+ d = p->to.offset;
+ v = p->to.sym;
+ if(v) {
+ switch(v->type) {
+ case SUNDEF:
+ ckoff(v, d);
+ d += v->value;
+ break;
+ case STEXT:
+ case SLEAF:
+ d += v->value;
+#ifdef CALLEEBX
+ d += fnpinc(v);
+#else
+ if(v->thumb)
+ d++; // T bit
+#endif
+ break;
+ case SSTRING:
+ d += v->value;
+ break;
+ case SDATA:
+ case SBSS:
+ d += v->value + INITDAT;
+ break;
+ }
+ if(dlm)
+ dynreloc(v, a+INITDAT, 1);
+ }
+ cast = (char*)&d;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d%P", c, i, curp);
+ break;
+ case 1:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+void
+asmout(Prog *p, Optab *o)
+{
+ long o1, o2, o3, o4, o5, o6, v;
+ int r, rf, rt, rt2;
+ Sym *s;
+
+PP = p;
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ o6 = 0;
+ armsize += o->size;
+if(debug['P']) print("%ulx: %P type %d\n", (ulong)(p->pc), p, o->type);
+ switch(o->type) {
+ default:
+ diag("unknown asm %d", o->type);
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr, p->from.sym->used);
+ break;
+
+ case 1: /* op R,[R],R */
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 2: /* movbu $I,[R],R */
+ aclass(&p->from);
+ o1 = oprrr(p->as, p->scond);
+ o1 |= immrot(instoffset);
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 3: /* add R<<[IR],[R],R */
+ mov:
+ aclass(&p->from);
+ o1 = oprrr(p->as, p->scond);
+ o1 |= p->from.offset;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 4: /* add $I,[R],R */
+ aclass(&p->from);
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(instoffset);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 |= r << 16;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 5: /* bra s */
+ v = -8;
+ if(p->cond == UP) {
+ s = p->to.sym;
+ if(s->type != SUNDEF)
+ diag("bad branch sym type");
+ v = (ulong)s->value >> (Roffset-2);
+ dynreloc(s, p->pc, 0);
+ }
+ else if(p->cond != P)
+ v = (p->cond->pc - pc) - 8;
+#ifdef CALLEEBX
+ if(p->as == ABL)
+ v += fninc(p->to.sym);
+#endif
+ o1 = opbra(p->as, p->scond);
+ o1 |= (v >> 2) & 0xffffff;
+ break;
+
+ case 6: /* b ,O(R) -> add $O,R,PC */
+ aclass(&p->to);
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGPC << 12;
+ break;
+
+ case 7: /* bl ,O(R) -> mov PC,link; add $O,R,PC */
+ aclass(&p->to);
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(0);
+ o1 |= REGPC << 16;
+ o1 |= REGLINK << 12;
+
+ o2 = oprrr(AADD, p->scond);
+ o2 |= immrot(instoffset);
+ o2 |= p->to.reg << 16;
+ o2 |= REGPC << 12;
+ break;
+
+ case 8: /* sll $c,[R],R -> mov (R<<$c),R */
+ aclass(&p->from);
+ o1 = oprrr(p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (instoffset&31) << 7;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 9: /* sll R,[R],R -> mov (R<<R),R */
+ o1 = oprrr(p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (p->from.reg << 8) | (1<<4);
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 10: /* swi [$con] */
+ o1 = oprrr(p->as, p->scond);
+ if(p->to.type != D_NONE) {
+ aclass(&p->to);
+ o1 |= instoffset & 0xffffff;
+ }
+ break;
+
+ case 11: /* word */
+ switch(aclass(&p->to)) {
+ case C_LCON:
+ if(!dlm)
+ break;
+ if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
+ break;
+ case C_ADDR:
+ if(p->to.sym->type == SUNDEF)
+ ckoff(p->to.sym, p->to.offset);
+ dynreloc(p->to.sym, p->pc, 1);
+ }
+ o1 = instoffset;
+ break;
+
+ case 12: /* movw $lcon, reg */
+ o1 = omvl(p, &p->from, p->to.reg);
+ break;
+
+ case 13: /* op $lcon, [R], R */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = oprrr(p->as, p->scond);
+ o2 |= REGTMP;
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 14: /* movb/movbu/movh/movhu R,R */
+ o1 = oprrr(ASLL, p->scond);
+
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ o2 = oprrr(ASRL, p->scond);
+ else
+ o2 = oprrr(ASRA, p->scond);
+
+ r = p->to.reg;
+ o1 |= (p->from.reg)|(r<<12);
+ o2 |= (r)|(r<<12);
+ if(p->as == AMOVB || p->as == AMOVBU) {
+ o1 |= (24<<7);
+ o2 |= (24<<7);
+ } else {
+ o1 |= (16<<7);
+ o2 |= (16<<7);
+ }
+ break;
+
+ case 15: /* mul r,[r,]r */
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG)
+ r = rt;
+ if(rt == r) {
+ r = rf;
+ rf = rt;
+ }
+ if(0)
+ if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
+ diag("bad registers in MUL");
+ prasm(p);
+ }
+ o1 |= (rf<<8) | r | (rt<<16);
+ break;
+
+
+ case 16: /* div r,[r,]r */
+ o1 = 0xf << 28;
+ o2 = 0;
+ break;
+
+ case 17:
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ rt2 = p->to.offset;
+ r = p->reg;
+ o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
+ break;
+
+ case 20: /* mov/movb/movbu R,O(R) */
+ aclass(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
+ break;
+
+ case 21: /* mov/movbu O(R),R -> lr */
+ aclass(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olr(instoffset, r, p->to.reg, p->scond);
+ if(p->as != AMOVW)
+ o1 |= 1<<22;
+ break;
+
+ case 22: /* movb/movh/movhu O(R),R -> lr,shl,shr */
+ aclass(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olr(instoffset, r, p->to.reg, p->scond);
+
+ o2 = oprrr(ASLL, p->scond);
+ o3 = oprrr(ASRA, p->scond);
+ r = p->to.reg;
+ if(p->as == AMOVB) {
+ o2 |= (24<<7)|(r)|(r<<12);
+ o3 |= (24<<7)|(r)|(r<<12);
+ } else {
+ o2 |= (16<<7)|(r)|(r<<12);
+ if(p->as == AMOVHU)
+ o3 = oprrr(ASRL, p->scond);
+ o3 |= (16<<7)|(r)|(r<<12);
+ }
+ break;
+
+ case 23: /* movh/movhu R,O(R) -> sb,sb */
+ aclass(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond);
+
+ o2 = oprrr(ASRL, p->scond);
+ o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12);
+
+ o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond);
+ break;
+
+ case 30: /* mov/movb/movbu R,L(R) */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = osrr(p->from.reg, REGTMP,r, p->scond);
+ if(p->as != AMOVW)
+ o2 |= 1<<22;
+ break;
+
+ case 31: /* mov/movbu L(R),R -> lr[b] */
+ case 32: /* movh/movb L(R),R -> lr[b] */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olrr(REGTMP,r, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVB)
+ o2 |= 1<<22;
+ if(o->type == 31)
+ break;
+
+ o3 = oprrr(ASLL, p->scond);
+
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ o4 = oprrr(ASRL, p->scond);
+ else
+ o4 = oprrr(ASRA, p->scond);
+
+ r = p->to.reg;
+ o3 |= (r)|(r<<12);
+ o4 |= (r)|(r<<12);
+ if(p->as == AMOVB || p->as == AMOVBU) {
+ o3 |= (24<<7);
+ o4 |= (24<<7);
+ } else {
+ o3 |= (16<<7);
+ o4 |= (16<<7);
+ }
+ break;
+
+ case 33: /* movh/movhu R,L(R) -> sb, sb */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = osrr(p->from.reg, REGTMP, r, p->scond);
+ o2 |= (1<<22) ;
+
+ o3 = oprrr(ASRL, p->scond);
+ o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
+ o3 |= (1<<6); /* ROR 8 */
+
+ o4 = oprrr(AADD, p->scond);
+ o4 |= (REGTMP << 12) | (REGTMP << 16);
+ o4 |= immrot(1);
+
+ o5 = osrr(p->from.reg, REGTMP,r,p->scond);
+ o5 |= (1<<22);
+
+ o6 = oprrr(ASRL, p->scond);
+ o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
+ o6 |= (1<<6); /* ROL 8 */
+
+ break;
+
+ case 34: /* mov $lacon,R */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+
+ o2 = oprrr(AADD, p->scond);
+ o2 |= REGTMP;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 35: /* mov PSR,R */
+ o1 = (2<<23) | (0xf<<16) | (0<<0);
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->from.reg & 1) << 22;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 36: /* mov R,PSR */
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 37: /* mov $con,PSR */
+ aclass(&p->from);
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= immrot(instoffset);
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 38: /* movm $con,oreg -> stm */
+ o1 = (0x4 << 25);
+ o1 |= p->from.offset & 0xffff;
+ o1 |= p->to.reg << 16;
+ aclass(&p->to);
+ goto movm;
+
+ case 39: /* movm oreg,$con -> ldm */
+ o1 = (0x4 << 25) | (1 << 20);
+ o1 |= p->to.offset & 0xffff;
+ o1 |= p->from.reg << 16;
+ aclass(&p->from);
+ movm:
+ if(instoffset != 0)
+ diag("offset must be zero in MOVM");
+ o1 |= (p->scond & C_SCOND) << 28;
+ if(p->scond & C_PBIT)
+ o1 |= 1 << 24;
+ if(p->scond & C_UBIT)
+ o1 |= 1 << 23;
+ if(p->scond & C_SBIT)
+ o1 |= 1 << 22;
+ if(p->scond & C_WBIT)
+ o1 |= 1 << 21;
+ break;
+
+ case 40: /* swp oreg,reg,reg */
+ aclass(&p->from);
+ if(instoffset != 0)
+ diag("offset must be zero in SWP");
+ o1 = (0x2<<23) | (0x9<<4);
+ if(p->as != ASWPW)
+ o1 |= 1 << 22;
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+
+ case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
+ o1 = 0xe8fd8000;
+ break;
+
+ case 50: /* floating point store */
+ v = regoff(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
+ break;
+
+ case 51: /* floating point load */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
+ break;
+
+ case 52: /* floating point store, long offset UGLY */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ break;
+
+ case 53: /* floating point load, long offset UGLY */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ break;
+
+ case 54: /* floating point arith */
+ o1 = oprrr(p->as, p->scond);
+ if(p->from.type == D_FCONST) {
+ rf = chipfloat(p->from.ieee);
+ if(rf < 0){
+ diag("invalid floating-point immediate\n%P", p);
+ rf = 0;
+ }
+ rf |= (1<<3);
+ } else
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0; /* CMP[FD] */
+ else if(o1 & (1<<15))
+ r = 0; /* monadic */
+ else if(r == NREG)
+ r = rt;
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 55: /* floating point fix and float */
+ o1 = oprrr(p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ if(p->to.type == D_NONE){
+ rt = 0;
+ diag("to.type==D_NONE (asm/fp)");
+ }
+ if(p->from.type == D_REG)
+ o1 |= (rf<<12) | (rt<<16);
+ else
+ o1 |= rf | (rt<<12);
+ break;
+
+ case 56: /* move to FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
+ break;
+
+ case 57: /* move from FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
+ break;
+ case 58: /* movbu R,R */
+ o1 = oprrr(AAND, p->scond);
+ o1 |= immrot(0xff);
+ rt = p->to.reg;
+ r = p->from.reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 59: /* movw/bu R<<I(R),R -> ldr indexed */
+ if(p->from.reg == NREG) {
+ if(p->as != AMOVW)
+ diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(1<<4))
+ diag("bad shift in LDR");
+ o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
+ if(p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 60: /* movb R(R),R -> ldrsb indexed */
+ if(p->from.reg == NREG) {
+ diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(~0xf))
+ diag("bad shift in LDRSB");
+ o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
+ o1 ^= (1<<5)|(1<<6);
+ break;
+
+ case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
+ if(p->to.reg == NREG)
+ diag("MOV to shifter operand");
+ o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 62: /* case R -> movw R<<2(PC),PC */
+ o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
+ o1 |= 2<<7;
+ break;
+
+ case 63: /* bcase */
+ if(p->cond != P) {
+ o1 = p->cond->pc;
+ if(dlm)
+ dynreloc(S, p->pc, 1);
+ }
+ break;
+
+ /* reloc ops */
+ case 64: /* mov/movb/movbu R,addr */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
+ break;
+
+ case 65: /* mov/movbu addr,R */
+ case 66: /* movh/movhu/movb addr,R */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olr(0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVB)
+ o2 |= 1<<22;
+ if(o->type == 65)
+ break;
+
+ o3 = oprrr(ASLL, p->scond);
+
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ o4 = oprrr(ASRL, p->scond);
+ else
+ o4 = oprrr(ASRA, p->scond);
+
+ r = p->to.reg;
+ o3 |= (r)|(r<<12);
+ o4 |= (r)|(r<<12);
+ if(p->as == AMOVB || p->as == AMOVBU) {
+ o3 |= (24<<7);
+ o4 |= (24<<7);
+ } else {
+ o3 |= (16<<7);
+ o4 |= (16<<7);
+ }
+ break;
+
+ case 67: /* movh/movhu R,addr -> sb, sb */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
+
+ o3 = oprrr(ASRL, p->scond);
+ o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
+ o3 |= (1<<6); /* ROR 8 */
+
+ o4 = oprrr(AADD, p->scond);
+ o4 |= (REGTMP << 12) | (REGTMP << 16);
+ o4 |= immrot(1);
+
+ o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
+
+ o6 = oprrr(ASRL, p->scond);
+ o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
+ o6 |= (1<<6); /* ROL 8 */
+ break;
+
+ case 68: /* floating point store -> ADDR */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ break;
+
+ case 69: /* floating point load <- ADDR */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ break;
+
+ /* ArmV4 ops: */
+ case 70: /* movh/movhu R,O(R) -> strh */
+ aclass(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = oshr(p->from.reg, instoffset, r, p->scond);
+ break;
+ case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
+ aclass(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olhr(instoffset, r, p->to.reg, p->scond);
+ if(p->as == AMOVB)
+ o1 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH)
+ o1 ^= (1<<6);
+ break;
+ case 72: /* movh/movhu R,L(R) -> strh */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
+ break;
+ case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
+ if(p->as == AMOVB)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH)
+ o2 ^= (1<<6);
+ break;
+ case 74: /* bx $I */
+#ifdef CALLEEBX
+ diag("bx $i case (arm)");
+#endif
+ if(!seenthumb)
+ diag("ABX $I and seenthumb==0");
+ v = p->cond->pc;
+ if(p->to.sym->thumb)
+ v |= 1; // T bit
+ o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp
+ o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
+ o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp
+ o4 = opbra(AB, 14); // B over o6
+ o5 = v;
+ break;
+ case 75: /* bx O(R) */
+ aclass(&p->to);
+ if(instoffset != 0)
+ diag("non-zero offset in ABX");
+/*
+ o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+*/
+ // p->to.reg may be REGLINK
+ o1 = oprrr(AADD, p->scond);
+ o1 |= immrot(instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGTMP << 12;
+ o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
+ break;
+ case 76: /* bx O(R) when returning from fn*/
+ if(!seenthumb)
+ diag("ABXRET and seenthumb==0");
+ aclass(&p->to);
+// print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg);
+ if(instoffset != 0)
+ diag("non-zero offset in ABXRET");
+ // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp
+ o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+ break;
+ }
+
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ lputl(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ lputl(o1);
+ lputl(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ break;
+ case 24:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, o6, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ lputl(o6);
+ break;
+ }
+}
+
+long
+oprrr(int a, int sc)
+{
+ long o;
+
+ o = (sc & C_SCOND) << 28;
+ if(sc & C_SBIT)
+ o |= 1 << 20;
+ if(sc & (C_PBIT|C_WBIT))
+ diag(".P/.W on dp instruction");
+ switch(a) {
+ case AMULU:
+ case AMUL: return o | (0x0<<21) | (0x9<<4);
+ case AMULA: return o | (0x1<<21) | (0x9<<4);
+ case AMULLU: return o | (0x4<<21) | (0x9<<4);
+ case AMULL: return o | (0x6<<21) | (0x9<<4);
+ case AMULALU: return o | (0x5<<21) | (0x9<<4);
+ case AMULAL: return o | (0x7<<21) | (0x9<<4);
+ case AAND: return o | (0x0<<21);
+ case AEOR: return o | (0x1<<21);
+ case ASUB: return o | (0x2<<21);
+ case ARSB: return o | (0x3<<21);
+ case AADD: return o | (0x4<<21);
+ case AADC: return o | (0x5<<21);
+ case ASBC: return o | (0x6<<21);
+ case ARSC: return o | (0x7<<21);
+ case ATST: return o | (0x8<<21) | (1<<20);
+ case ATEQ: return o | (0x9<<21) | (1<<20);
+ case ACMP: return o | (0xa<<21) | (1<<20);
+ case ACMN: return o | (0xb<<21) | (1<<20);
+ case AORR: return o | (0xc<<21);
+ case AMOVW: return o | (0xd<<21);
+ case ABIC: return o | (0xe<<21);
+ case AMVN: return o | (0xf<<21);
+ case ASLL: return o | (0xd<<21) | (0<<5);
+ case ASRL: return o | (0xd<<21) | (1<<5);
+ case ASRA: return o | (0xd<<21) | (2<<5);
+ case ASWI: return o | (0xf<<24);
+
+ case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
+ case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8);
+ case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
+ case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8);
+ case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
+ case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8);
+ case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
+ case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8);
+ case ACMPD:
+ case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */
+
+ case AMOVF:
+ case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
+ case AMOVD:
+ case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
+
+ case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
+ case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
+ case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
+ case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
+ }
+ diag("bad rrr %d", a);
+ prasm(curp);
+ return 0;
+}
+
+long
+opbra(int a, int sc)
+{
+
+ if(sc & (C_SBIT|C_PBIT|C_WBIT))
+ diag(".S/.P/.W on bra instruction");
+ sc &= C_SCOND;
+ if(a == ABL)
+ return (sc<<28)|(0x5<<25)|(0x1<<24);
+ if(sc != 0xe)
+ diag(".COND on bcond instruction");
+ switch(a) {
+ case ABEQ: return (0x0<<28)|(0x5<<25);
+ case ABNE: return (0x1<<28)|(0x5<<25);
+ case ABCS: return (0x2<<28)|(0x5<<25);
+ case ABHS: return (0x2<<28)|(0x5<<25);
+ case ABCC: return (0x3<<28)|(0x5<<25);
+ case ABLO: return (0x3<<28)|(0x5<<25);
+ case ABMI: return (0x4<<28)|(0x5<<25);
+ case ABPL: return (0x5<<28)|(0x5<<25);
+ case ABVS: return (0x6<<28)|(0x5<<25);
+ case ABVC: return (0x7<<28)|(0x5<<25);
+ case ABHI: return (0x8<<28)|(0x5<<25);
+ case ABLS: return (0x9<<28)|(0x5<<25);
+ case ABGE: return (0xa<<28)|(0x5<<25);
+ case ABLT: return (0xb<<28)|(0x5<<25);
+ case ABGT: return (0xc<<28)|(0x5<<25);
+ case ABLE: return (0xd<<28)|(0x5<<25);
+ case AB: return (0xe<<28)|(0x5<<25);
+ }
+ diag("bad bra %A", a);
+ prasm(curp);
+ return 0;
+}
+
+long
+olr(long v, int b, int r, int sc)
+{
+ long o;
+
+ if(sc & C_SBIT)
+ diag(".S on LDR/STR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(!(sc & C_UBIT))
+ o |= 1 << 23;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (0x1<<26) | (1<<20);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v >= (1<<12))
+ diag("literal span too large: %d (R%d)\n%P", v, b, PP);
+ o |= v;
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+long
+olhr(long v, int b, int r, int sc)
+{
+ long o;
+
+ if(sc & C_SBIT)
+ diag(".S on LDRH/STRH instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (1<<23) | (1<<20)|(0xb<<4);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v >= (1<<8))
+ diag("literal span too large: %d (R%d)\n%P", v, b, PP);
+ o |= (v&0xf)|((v>>4)<<8)|(1<<22);
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+long
+osr(int a, int r, long v, int b, int sc)
+{
+ long o;
+
+ o = olr(v, b, r, sc) ^ (1<<20);
+ if(a != AMOVW)
+ o |= 1<<22;
+ return o;
+}
+
+long
+oshr(int r, long v, int b, int sc)
+{
+ long o;
+
+ o = olhr(v, b, r, sc) ^ (1<<20);
+ return o;
+}
+
+
+long
+osrr(int r, int i, int b, int sc)
+{
+
+ return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
+}
+
+long
+oshrr(int r, int i, int b, int sc)
+{
+ return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
+}
+
+long
+olrr(int i, int b, int r, int sc)
+{
+
+ return olr(i, b, r, sc) ^ (1<<25);
+}
+
+long
+olhrr(int i, int b, int r, int sc)
+{
+ return olhr(i, b, r, sc) ^ (1<<22);
+}
+
+long
+ofsr(int a, int r, long v, int b, int sc, Prog *p)
+{
+ long o;
+
+ if(sc & C_SBIT)
+ diag(".S on FLDR/FSTR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (6<<25) | (1<<24) | (1<<23);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v & 3)
+ diag("odd offset for floating point op: %d\n%P", v, p);
+ else if(v >= (1<<10))
+ diag("literal span too large: %d\n%P", v, p);
+ o |= (v>>2) & 0xFF;
+ o |= b << 16;
+ o |= r << 12;
+ o |= 1 << 8;
+
+ switch(a) {
+ default:
+ diag("bad fst %A", a);
+ case AMOVD:
+ o |= 1<<15;
+ case AMOVF:
+ break;
+ }
+ return o;
+}
+
+long
+omvl(Prog *p, Adr *a, int dr)
+{
+ long v, o1;
+ if(!p->cond) {
+ aclass(a);
+ v = immrot(~instoffset);
+ if(v == 0) {
+ diag("missing literal");
+ prasm(p);
+ return 0;
+ }
+ o1 = oprrr(AMVN, p->scond&C_SCOND);
+ o1 |= v;
+ o1 |= dr << 12;
+ } else {
+ v = p->cond->pc - p->pc - 8;
+ o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
+ }
+ return o1;
+}
+
+static Ieee chipfloats[] = {
+ {0x00000000, 0x00000000}, /* 0 */
+ {0x00000000, 0x3ff00000}, /* 1 */
+ {0x00000000, 0x40000000}, /* 2 */
+ {0x00000000, 0x40080000}, /* 3 */
+ {0x00000000, 0x40100000}, /* 4 */
+ {0x00000000, 0x40140000}, /* 5 */
+ {0x00000000, 0x3fe00000}, /* .5 */
+ {0x00000000, 0x40240000}, /* 10 */
+};
+
+int
+chipfloat(Ieee *e)
+{
+ Ieee *p;
+ int n;
+
+ for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
+ p = &chipfloats[n];
+ if(p->l == e->l && p->h == e->h)
+ return n;
+ }
+ return -1;
+}
diff --git a/utils/5l/l.h b/utils/5l/l.h
new file mode 100644
index 00000000..a7c322be
--- /dev/null
+++ b/utils/5l/l.h
@@ -0,0 +1,444 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../5c/5.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/* do not undefine this - code will be removed eventually */
+#define CALLEEBX
+
+typedef struct Adr Adr;
+typedef struct Sym Sym;
+typedef struct Autom Auto;
+typedef struct Prog Prog;
+typedef struct Optab Optab;
+typedef struct Oprang Oprang;
+typedef uchar Opcross[32][2][32];
+typedef struct Count Count;
+typedef struct Use Use;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define U ((Use*)0)
+#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ long u0offset;
+ char* u0sval;
+ Ieee* u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ char type;
+ char reg;
+ char name;
+ char class;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0regused;
+ Prog* u0forwd;
+ } u0;
+ Prog* cond;
+ Prog* link;
+ long pc;
+ long line;
+ uchar mark;
+ uchar optab;
+ uchar as;
+ uchar scond;
+ uchar reg;
+ uchar align;
+};
+#define regused u0.u0regused
+#define forwd u0.u0forwd
+
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ uchar subtype;
+ ushort file;
+ long value;
+ long sig;
+ uchar used;
+ uchar thumb; // thumb code
+ uchar foreign; // called by arm if thumb, by thumb if arm
+ uchar fnptr; // used as fn ptr
+ Use* use;
+ Sym* link;
+};
+
+#define SIGNINTERN (1729*325*1729)
+
+struct Autom
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Optab
+{
+ char as;
+ char a1;
+ char a2;
+ char a3;
+ char type;
+ char size;
+ char param;
+ char flag;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+struct Count
+{
+ long count;
+ long outof;
+};
+struct Use
+{
+ Prog* p; /* use */
+ Prog* ct; /* curtext */
+ Use* link;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SLEAF,
+ SFILE,
+ SCONST,
+ SSTRING,
+ SUNDEF,
+ SREMOVED,
+
+ SIMPORT,
+ SEXPORT,
+
+ LFROM = 1<<0,
+ LTO = 1<<1,
+ LPOOL = 1<<2,
+ V4 = 1<<3, /* arm v4 arch */
+
+ C_NONE = 0,
+ C_REG,
+ C_REGREG,
+ C_SHIFT,
+ C_FREG,
+ C_PSR,
+ C_FCR,
+
+ C_RCON, /* 0xff rotated */
+ C_NCON, /* ~RCON */
+ C_SCON, /* 0xffff */
+ C_BCON, /* thumb */
+ C_LCON,
+ C_FCON,
+ C_GCON, /* thumb */
+
+ C_RACON,
+ C_SACON, /* thumb */
+ C_LACON,
+ C_GACON, /* thumb */
+
+ C_RECON,
+ C_LECON,
+
+ C_SBRA,
+ C_LBRA,
+ C_GBRA, /* thumb */
+
+ C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
+ C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
+ C_HFAUTO, /* both H and F */
+ C_SAUTO, /* -0xfff to 0xfff */
+ C_LAUTO,
+
+ C_HEXT,
+ C_FEXT,
+ C_HFEXT,
+ C_SEXT,
+ C_LEXT,
+
+ C_HOREG,
+ C_FOREG,
+ C_HFOREG,
+ C_SOREG,
+ C_ROREG,
+ C_SROREG, /* both S and R */
+ C_LOREG,
+ C_GOREG, /* thumb */
+
+ C_PC,
+ C_SP,
+ C_HREG,
+ C_OFFPC, /* thumb */
+
+ C_ADDR, /* relocatable address */
+
+ C_GOK,
+
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+
+ BIG = (1<<12)-4,
+ STRINGSZ = 200,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+
+ Roffset = 22, /* no. bits for offset in relocation address */
+ Rindex = 10, /* no. bits for index in relocation address */
+};
+
+EXTERN union
+{
+ struct
+ {
+ uchar obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+#define setarch(p) if((p)->as==ATEXT) thumb=(p)->reg&ALLTHUMBS
+#define setthumb(p) if((p)->as==ATEXT) seenthumb|=(p)->reg&ALLTHUMBS
+
+#ifndef COFFCVT
+
+EXTERN long HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN long INITDAT; /* data location */
+EXTERN long INITRND; /* data round above text location */
+EXTERN long INITTEXT; /* text location */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN long autosize;
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN uchar* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi4[4];
+EXTERN char fnuxi8[8];
+EXTERN char* noname;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long instoffset;
+EXTERN Opcross opcross[8];
+EXTERN Oprang oprange[ALAST];
+EXTERN Oprang thumboprange[ALAST];
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN uchar repop[ALAST];
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN char xcmp[C_GOK+1][C_GOK+1];
+EXTERN Prog zprg;
+EXTERN int dtype;
+EXTERN int armv4;
+EXTERN int thumb;
+EXTERN int seenthumb;
+EXTERN int armsize;
+
+EXTERN int doexp, dlm;
+EXTERN int imports, nimports;
+EXTERN int exports, nexports;
+EXTERN char* EXPTAB;
+EXTERN Prog undefp;
+
+#define UP (&undefp)
+
+extern char* anames[];
+extern Optab optab[];
+extern Optab thumboptab[];
+
+void addpool(Prog*, Adr*);
+EXTERN Prog* blitrl;
+EXTERN Prog* elitrl;
+
+void initdiv(void);
+EXTERN Prog* prog_div;
+EXTERN Prog* prog_divu;
+EXTERN Prog* prog_mod;
+EXTERN Prog* prog_modu;
+
+#pragma varargck type "A" int
+#pragma varargck type "C" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+
+int Aconv(Fmt*);
+int Cconv(Fmt*);
+int Dconv(Fmt*);
+int Nconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int aclass(Adr*);
+int thumbaclass(Adr*, Prog*);
+void addhist(long, int);
+void append(Prog*, Prog*);
+void asmb(void);
+void asmdyn(void);
+void asmlc(void);
+void asmthumbmap(void);
+void asmout(Prog*, Optab*);
+void thumbasmout(Prog*, Optab*);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void thumbbuildop(void);
+void buildrep(int, int);
+void cflush(void);
+void ckoff(Sym*, long);
+int chipfloat(Ieee*);
+int cmp(int, int);
+int compound(Prog*);
+double cputime(void);
+void datblk(long, long, int);
+void diag(char*, ...);
+void divsig(void);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+void dynreloc(Sym*, long, int);
+long entryvalue(void);
+void errorexit(void);
+void exchange(Prog*);
+void export(void);
+int find1(long, int);
+void follow(void);
+void gethunk(void);
+void histtoauto(void);
+void hputl(int);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void import(void);
+int isnop(Prog*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void cput(int);
+void hput(long);
+void lput(long);
+void lputl(long);
+void mkfwd(void);
+void* mysbrk(ulong);
+void names(void);
+void nocache(Prog*);
+void nuxiinit(void);
+void objfile(char*);
+int ocmp(const void*, const void*);
+long opirr(int);
+Optab* oplook(Prog*);
+long oprrr(int, int);
+long olr(long, int, int, int);
+long olhr(long, int, int, int);
+long olrr(int, int, int, int);
+long olhrr(int, int, int, int);
+long osr(int, int, long, int, int);
+long oshr(int, long, int, int);
+long ofsr(int, int, long, int, int, Prog*);
+long osrr(int, int, int, int);
+long oshrr(int, int, int, int);
+long omvl(Prog*, Adr*, int);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+void putsymb(char*, int, long, int);
+void readundefs(char*, int);
+long regoff(Adr*);
+int relinv(int);
+long rnd(long, long);
+void span(void);
+void strnput(char*, int);
+void undef(void);
+void undefsym(Sym*);
+void wput(long);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+void zerosig(char*);
+void noops(void);
+long immrot(ulong);
+long immaddr(long);
+long opbra(int, int);
+int brextra(Prog*);
+int isbranch(Prog*);
+int fnpinc(Sym *);
+int fninc(Sym *);
+void thumbcount(void);
+void reachable(void);
+void fnptrs(void);
+
+#endif
diff --git a/utils/5l/list.c b/utils/5l/list.c
new file mode 100644
index 00000000..5d2e7b49
--- /dev/null
+++ b/utils/5l/list.c
@@ -0,0 +1,360 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('C', Cconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ switch(a) {
+ default:
+ s = str;
+ s += sprint(s, "(%ld)", p->line);
+ if(p->reg == NREG)
+ sprint(s, " %A%C %D,%D",
+ a, p->scond, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(s, " %A%C %D,R%d,%D",
+ a, p->scond, &p->from, p->reg, &p->to);
+ else
+ sprint(s, " %A%C %D,F%d,%D",
+ a, p->scond, &p->from, p->reg, &p->to);
+ break;
+
+ case ASWPW:
+ case ASWPBU:
+ sprint(str, "(%ld) %A%C R%d,%D,%D",
+ p->line, a, p->scond, p->reg, &p->from, &p->to);
+ break;
+
+ case ADATA:
+ case AINIT:
+ case ADYNT:
+ sprint(str, "(%ld) %A%C %D/%d,%D",
+ p->line, a, p->scond, &p->from, p->reg, &p->to);
+ break;
+
+ case AWORD:
+ sprint(str, "WORD %ld", p->to.offset);
+ break;
+
+ case ADWORD:
+ sprint(str, "DWORD %ld %ld", p->from.offset, p->to.offset);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+char* strcond[16] =
+{
+ ".EQ",
+ ".NE",
+ ".HS",
+ ".LO",
+ ".MI",
+ ".PL",
+ ".VS",
+ ".VC",
+ ".HI",
+ ".LS",
+ ".GE",
+ ".LT",
+ ".GT",
+ ".LE",
+ "",
+ ".NV"
+};
+
+int
+Cconv(Fmt *fp)
+{
+ char s[20];
+ int c;
+
+ c = va_arg(fp->args, int);
+ strcpy(s, strcond[c & C_SCOND]);
+ if(c & C_SBIT)
+ strcat(s, ".S");
+ if(c & C_PBIT)
+ strcat(s, ".P");
+ if(c & C_WBIT)
+ strcat(s, ".W");
+ if(c & C_UBIT) /* ambiguous with FBIT */
+ strcat(s, ".U");
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ char *op;
+ Adr *a;
+ long v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg == NREG)
+ sprint(str, "$%N", a);
+ else
+ sprint(str, "$%N(R%d)", a, a->reg);
+ break;
+
+ case D_SHIFT:
+ v = a->offset;
+ op = "<<>>->@>" + (((v>>5) & 3) << 1);
+ if(v & (1<<4))
+ sprint(str, "R%ld%c%cR%ld", v&15, op[0], op[1], (v>>8)&15);
+ else
+ sprint(str, "R%ld%c%c%ld", v&15, op[0], op[1], (v>>7)&31);
+ if(a->reg != NREG)
+ sprint(str+strlen(str), "(R%d)", a->reg);
+ break;
+
+ case D_OCONST:
+ sprint(str, "$*$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_REGREG:
+ sprint(str, "(R%d,R%d)", a->reg, (int)a->offset);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ switch(a->reg) {
+ case 0:
+ sprint(str, "CPSR");
+ break;
+ case 1:
+ sprint(str, "SPSR");
+ break;
+ default:
+ sprint(str, "PSR%d", a->reg);
+ break;
+ }
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(PSR%d)(REG)", a, a->reg);
+ break;
+
+ case D_FPCR:
+ switch(a->reg){
+ case 0:
+ sprint(str, "FPSR");
+ break;
+ case 1:
+ sprint(str, "FPCR");
+ break;
+ default:
+ sprint(str, "FCR%d", a->reg);
+ break;
+ }
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(FCR%d)(REG)", a, a->reg);
+
+ break;
+
+ case D_BRANCH: /* botch */
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(a->sym != S)
+ sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5lux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%ld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%e", ieeedtod(a->ieee));
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(s == S)
+ sprint(str, "%ld(SB)", a->offset);
+ else
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ if(s == S)
+ sprint(str, "<>+%ld(SB)", a->offset);
+ else
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ if(s == S)
+ sprint(str, "%ld(SP)", a->offset);
+ else
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ if(s == S)
+ sprint(str, "%ld(FP)", a->offset);
+ else
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(long); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/5l/mkfile b/utils/5l/mkfile
new file mode 100644
index 00000000..4be81d08
--- /dev/null
+++ b/utils/5l/mkfile
@@ -0,0 +1,32 @@
+<../../mkconfig
+
+TARG=5l
+
+OFILES=\
+ asm.$O\
+ list.$O\
+ noop.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+ thumb.$O\
+
+HFILES=\
+ l.h\
+ ../5c/5.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9 # order is important
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+enam.$O: ../5c/enam.c
+ $CC $CFLAGS ../5c/enam.c
+
diff --git a/utils/5l/noop.c b/utils/5l/noop.c
new file mode 100644
index 00000000..08ef6dbe
--- /dev/null
+++ b/utils/5l/noop.c
@@ -0,0 +1,894 @@
+#include "l.h"
+
+static Sym* sym_div;
+static Sym* sym_divu;
+static Sym* sym_mod;
+static Sym* sym_modu;
+
+static void setdiv(int);
+
+static Prog *
+movrr(Prog *q, int rs, int rd, Prog *p)
+{
+ if(q == nil)
+ q = prg();
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = rs;
+ q->to.type = D_REG;
+ q->to.reg = rd;
+ q->link = p->link;
+ return q;
+}
+
+static Prog *
+fnret(Prog *q, int rs, int foreign, Prog *p)
+{
+ q = movrr(q, rs, REGPC, p);
+ if(foreign){ // BX rs
+ q->as = ABXRET;
+ q->from.type = D_NONE;
+ q->from.reg = NREG;
+ q->to.reg = rs;
+ }
+ return q;
+}
+
+static Prog *
+aword(long w, Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = AWORD;
+ q->line = p->line;
+ q->from.type = D_NONE;
+ q->reg = NREG;
+ q->to.type = D_CONST;
+ q->to.offset = w;
+ q->link = p->link;
+ p->link = q;
+ return q;
+}
+
+static Prog *
+adword(long w1, long w2, Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = ADWORD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = w1;
+ q->reg = NREG;
+ q->to.type = D_CONST;
+ q->to.offset = w2;
+ q->link = p->link;
+ p->link = q;
+ return q;
+}
+
+void
+noops(void)
+{
+ Prog *p, *q, *q1, *q2;
+ int o, curframe, curbecome, maxbecome, foreign;
+
+ /*
+ * find leaf subroutines
+ * become sizes
+ * frame sizes
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+
+ q = P;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == D_OREG && p->to.reg == REGSP)
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ p->mark |= LEAF;
+ curtext = p;
+ break;
+
+ case ARET:
+ /* special form of RET is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ q = p;
+ if(prog_div == P)
+ initdiv();
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+ setdiv(p->as);
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ case ABL:
+ case ABX:
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+
+ case ABCASE:
+ case AB:
+
+ case ABEQ:
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
+ }
+ }
+ break;
+ }
+ q = p;
+ }
+
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+ case ABL:
+ // case ABX:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ o = maxbecome - curtext->from.sym->frame;
+ if(o <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += o;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, o);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(autosize <= 4)
+ if(curtext->mark & LEAF) {
+ p->to.offset = -4;
+ autosize = 0;
+ }
+
+ if(!autosize && !(curtext->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ curtext->from.sym->name);
+ Bflush(&bso);
+ curtext->mark |= LEAF;
+ }
+#ifdef CALLEEBX
+ if(p->from.sym->foreign){
+ if(thumb)
+ // don't allow literal pool to seperate these
+ p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
+ // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
+ else
+ p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
+ }
+#endif
+ if(curtext->mark & LEAF) {
+ if(curtext->from.sym)
+ curtext->from.sym->type = SLEAF;
+#ifdef optimise_time
+ if(autosize) {
+ q = prg();
+ q->as = ASUB;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+ break;
+#else
+ if(!autosize)
+ break;
+#endif
+ }
+
+ if(thumb){
+ if(!(curtext->mark & LEAF)){
+ q = movrr(nil, REGLINK, REGTMPT-1, p);
+ p->link = q;
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMPT-1;
+ q1->to.type = D_OREG;
+ q1->to.name = D_NONE;
+ q1->to.reg = REGSP;
+ q1->to.offset = 0;
+ q1->link = q->link;
+ q->link = q1;
+ }
+ if(autosize){
+ q2 = prg();
+ q2->as = ASUB;
+ q2->line = p->line;
+ q2->from.type = D_CONST;
+ q2->from.offset = autosize;
+ q2->to.type = D_REG;
+ q2->to.reg = REGSP;
+ q2->link = p->link;
+ p->link = q2;
+ }
+ break;
+ }
+
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->scond |= C_WBIT;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGLINK;
+ q1->to.type = D_OREG;
+ q1->to.offset = -autosize;
+ q1->to.reg = REGSP;
+ q1->link = p->link;
+ p->link = q1;
+ break;
+
+ case ARET:
+ nocache(p);
+ foreign = seenthumb && curtext->from.sym != S && (curtext->from.sym->foreign || curtext->from.sym->fnptr);
+// print("%s %d %d\n", curtext->from.sym->name, curtext->from.sym->foreign, curtext->from.sym->fnptr);
+ if(p->from.type == D_CONST)
+ goto become;
+ if(curtext->mark & LEAF) {
+ if(!autosize) {
+ if(thumb){
+ p = fnret(p, REGLINK, foreign, p);
+ break;
+ }
+// if(foreign) print("ABXRET 1 %s\n", curtext->from.sym->name);
+ p->as = foreign ? ABXRET : AB;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ break;
+ }
+
+#ifdef optimise_time
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ if(thumb){
+ p->link = fnret(nil, REGLINK, foreign, p);
+ break;
+ }
+ q = prg();
+// if(foreign) print("ABXRET 2 %s\n", curtext->from.sym->name);
+ q->as = foreign ? ABXRET : AB;
+ q->scond = p->scond;
+ q->line = p->line;
+ q->to.type = D_OREG;
+ q->to.offset = 0;
+ q->to.reg = REGLINK;
+
+ q->link = p->link;
+ p->link = q;
+
+ break;
+#endif
+ }
+ if(thumb){
+ if(curtext->mark & LEAF){
+ if(autosize){
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ q = nil;
+ }
+ else
+ q = p;
+ q = fnret(q, REGLINK, foreign, p);
+ if(q != p)
+ p->link = q;
+ }
+ else{
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_NONE;
+ p->from.reg = REGSP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ if(autosize){
+ q = prg();
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+ }
+ else
+ q = p;
+ q1 = fnret(nil, REGTMPT-1, foreign, p);
+ q1->link = q->link;
+ q->link = q1;
+ }
+ break;
+ }
+ if(foreign) {
+// if(foreign) print("ABXRET 3 %s\n", curtext->from.sym->name);
+#define R 1
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_NONE;
+ p->from.reg = REGSP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = R;
+ q = prg();
+ q->as = AADD;
+ q->scond = p->scond;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+ q1 = prg();
+ q1->as = ABXRET;
+ q1->scond = p->scond;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 0;
+ q1->to.reg = R;
+ q1->link = q->link;
+ q->link = q1;
+#undef R
+ }
+ else {
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
+ }
+ break;
+
+ become:
+ if(foreign){
+ diag("foreign become - help");
+ break;
+ }
+ if(thumb){
+ diag("thumb become - help");
+ break;
+ }
+ print("arm become\n");
+ if(curtext->mark & LEAF) {
+
+ if(!autosize) {
+ p->as = AB;
+ p->from = zprg.from;
+ break;
+ }
+
+#ifdef optimise_time
+ q = prg();
+ q->scond = p->scond;
+ q->line = p->line;
+ q->as = AB;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ p->link = q;
+
+ p->as = AADD;
+ p->from = zprg.from;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ break;
+#endif
+ }
+ q = prg();
+ q->scond = p->scond;
+ q->line = p->line;
+ q->as = AB;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ p->link = q;
+ if(thumb){
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AADD;
+ q1->from.type = D_CONST;
+ q1->from.offset = autosize;
+ q1->to.type = D_REG;
+ q1->to.reg = REGSP;
+ p->as = AMOVW;
+ p->line = p->line;
+ p->from.type = D_OREG;
+ p->from.name = D_NONE;
+ p->from.reg = REGSP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q1->link = q;
+ p->link = q1;
+ q2 = movrr(nil, REGTMPT-1, REGLINK, p);
+ q2->link = q;
+ q1->link = q2;
+ break;
+ }
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from = zprg.from;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGLINK;
+
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ if(debug['M'])
+ break;
+ if(p->from.type != D_REG)
+ break;
+ if(p->to.type != D_REG)
+ break;
+ q1 = p;
+
+ /* MOV a,4(SP) */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AMOVW;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->from.reg;
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+
+ /* MOV b,REGTMP */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AMOVW;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->reg;
+ if(q1->reg == NREG)
+ p->from.reg = q1->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+#ifdef CALLEEBX
+ p->as = ABL;
+#else
+ if(prog_div != UP && prog_div->from.sym->thumb)
+ p->as = thumb ? ABL : ABX;
+ else
+ p->as = thumb ? ABX : ABL;
+#endif
+ p->line = q1->line;
+ p->to.type = D_BRANCH;
+ p->cond = p;
+ switch(o) {
+ case ADIV:
+ p->cond = prog_div;
+ p->to.sym = sym_div;
+ break;
+ case ADIVU:
+ p->cond = prog_divu;
+ p->to.sym = sym_divu;
+ break;
+ case AMOD:
+ p->cond = prog_mod;
+ p->to.sym = sym_mod;
+ break;
+ case AMODU:
+ p->cond = prog_modu;
+ p->to.sym = sym_modu;
+ break;
+ }
+
+ /* MOV REGTMP, b */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AMOVW;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = q1->to.reg;
+
+ /* ADD $8,SP */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.reg = NREG;
+ p->from.offset = 8;
+ p->reg = NREG;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ /* SUB $8,SP */
+ q1->as = ASUB;
+ q1->from.type = D_CONST;
+ q1->from.offset = 8;
+ q1->from.reg = NREG;
+ q1->reg = NREG;
+ q1->to.type = D_REG;
+ q1->to.reg = REGSP;
+
+ break;
+ case AMOVW:
+ if(thumb){
+ Adr *a = &p->from;
+
+ if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
+ diag("SP offset not multiple of 4");
+ }
+ break;
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ if(thumb){
+ if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
+ q = prg();
+ *q = *p;
+ if(p->from.name == D_AUTO)
+ q->from.offset += autosize;
+ else if(p->from.name == D_PARAM)
+ q->from.offset += autosize+4;
+ q->from.name = D_NONE;
+ q->from.reg = REGTMPT;
+ p = movrr(p, REGSP, REGTMPT, p);
+ q->link = p->link;
+ p->link = q;
+ }
+ if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
+ q = prg();
+ *q = *p;
+ if(p->to.name == D_AUTO)
+ q->to.offset += autosize;
+ else if(p->to.name == D_PARAM)
+ q->to.offset += autosize+4;
+ q->to.name = D_NONE;
+ q->to.reg = REGTMPT;
+ p = movrr(p, REGSP, REGTMPT, p);
+ q->link = p->link;
+ p->link = q;
+ if(q->to.offset < 0 || q->to.offset > 255){ // complicated
+ p->to.reg = REGTMPT+1; // mov sp, r8
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AMOVW;
+ q1->from.type = D_CONST;
+ q1->from.offset = q->to.offset;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMPT; // mov $o, r7
+ p->link = q1;
+ q1->link = q;
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AADD;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMPT+1;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMPT; // add r8, r7
+ p->link->link = q1;
+ q1->link = q;
+ q->to.offset = 0; // mov* r, 0(r7)
+ /* phew */
+ }
+ }
+ }
+ break;
+ case AMOVM:
+ if(thumb){
+ if(p->from.type == D_OREG){
+ if(p->from.offset == 0)
+ p->from.type = D_REG;
+ else
+ diag("non-zero AMOVM offset");
+ }
+ else if(p->to.type == D_OREG){
+ if(p->to.offset == 0)
+ p->to.type = D_REG;
+ else
+ diag("non-zero AMOVM offset");
+ }
+ }
+ break;
+ case AB:
+ if(thumb && p->to.type == D_OREG){
+ if(p->to.offset == 0){
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
+ }
+ else{
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = p->to.offset;
+ p->reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q = prg();
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGTMPT-1;
+ q->to.type = D_REG;
+ q->to.reg = REGPC;
+ q->link = p->link;
+ p->link = q;
+ }
+ }
+ if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
+ // print("warn %s: b (R%d) assuming a return\n", curtext->from.sym->name, p->to.reg);
+ p->as = ABXRET;
+ }
+ break;
+ case ABL:
+ case ABX:
+ if(thumb && p->to.type == D_OREG){
+ if(p->to.offset == 0){
+ p->as = o;
+ p->from.type = D_NONE;
+ p->to.type = D_REG;
+ }
+ else{
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = p->to.offset;
+ p->reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q = prg();
+ q->as = o;
+ q->line = p->line;
+ q->from.type = D_NONE;
+ q->to.type = D_REG;
+ q->to.reg = REGTMPT-1;
+ q->link = p->link;
+ p->link = q;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void
+sigdiv(char *n)
+{
+ Sym *s;
+
+ s = lookup(n, 0);
+ if(s->type == STEXT){
+ if(s->sig == 0)
+ s->sig = SIGNINTERN;
+ }
+ else if(s->type == 0 || s->type == SXREF)
+ s->type = SUNDEF;
+}
+
+void
+divsig(void)
+{
+ sigdiv("_div");
+ sigdiv("_divu");
+ sigdiv("_mod");
+ sigdiv("_modu");
+}
+
+static void
+sdiv(Sym *s)
+{
+ if(s->type == 0 || s->type == SXREF){
+ /* undefsym(s); */
+ s->type = SXREF;
+ if(s->sig == 0)
+ s->sig = SIGNINTERN;
+ s->subtype = SIMPORT;
+ }
+ else if(s->type != STEXT)
+ diag("undefined: %s", s->name);
+}
+
+void
+initdiv(void)
+{
+ Sym *s2, *s3, *s4, *s5;
+ Prog *p;
+
+ if(prog_div != P)
+ return;
+ sym_div = s2 = lookup("_div", 0);
+ sym_divu = s3 = lookup("_divu", 0);
+ sym_mod = s4 = lookup("_mod", 0);
+ sym_modu = s5 = lookup("_modu", 0);
+ if(dlm) {
+ sdiv(s2); if(s2->type == SXREF) prog_div = UP;
+ sdiv(s3); if(s3->type == SXREF) prog_divu = UP;
+ sdiv(s4); if(s4->type == SXREF) prog_mod = UP;
+ sdiv(s5); if(s5->type == SXREF) prog_modu = UP;
+ }
+ for(p = firstp; p != P; p = p->link)
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2)
+ prog_div = p;
+ if(p->from.sym == s3)
+ prog_divu = p;
+ if(p->from.sym == s4)
+ prog_mod = p;
+ if(p->from.sym == s5)
+ prog_modu = p;
+ }
+ if(prog_div == P) {
+ diag("undefined: %s", s2->name);
+ prog_div = curtext;
+ }
+ if(prog_divu == P) {
+ diag("undefined: %s", s3->name);
+ prog_divu = curtext;
+ }
+ if(prog_mod == P) {
+ diag("undefined: %s", s4->name);
+ prog_mod = curtext;
+ }
+ if(prog_modu == P) {
+ diag("undefined: %s", s5->name);
+ prog_modu = curtext;
+ }
+}
+
+static void
+setdiv(int as)
+{
+ Prog *p = nil;
+
+ switch(as){
+ case ADIV: p = prog_div; break;
+ case ADIVU: p = prog_divu; break;
+ case AMOD: p = prog_mod; break;
+ case AMODU: p = prog_modu; break;
+ }
+ if(p != UP && thumb != p->from.sym->thumb)
+ p->from.sym->foreign = 1;
+}
+
+void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
diff --git a/utils/5l/obj.c b/utils/5l/obj.c
new file mode 100644
index 00000000..f70f7356
--- /dev/null
+++ b/utils/5l/obj.c
@@ -0,0 +1,1557 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = '5';
+char *thestring = "arm";
+
+/*
+ * -H1 -T0x10005000 -R4 is aif for risc os
+ * -H2 -T4128 -R4096 is plan9 format
+ * -H3 -T0xF0000020 -R4 is NetBSD format
+ * -H4 is IXP1200 (raw)
+ * -H5 -T0xC0008010 -R1024 is ipaq
+ */
+
+static int
+isobjfile(char *f)
+{
+ int n, v;
+ Biobuf *b;
+ char buf1[5], buf2[SARMAG];
+
+ b = Bopen(f, OREAD);
+ if(b == nil)
+ return 0;
+ n = Bread(b, buf1, 5);
+ if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
+ v = 1; /* good enough for our purposes */
+ else{
+ Bseek(b, 0, 0);
+ n = Bread(b, buf2, SARMAG);
+ v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
+ }
+ Bterm(b);
+ return v;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ srand(time(0));
+ cout = -1;
+ listinit();
+ outfile = 0;
+ nerrors = 0;
+ curtext = P;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ /* do something about setting INITTEXT */
+ break;
+ case 'x': /* produce export table */
+ doexp = 1;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SEXPORT);
+ break;
+ case 'u': /* produce dynamically loadable module */
+ dlm = 1;
+ debug['l']++;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SIMPORT);
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0) {
+ diag("usage: 5l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 0;
+ if(debug['B'])
+ HEADTYPE = 1;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+ case 0: /* no header */
+ HEADR = 0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 1: /* aif for risc os */
+ HEADR = 128L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x10005000 + HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* boot for NetBSD */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xF0000020L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 4: /* boot for IXP1200 */
+ HEADR = 0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 5: /* boot for ipaq */
+ HEADR = 16L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xC0008010;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 1024;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.scond = 14;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.to = zprg.from;
+ buildop();
+ thumbbuildop(); // could build on demand
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ dtype = 4;
+ if(outfile == 0)
+ outfile = "5.out";
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("%s: cannot create", outfile);
+ errorexit();
+ }
+ nuxiinit();
+
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ goto out;
+ if(doexp || dlm){
+ EXPTAB = "_exporttab";
+ zerosig(EXPTAB);
+ zerosig("etext");
+ zerosig("edata");
+ zerosig("end");
+ if(dlm){
+ initdiv();
+ import();
+ HEADTYPE = 2;
+ INITTEXT = INITDAT = 0;
+ INITRND = 8;
+ INITENTRY = EXPTAB;
+ }
+ else
+ divsig();
+ export();
+ }
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ if(debug['u'])
+ reachable();
+ dodata();
+ if(seenthumb && debug['f'])
+ fnptrs();
+ follow();
+ if(firstp == P)
+ goto out;
+ noops();
+ span();
+ asmb();
+ undef();
+
+out:
+ if(debug['c']){
+ thumbcount();
+ print("ARM size = %d\n", armsize);
+ }
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ Bflush(&bso);
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int i, c;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ c = p[2];
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ p[0] = ALAST+1;
+ return 0;
+ }
+ a->type = p[0];
+ a->reg = p[1];
+ a->sym = h[c];
+ a->name = p[3];
+ c = 4;
+
+ if(a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+ }
+
+ if(a->type == D_CONST || a->type == D_OCONST) {
+ if(a->name == D_EXTERN || a->name == D_STATIC) {
+ s = a->sym;
+ if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) {
+ if(0 && !s->fnptr && s->name[0] != '.')
+ print("%s used as function pointer\n", s->name);
+ s->fnptr = 1; // over the top cos of SXREF
+ }
+ }
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+
+ case D_REGREG:
+ a->offset = p[4];
+ c++;
+ break;
+
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ case D_SHIFT:
+ a->offset = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ c += 4;
+ break;
+
+ case D_SCONST:
+ while(nhunk < NSNAME)
+ gethunk();
+ a->sval = (char*)hunk;
+ nhunk -= NSNAME;
+ hunk += NSNAME;
+
+ memmove(a->sval, p+4, NSNAME);
+ c += NSNAME;
+ break;
+
+ case D_FCONST:
+ while(nhunk < sizeof(Ieee))
+ gethunk();
+ a->ieee = (Ieee*)hunk;
+ nhunk -= NSNAME;
+ hunk += NSNAME;
+
+ a->ieee->l = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ a->ieee->h = p[8] | (p[9]<<8) |
+ (p[10]<<16) | (p[11]<<24);
+ c += 8;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ return c;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+static void puntfp(Prog *);
+
+void
+ldobj(int f, long c, char *pn)
+{
+ long ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ Sym *h[NSYM], *s, *di;
+ int v, o, r, skip;
+ ulong sig;
+ static int files;
+ static char **filen;
+ char **nfilen;
+
+ if((files&15) == 0){
+ nfilen = malloc((files+16)*sizeof(char*));
+ memmove(nfilen, filen, files*sizeof(char*));
+ free(filen);
+ filen = nfilen;
+ }
+ filen[files++] = strdup(pn);
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0]; /* as */
+ if(o <= AXXX || o >= ALAST) {
+ diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o);
+ print(" probably not a .5 file\n");
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME){
+ sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24);
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[1]; /* type */
+ o = bloc[2]; /* sym */
+ bloc += 3;
+ c -= 3;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
+ s->sig = sig;
+ s->file = files-1;
+ }
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ if(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->scond = bloc[1];
+ p->reg = bloc[2];
+ p->line = bloc[3] | (bloc[4]<<8) | (bloc[5]<<16) | (bloc[6]<<24);
+
+ r = zaddr(bloc+7, &p->from, h) + 7;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(p->reg < 0 || p->reg > NREG)
+ diag("register out of range %d", p->reg);
+
+ p->link = P;
+ p->cond = P;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ break;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->reg = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_CONST;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case ADATA:
+ if(p->from.sym == S) {
+ diag("DATA without a sym\n%P", p);
+ break;
+ }
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ setarch(p);
+ setthumb(p);
+ p->align = 4;
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ curtext = p;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
+ s = p->from.sym;
+ if(s == S) {
+ diag("TEXT must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->reg & DUPOK) {
+ skip = 1;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P", s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ s->thumb = thumb;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->cond = p;
+ etextp = p;
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE)
+ if(p->from.offset < 0) {
+ p->from.offset = -p->from.offset;
+ p->as = AADD;
+ }
+ goto casedef;
+
+ case AADD:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE)
+ if(p->from.offset < 0) {
+ p->from.offset = -p->from.offset;
+ p->as = ASUB;
+ }
+ goto casedef;
+
+ case AMOVWD:
+ case AMOVWF:
+ case AMOVDW:
+ case AMOVFW:
+ case AMOVFD:
+ case AMOVDF:
+ // case AMOVF:
+ // case AMOVD:
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ if(thumb)
+ puntfp(p);
+ goto casedef;
+
+ case AMOVF:
+ if(thumb)
+ puntfp(p);
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 4;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVD:
+ if(thumb)
+ puntfp(p);
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee->l, p->from.ieee->h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ s->used = s->thumb = s->foreign = s->fnptr = 0;
+ s->use = nil;
+ hash[h] = s;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = thumb ? REGTMPT : REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = thumb ? REGTMPT : REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = thumb ? REGTMPT : REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->reg = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->reg = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ if(p->reg & NOPROF) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * BL profin, R2
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BL profout
+ */
+ p->as = ABL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ fnuxi4[i] = c;
+ if(debug['d']){
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+ else{
+ fnuxi8[i] = c+4; /* ms word first, then ls, even in little endian mode */
+ fnuxi8[i+4] = c;
+ }
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", fnuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+long
+ieeedtof(Ieee *ieeep)
+{
+ int exp;
+ long v;
+
+ if(ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (ieeep->h & 0xfffffL) << 3;
+ v |= (ieeep->l >> 29) & 0x7L;
+ if((ieeep->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= ieeep->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
+
+static void
+puntfp(Prog *p)
+{
+ USED(p);
+ /* floating point - punt for now */
+ curtext->reg = NREG; /* ARM */
+ curtext->from.sym->thumb = 0;
+ thumb = 0;
+ // print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line);
+}
+
+void
+undefsym(Sym *s)
+{
+ int n;
+
+ n = imports;
+ if(s->value != 0)
+ diag("value != 0 on SXREF");
+ if(n >= 1<<Rindex)
+ diag("import index %d out of range", n);
+ s->value = n<<Roffset;
+ s->type = SUNDEF;
+ imports++;
+}
+
+void
+zerosig(char *sp)
+{
+ Sym *s;
+
+ s = lookup(sp, 0);
+ s->sig = 0;
+}
+
+void
+readundefs(char *f, int t)
+{
+ int i, n;
+ Sym *s;
+ Biobuf *b;
+ char *l, buf[256], *fields[64];
+
+ if(f == nil)
+ return;
+ b = Bopen(f, OREAD);
+ if(b == nil){
+ diag("could not open %s: %r", f);
+ errorexit();
+ }
+ while((l = Brdline(b, '\n')) != nil){
+ n = Blinelen(b);
+ if(n >= sizeof(buf)){
+ diag("%s: line too long", f);
+ errorexit();
+ }
+ memmove(buf, l, n);
+ buf[n-1] = '\0';
+ n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
+ if(n == nelem(fields)){
+ diag("%s: bad format", f);
+ errorexit();
+ }
+ for(i = 0; i < n; i++){
+ s = lookup(fields[i], 0);
+ s->type = SXREF;
+ s->subtype = t;
+ if(t == SIMPORT)
+ nimports++;
+ else
+ nexports++;
+ }
+ }
+ Bterm(b);
+}
diff --git a/utils/5l/optab.c b/utils/5l/optab.c
new file mode 100644
index 00000000..65ad3447
--- /dev/null
+++ b/utils/5l/optab.c
@@ -0,0 +1,253 @@
+#include "l.h"
+
+Optab optab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
+
+ { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
+
+ { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
+
+ { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
+ { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
+
+ { AMOVW, C_RECON,C_NONE, C_REG, 4, 4, REGSB },
+ { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
+
+ { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
+ { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+
+ { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 },
+ { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
+ { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
+
+ { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
+ { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
+
+ { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_LEXT, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
+
+ { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
+
+ { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
+ { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
+ { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
+
+ { AMOVB, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
+
+ { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
+ { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
+
+ { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
+ { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
+
+ { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+
+ { AMOVW, C_SEXT, C_NONE, C_REG, 21, 4, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+ { AMOVBU, C_SEXT, C_NONE, C_REG, 21, 4, REGSB },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+
+ { AMOVB, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
+ { AMOVB, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
+ { AMOVB, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
+ { AMOVH, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
+ { AMOVH, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
+ { AMOVH, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
+ { AMOVHU, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
+ { AMOVHU, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
+ { AMOVHU, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_SEXT, 23, 12, REGSB },
+ { AMOVH, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
+ { AMOVH, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
+ { AMOVHU, C_REG, C_NONE, C_SEXT, 23, 12, REGSB },
+ { AMOVHU, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
+ { AMOVHU, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
+ { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
+
+ { AMOVW, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM },
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
+ { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
+ { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
+ { AMOVBU, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM },
+ { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
+ { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
+ { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
+
+ { AMOVB, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
+ { AMOVH, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
+ { AMOVHU, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
+
+ { AMOVH, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO },
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
+
+ { AMOVW, C_LECON,C_NONE, C_REG, 34, 8, REGSB, LFROM },
+ { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
+
+ { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
+
+ { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
+ { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
+
+ { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
+
+ { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_FEXT, 50, 4, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
+
+ { AMOVF, C_FEXT, C_NONE, C_FREG, 51, 4, REGSB },
+ { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
+ { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_LEXT, 52, 12, REGSB, LTO },
+ { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
+
+ { AMOVF, C_LEXT, C_NONE, C_FREG, 53, 12, REGSB, LFROM },
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
+
+ { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO },
+ { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM },
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
+ { AADDF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
+ { AADDF, C_FCON, C_REG, C_FREG, 54, 4, 0 },
+ { AMOVF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+
+ { ACMPF, C_FREG, C_REG, C_NONE, 54, 4, 0 },
+ { ACMPF, C_FCON, C_REG, C_NONE, 54, 4, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_REG, 55, 4, 0 },
+ { AMOVFW, C_REG, C_NONE, C_FREG, 55, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
+ { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
+
+ { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+ { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+
+ { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+
+ { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
+ { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 },
+ { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
+ { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
+ { AMOVHU, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 },
+ { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
+ { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
+
+ { AMOVB, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
+ { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
+ { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
+ { AMOVH, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
+ { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
+ { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
+ { AMOVHU, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
+ { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
+ { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
+
+ { AMOVH, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 },
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
+ { AMOVHU, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
+
+ { AMOVB, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
+ { AMOVH, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
+ { AMOVHU, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
diff --git a/utils/5l/pass.c b/utils/5l/pass.c
new file mode 100644
index 00000000..e4322df5
--- /dev/null
+++ b/utils/5l/pass.c
@@ -0,0 +1,942 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i, t;
+ Sym *s;
+ Prog *p;
+ long orig, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ v = p->from.offset + p->reg;
+ if(v > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ if((s->type == SBSS || s->type == SDATA) && (p->to.type == D_CONST || p->to.type == D_OCONST) && (p->to.name == D_EXTERN || p->to.name == D_STATIC)){
+ s = p->to.sym;
+ if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF))
+ s->fnptr = 1;
+ }
+ }
+
+ if(debug['t']) {
+ /*
+ * pull out string constants
+ */
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->to.type == D_SCONST)
+ s->type = SSTRING;
+ }
+ }
+
+ /*
+ * pass 1
+ * assign 'small' variables to data segment
+ * (rational is that data segment is more easily
+ * addressed through offset on R12)
+ */
+ orig = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA && t != SBSS)
+ continue;
+ v = s->value;
+ if(v == 0) {
+ diag("%s: no size", s->name);
+ v = 1;
+ }
+ while(v & 3)
+ v++;
+ s->value = v;
+ if(v > MINSIZ)
+ continue;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+
+ /*
+ * pass 2
+ * assign large 'data' variables to data segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA) {
+ if(t == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ v = s->value;
+ s->value = orig;
+ orig += v;
+ }
+
+ while(orig & 7)
+ orig++;
+ datsize = orig;
+
+ /*
+ * pass 3
+ * everything else to bss segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ v = s->value;
+ s->value = orig;
+ orig += v;
+ }
+ while(orig & 7)
+ orig++;
+ bsssize = orig-datsize;
+
+ xdefine("setR12", SDATA, 0L+BIG);
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+ xdefine("etext", STEXT, 0L);
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != AB)
+ return p;
+ p = p->cond;
+ }
+ return P;
+}
+
+int
+relinv(int a)
+{
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABCS: return ABCC;
+ case ABHS: return ABLO;
+ case ABCC: return ABCS;
+ case ABLO: return ABHS;
+ case ABMI: return ABPL;
+ case ABPL: return ABMI;
+ case ABVS: return ABVC;
+ case ABVC: return ABVS;
+ case ABHI: return ABLS;
+ case ABLS: return ABHI;
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+ }
+ diag("unknown relation: %s", anames[a]);
+ return a;
+}
+
+void
+follow(void)
+{
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+
+ firstp = firstp->link;
+ lastp->link = P;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == P)
+ return;
+ setarch(p);
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(a == AB) {
+ q = p->cond;
+ if(q != P) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
+ goto copy;
+ if(!q->cond || (q->cond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ lastp->link = r;
+ lastp = r;
+ continue;
+ }
+ lastp->link = r;
+ lastp = r;
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+ a = AB;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){
+ return;
+ }
+ if(p->cond != P)
+ if(a != ABL && a != ABX && p->link != P) {
+ q = brchain(p->link);
+ if(a != ATEXT && a != ABCASE)
+ if(q != P && (q->mark&FOLL)) {
+ p->as = relinv(a);
+ p->link = p->cond;
+ p->cond = q;
+ }
+ xfol(p->link);
+ q = brchain(p->cond);
+ if(q == P)
+ q = p->cond;
+ if(q->mark&FOLL) {
+ p->cond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ long c, vexit;
+ Prog *p, *q;
+ Sym *s, *s1;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(seenthumb && a == ABL){
+ // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
+ // print("%s calls %s\n", s1->name, s->name);
+ if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S && s->thumb != s1->thumb)
+ s->foreign = 1;
+ }
+ if((a == ABL || a == ABX || a == AB || a == ARET) &&
+ p->to.type != D_BRANCH && p->to.sym != S) {
+ s = p->to.sym;
+ switch(s->type) {
+ default:
+ diag("undefined: %s\n%P", s->name, p);
+ s->type = STEXT;
+ s->value = vexit;
+ break;
+ case STEXT:
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ break;
+ case SUNDEF:
+ if(p->as != ABL)
+ diag("help: SUNDEF in AB || ARET");
+ p->to.offset = 0;
+ p->to.type = D_BRANCH;
+ p->cond = UP;
+ break;
+ }
+ }
+ if(p->to.type != D_BRANCH || p->cond == UP)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range %ld\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ a = p->as;
+ if(p->as == ATEXT)
+ curtext = p;
+ if(seenthumb && a == ABL) {
+#ifdef CALLEEBX
+ if(0)
+ {}
+#else
+ if((s = p->to.sym) != S && (s->foreign || s->fnptr))
+ p->as = ABX;
+#endif
+ else if(p->to.type == D_OREG)
+ p->as = ABX;
+ }
+ if(p->cond != P && p->cond != UP) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ long dwn[LOG], cnt[LOG], i;
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != AB)
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
+
+#define Reachable(n) if((s = lookup(n, 0)) != nil) s->used++
+
+static void
+rused(Adr *a)
+{
+ Sym *s = a->sym;
+
+ if(s == S)
+ return;
+ if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){
+ if(a->name == D_EXTERN || a->name == D_STATIC){
+ if(s->used == 0)
+ s->used = 1;
+ }
+ }
+ else if(a->type == D_BRANCH){
+ if(s->used == 0)
+ s->used = 1;
+ }
+}
+
+void
+reachable()
+{
+ Prog *p, *prev, *prevt, *nextt, *q;
+ Sym *s, *s0;
+ int i, todo;
+ char *a;
+
+ Reachable("_div");
+ Reachable("_divu");
+ Reachable("_mod");
+ Reachable("_modu");
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return;
+ s = lookup(a, 0);
+ if(s == nil)
+ return;
+ if(s->type == 0){
+ s->used = 1; // to stop asm complaining
+ for(p = firstp; p != P && p->as != ATEXT; p = p->link)
+ ;
+ if(p == nil)
+ return;
+ s = p->from.sym;
+ }
+ s->used = 1;
+ do{
+ todo = 0;
+ for(p = firstp; p != P; p = p->link){
+ if(p->as == ATEXT && (s0 = p->from.sym)->used == 1){
+ todo = 1;
+ for(q = p->link; q != P && q->as != ATEXT; q = q->link){
+ rused(&q->from);
+ rused(&q->to);
+ }
+ s0->used = 2;
+ }
+ }
+ for(p = datap; p != P; p = p->link){
+ if((s0 = p->from.sym)->used == 1){
+ todo = 1;
+ for(q = p; q != P; q = q->link){ // data can be scattered
+ if(q->from.sym == s0)
+ rused(&q->to);
+ }
+ s0->used = 2;
+ }
+ }
+ }while(todo);
+ prev = nil;
+ prevt = nextt = nil;
+ for(p = firstp; p != P; ){
+ if(p->as == ATEXT){
+ prevt = nextt;
+ nextt = p;
+ }
+ if(p->as == ATEXT && (s0 = p->from.sym)->used == 0){
+ s0->type = SREMOVED;
+ for(q = p->link; q != P && q->as != ATEXT; q = q->link)
+ ;
+ if(q != p->cond)
+ diag("bad ptr in reachable()");
+ if(prev == nil)
+ firstp = q;
+ else
+ prev->link = q;
+ if(q == nil)
+ lastp = prev;
+ if(prevt == nil)
+ textp = q;
+ else
+ prevt->cond = q;
+ if(q == nil)
+ etextp = prevt;
+ nextt = prevt;
+ if(debug['V'])
+ print("%s unused\n", s0->name);
+ p = q;
+ }
+ else{
+ prev = p;
+ p = p->link;
+ }
+ }
+ prevt = nil;
+ for(p = datap; p != nil; ){
+ if((s0 = p->from.sym)->used == 0){
+ s0->type = SREMOVED;
+ prev = prevt;
+ for(q = p; q != nil; q = q->link){
+ if(q->from.sym == s0){
+ if(prev == nil)
+ datap = q->link;
+ else
+ prev->link = q->link;
+ }
+ else
+ prev = q;
+ }
+ if(debug['V'])
+ print("%s unused (data)\n", s0->name);
+ p = prevt->link;
+ }
+ else{
+ prevt = p;
+ p = p->link;
+ }
+ }
+ for(i=0; i<NHASH; i++){
+ for(s = hash[i]; s != S; s = s->link){
+ if(s->used == 0)
+ s->type = SREMOVED;
+ }
+ }
+}
+
+static void
+fused(Adr *a, Prog *p, Prog *ct)
+{
+ Sym *s = a->sym;
+ Use *u;
+
+ if(s == S)
+ return;
+ if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){
+ if(a->name == D_EXTERN || a->name == D_STATIC){
+ u = malloc(sizeof(Use));
+ u->p = p;
+ u->ct = ct;
+ u->link = s->use;
+ s->use = u;
+ }
+ }
+ else if(a->type == D_BRANCH){
+ u = malloc(sizeof(Use));
+ u->p = p;
+ u->ct = ct;
+ u->link = s->use;
+ s->use = u;
+ }
+}
+
+static int
+ckfpuse(Prog *p, Prog *ct, Sym *fp, Sym *r)
+{
+ int reg;
+
+ USED(fp);
+ USED(ct);
+ if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){
+ reg = p->to.reg;
+ for(p = p->link; p != P && p->as != ATEXT; p = p->link){
+ if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg)
+ return 1;
+ if(!debug['F'] && (isbranch(p) || p->as == ARET)){
+ // print("%s: branch %P in %s\n", fp->name, p, ct->from.sym->name);
+ return 0;
+ }
+ if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){
+ if(!debug['F'] && p->to.type != D_REG){
+ // print("%s: store %P in %s\n", fp->name, p, ct->from.sym->name);
+ return 0;
+ }
+ reg = p->to.reg;
+ }
+ }
+ }
+ // print("%s: no MOVW O(R), R\n", fp->name);
+ return debug['F'];
+}
+
+static void
+setfpuse(Prog *p, Sym *fp, Sym *r)
+{
+ int reg;
+
+ if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){
+ reg = p->to.reg;
+ for(p = p->link; p != P && p->as != ATEXT; p = p->link){
+ if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg){
+ fp->fnptr = 0;
+ p->as = ABL; // safe to do so
+// print("simplified %s call\n", fp->name);
+ break;
+ }
+ if(!debug['F'] && (isbranch(p) || p->as == ARET))
+ diag("bad setfpuse call");
+ if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){
+ if(!debug['F'] && p->to.type != D_REG)
+ diag("bad setfpuse call");
+ reg = p->to.reg;
+ }
+ }
+ }
+}
+
+static int
+cksymuse(Sym *s, int t)
+{
+ Prog *p;
+
+ for(p = datap; p != P; p = p->link){
+ if(p->from.sym == s && p->to.sym != nil && strcmp(p->to.sym->name, ".string") != 0 && p->to.sym->thumb != t){
+ // print("%s %s %d %d ", p->from.sym->name, p->to.sym->name, p->to.sym->thumb, t);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* check the use of s at the given point */
+static int
+ckuse(Sym *s, Sym *s0, Use *u)
+{
+ Sym *s1;
+
+ s1 = u->p->from.sym;
+// print("ckuse %s %s %s\n", s->name, s0->name, s1 ? s1->name : "nil");
+ if(u->ct == nil){ /* in data area */
+ if(s0 == s && !cksymuse(s1, s0->thumb)){
+ // print("%s: cksymuse fails\n", s0->name);
+ return 0;
+ }
+ for(u = s1->use; u != U; u = u->link)
+ if(!ckuse(s1, s0, u))
+ return 0;
+ }
+ else{ /* in text area */
+ if(u->ct->from.sym->thumb != s0->thumb){
+ // print("%s(%d): foreign call %s(%d)\n", s0->name, s0->thumb, u->ct->from.sym->name, u->ct->from.sym->thumb);
+ return 0;
+ }
+ return ckfpuse(u->p, u->ct, s0, s);
+ }
+ return 1;
+}
+
+static void
+setuse(Sym *s, Sym *s0, Use *u)
+{
+ Sym *s1;
+
+ s1 = u->p->from.sym;
+ if(u->ct == nil){ /* in data area */
+ for(u = s1->use; u != U; u = u->link)
+ setuse(s1, s0, u);
+ }
+ else{ /* in text area */
+ setfpuse(u->p, s0, s);
+ }
+}
+
+/* detect BX O(R) which can be done as BL O(R) */
+void
+fnptrs()
+{
+ int i;
+ Sym *s;
+ Prog *p;
+ Use *u;
+
+ for(i=0; i<NHASH; i++){
+ for(s = hash[i]; s != S; s = s->link){
+ if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){
+ // print("%s : fnptr %d %d\n", s->name, s->thumb, s->foreign);
+ }
+ }
+ }
+ /* record use of syms */
+ for(p = firstp; p != P; p = p->link){
+ if(p->as == ATEXT)
+ curtext = p;
+ else{
+ fused(&p->from, p, curtext);
+ fused(&p->to, p, curtext);
+ }
+ }
+ for(p = datap; p != P; p = p->link)
+ fused(&p->to, p, nil);
+
+ /* now look for fn ptrs */
+ for(i=0; i<NHASH; i++){
+ for(s = hash[i]; s != S; s = s->link){
+ if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){
+ for(u = s->use; u != U; u = u->link){
+ if(!ckuse(s, s, u))
+ break;
+ }
+ if(u == U){ // can simplify
+ for(u = s->use; u != U; u = u->link)
+ setuse(s, s, u);
+ }
+ }
+ }
+ }
+
+ /* now free Use structures */
+}
+
+void
+import(void)
+{
+ int i;
+ Sym *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
+ undefsym(s);
+ Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
+ }
+}
+
+void
+ckoff(Sym *s, long v)
+{
+ if(v < 0 || v >= 1<<Roffset)
+ diag("relocation offset %ld for %s out of range", v, s->name);
+}
+
+static Prog*
+newdata(Sym *s, int o, int w, int t)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = datap;
+ datap = p;
+ p->as = ADATA;
+ p->reg = w;
+ p->from.type = D_OREG;
+ p->from.name = t;
+ p->from.sym = s;
+ p->from.offset = o;
+ p->to.type = D_CONST;
+ p->to.name = D_NONE;
+ return p;
+}
+
+void
+export(void)
+{
+ int i, j, n, off, nb, sv, ne;
+ Sym *s, *et, *str, **esyms;
+ Prog *p;
+ char buf[NSNAME], *t;
+
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ n++;
+ esyms = malloc(n*sizeof(Sym*));
+ ne = n;
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ esyms[n++] = s;
+ for(i = 0; i < ne-1; i++)
+ for(j = i+1; j < ne; j++)
+ if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
+ s = esyms[i];
+ esyms[i] = esyms[j];
+ esyms[j] = s;
+ }
+
+ nb = 0;
+ off = 0;
+ et = lookup(EXPTAB, 0);
+ if(et->type != 0 && et->type != SXREF)
+ diag("%s already defined", EXPTAB);
+ et->type = SDATA;
+ str = lookup(".string", 0);
+ if(str->type == 0)
+ str->type = SDATA;
+ sv = str->value;
+ for(i = 0; i < ne; i++){
+ s = esyms[i];
+ Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type);
+
+ /* signature */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.offset = s->sig;
+
+ /* address */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+
+ /* string */
+ t = s->name;
+ n = strlen(t)+1;
+ for(;;){
+ buf[nb++] = *t;
+ sv++;
+ if(nb >= NSNAME){
+ p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
+ p->to.type = D_SCONST;
+ p->to.sval = malloc(NSNAME);
+ memmove(p->to.sval, buf, NSNAME);
+ nb = 0;
+ }
+ if(*t++ == 0)
+ break;
+ }
+
+ /* name */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.name = D_STATIC;
+ p->to.sym = str;
+ p->to.offset = sv-n;
+ }
+
+ if(nb > 0){
+ p = newdata(str, sv-nb, nb, D_STATIC);
+ p->to.type = D_SCONST;
+ p->to.sval = malloc(NSNAME);
+ memmove(p->to.sval, buf, nb);
+ }
+
+ for(i = 0; i < 3; i++){
+ newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ }
+ et->value = off;
+ if(sv == 0)
+ sv = 1;
+ str->value = sv;
+ exports = ne;
+ free(esyms);
+}
diff --git a/utils/5l/span.c b/utils/5l/span.c
new file mode 100644
index 00000000..f91c776e
--- /dev/null
+++ b/utils/5l/span.c
@@ -0,0 +1,1262 @@
+#include "l.h"
+
+static struct {
+ ulong start;
+ ulong size;
+ ulong extra;
+} pool;
+
+int checkpool(Prog*, int);
+int flushpool(Prog*, int, int);
+
+int
+isbranch(Prog *p)
+{
+ int as = p->as;
+ return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
+}
+
+static int
+ispad(Prog *p)
+{
+ if(p->as != AMOVW)
+ return 0;
+ if(p->from.type != D_REG || p->from.reg != REGSB)
+ return 0;
+ if(p->to.type != D_REG || p->to.reg != REGSB)
+ return 0;
+ return 1;
+}
+
+int
+fninc(Sym *s)
+{
+ if(thumb){
+ if(s->thumb){
+ if(s->foreign)
+ return 8;
+ else
+ return 0;
+ }
+ else{
+ if(s->foreign)
+ return 0;
+ else
+ diag("T A !foreign in fninc");
+ }
+ }
+ else{
+ if(s->thumb){
+ if(s->foreign)
+ return 0;
+ else
+ diag("A T !foreign in fninc");
+ }
+ else{
+ if(s->foreign)
+ return 4;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int
+fnpinc(Sym *s)
+{
+ if(!s->fnptr){ // a simplified case BX O(R) -> BL O(R)
+ if(!debug['f'])
+ diag("fnptr == 0 in fnpinc");
+ if(s->foreign)
+ diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb);
+ return 0;
+ }
+ /* 0, 1, 2, 3 squared */
+ if(s->thumb)
+ return s->foreign ? 9 : 1;
+ else
+ return s->foreign ? 4 : 0;
+}
+
+static Prog *
+pad(Prog *p, int pc)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGSB;
+ q->to.type = D_REG;
+ q->to.reg = REGSB;
+ q->pc = pc;
+ q->link = p->link;
+ return q;
+}
+
+static int
+scan(Prog *op, Prog *p, int c)
+{
+ Prog *q;
+
+ for(q = op->link; q != p; q = q->link){
+ q->pc = c;
+ c += oplook(q)->size;
+ nocache(q);
+ }
+ return c;
+}
+
+/* size of a case statement including jump table */
+static long
+casesz(Prog *p)
+{
+ int jt = 0;
+ long n = 0;
+ Optab *o;
+
+ for( ; p != P; p = p->link){
+ if(p->as == ABCASE)
+ jt = 1;
+ else if(jt)
+ break;
+ o = oplook(p);
+ n += o->size;
+ }
+ return n;
+}
+
+void
+span(void)
+{
+ Prog *p, *op;
+ Sym *setext, *s;
+ Optab *o;
+ int m, bflag, i;
+ long c, otxt, v;
+ int lastthumb = -1;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+
+ bflag = 0;
+ c = INITTEXT;
+ op = nil;
+ otxt = c;
+ for(p = firstp; p != P; op = p, p = p->link) {
+ setarch(p);
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(blitrl){
+ if(thumb && isbranch(p))
+ pool.extra += brextra(p);
+ if(checkpool(op, p->as == ACASE ? casesz(p) : m))
+ c = p->pc = scan(op, p, c);
+ }
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ if(blitrl && lastthumb != -1 && lastthumb != thumb){ // flush literal pool
+ if(flushpool(op, 0, 1))
+ c = p->pc = scan(op, p, c);
+ }
+ lastthumb = thumb;
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ if(thumb && blitrl)
+ pool.extra += brextra(p);
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ switch(o->flag & (LFROM|LTO|LPOOL)) {
+ case LFROM:
+ addpool(p, &p->from);
+ break;
+ case LTO:
+ addpool(p, &p->to);
+ break;
+ case LPOOL:
+ if ((p->scond&C_SCOND) == 14)
+ flushpool(p, 0, 0);
+ break;
+ }
+ if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
+ flushpool(p, 0, 0);
+ c += m;
+ if(blitrl && p->link == P){
+ if(thumb && isbranch(p))
+ pool.extra += brextra(p);
+ checkpool(p, 0);
+ }
+ }
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ while(bflag) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ setarch(p);
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+/* very larg branches
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ bflag = 1;
+ }
+ }
+ */
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ }
+
+ if(seenthumb){ // branch resolution
+ int passes = 0;
+ int lastc = 0;
+ int again;
+ Prog *oop;
+
+ loop:
+ passes++;
+ if(passes > 100){
+ diag("span looping !");
+ errorexit();
+ }
+ c = INITTEXT;
+ oop = op = nil;
+ again = 0;
+ for(p = firstp; p != P; oop = op, op = p, p = p->link){
+ setarch(p);
+ if(p->pc != c)
+ again = 1;
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+ m = o->size;
+ if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
+ if(p->as == ABL)
+ m = 4;
+ else
+ m = 2;
+ p->align = 0;
+ }
+ if(p->align){
+ if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
+ if(ispad(op)){
+ oop->link = p;
+ op = oop;
+ c -= 2;
+ p->pc = c;
+ }
+ else{
+ op->link = pad(op, c);
+ op = op->link;
+ c += 2;
+ p->pc = c;
+ }
+ again = 1;
+ }
+ }
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ }
+ c += m;
+ }
+ if(c != lastc || again){
+ lastc = c;
+ goto loop;
+ }
+ }
+
+ if(0 && seenthumb){ // rm redundant padding - obsolete
+ int d;
+
+ op = nil;
+ d = 0;
+ for(p = firstp; p != P; op = p, p = p->link){
+ p->pc -= d;
+ if(p->as == ATEXT){
+ if(p->from.sym != S)
+ p->from.sym->value -= d;
+// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
+ }
+ if(ispad(p) && p->link != P && ispad(p->link)){
+ op->link = p->link->link;
+ d += 4;
+ p = op;
+ }
+ }
+ // print("%d bytes removed (padding)\n", d);
+ c -= d;
+ }
+
+ if(debug['t']) {
+ /*
+ * add strings to text segment
+ */
+ c = rnd(c, 8);
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SSTRING)
+ continue;
+ v = s->value;
+ while(v & 3)
+ v++;
+ s->value = c;
+ c += v;
+ }
+ }
+
+ c = rnd(c, 8);
+
+ setext = lookup("etext", 0);
+ if(setext != S) {
+ setext->value = c;
+ textsize = c - INITTEXT;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "tsize = %lux\n", textsize);
+ Bflush(&bso);
+}
+
+/*
+ * when the first reference to the literal pool threatens
+ * to go out of range of a 12-bit PC-relative offset,
+ * drop the pool now, and branch round it.
+ * this happens only in extended basic blocks that exceed 4k.
+ */
+int
+checkpool(Prog *p, int sz)
+{
+ if(thumb){
+ if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc)
+ return flushpool(p, 1, 0);
+ else if(p->link == P)
+ return flushpool(p, 2, 0);
+ return 0;
+ }
+ if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
+ return flushpool(p, 1, 0);
+ else if(p->link == P)
+ return flushpool(p, 2, 0);
+ return 0;
+}
+
+int
+flushpool(Prog *p, int skip, int force)
+{
+ Prog *q;
+
+ if(blitrl) {
+ if(skip){
+ if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
+ q = prg();
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = p->link;
+ q->link = blitrl;
+ blitrl = q;
+ }
+ else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048)))
+ return 0;
+ elitrl->link = p->link;
+ p->link = blitrl;
+ blitrl = 0; /* BUG: should refer back to values until out-of-range */
+ elitrl = 0;
+ pool.size = 0;
+ pool.start = 0;
+ pool.extra = 0;
+ return 1;
+ }
+ return 0;
+}
+
+void
+addpool(Prog *p, Adr *a)
+{
+ Prog *q, t;
+ int c;
+
+ if(thumb)
+ c = thumbaclass(a, p);
+ else
+ c = aclass(a);
+
+ t = zprg;
+ t.as = AWORD;
+
+ switch(c) {
+ default:
+ t.to = *a;
+ break;
+
+ case C_SROREG:
+ case C_LOREG:
+ case C_ROREG:
+ case C_FOREG:
+ case C_SOREG:
+ case C_HOREG:
+ case C_GOREG:
+ case C_FAUTO:
+ case C_SAUTO:
+ case C_LAUTO:
+ case C_LACON:
+ case C_GACON:
+ t.to.type = D_CONST;
+ t.to.offset = instoffset;
+ break;
+ }
+
+ for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
+ if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
+ p->cond = q;
+ return;
+ }
+
+ q = prg();
+ *q = t;
+ q->pc = pool.size;
+
+ if(blitrl == P) {
+ blitrl = q;
+ pool.start = p->pc;
+ q->align = 4;
+ } else
+ elitrl->link = q;
+ elitrl = q;
+ pool.size += 4;
+
+ p->cond = q;
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+}
+
+long
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+long
+immrot(ulong v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return (i<<8) | v | (1<<25);
+ v = (v<<2) | (v>>30);
+ }
+ return 0;
+}
+
+long
+immaddr(long v)
+{
+ if(v >= 0 && v <= 0xfff)
+ return (v & 0xfff) |
+ (1<<24) | /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xfff && v < 0)
+ return (-v & 0xfff) |
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+int
+immfloat(long v)
+{
+ return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
+}
+
+int
+immhalf(long v)
+{
+ if(v >= 0 && v <= 0xff)
+ return v|
+ (1<<24)| /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xff && v < 0)
+ return (-v & 0xff)|
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+int
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_REGREG:
+ return C_REGREG;
+
+ case D_SHIFT:
+ return C_SHIFT;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FPCR:
+ return C_FCR;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ s = a->sym;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ if(dlm) {
+ switch(t) {
+ default:
+ instoffset = s->value + a->offset + INITDAT;
+ break;
+ case SUNDEF:
+ case STEXT:
+ case SCONST:
+ case SLEAF:
+ case SSTRING:
+ instoffset = s->value + a->offset;
+ break;
+ }
+ return C_ADDR;
+ }
+ instoffset = s->value + a->offset - BIG;
+ t = immaddr(instoffset);
+ if(t) {
+ if(immhalf(instoffset))
+ return immfloat(t) ? C_HFEXT : C_HEXT;
+ if(immfloat(t))
+ return C_FEXT;
+ return C_SEXT;
+ }
+ return C_LEXT;
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ t = immaddr(instoffset);
+ if(t){
+ if(immhalf(instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ t = immaddr(instoffset);
+ if(t){
+ if(immhalf(instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ t = immaddr(instoffset);
+ if(t) {
+ if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */
+ return immfloat(t) ? C_HFOREG : C_HOREG;
+ if(immfloat(t))
+ return C_FOREG; /* n.b. that it will also satisfy immrot */
+ t = immrot(instoffset);
+ if(t)
+ return C_SROREG;
+ if(immhalf(instoffset))
+ return C_HOREG;
+ return C_SOREG;
+ }
+ t = immrot(instoffset);
+ if(t)
+ return C_ROREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_PSR:
+ return C_PSR;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) {
+ instoffset = s->value + a->offset;
+#ifdef CALLEEBX
+ instoffset += fnpinc(s);
+#else
+ if(s->thumb)
+ instoffset++; // T bit
+#endif
+ return C_LCON;
+ }
+ return C_LCON;
+ }
+ return C_GOK;
+
+ case D_FCONST:
+ return C_FCON;
+
+ case D_CONST:
+ switch(a->name) {
+
+ case D_NONE:
+ instoffset = a->offset;
+ if(a->reg != NREG)
+ goto aconsize;
+
+ t = immrot(instoffset);
+ if(t)
+ return C_RCON;
+ t = immrot(~instoffset);
+ if(t)
+ return C_NCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ switch(t) {
+ case 0:
+ case SXREF:
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ break;
+ case SUNDEF:
+ case STEXT:
+ case SSTRING:
+ case SCONST:
+ case SLEAF:
+ instoffset = s->value + a->offset;
+#ifdef CALLEEBX
+ instoffset += fnpinc(s);
+#else
+ if(s->thumb)
+ instoffset++; // T bit
+#endif
+ return C_LCON;
+ }
+ if(!dlm) {
+ instoffset = s->value + a->offset - BIG;
+ t = immrot(instoffset);
+ if(t && instoffset != 0)
+ return C_RECON;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ goto aconsize;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ aconsize:
+ t = immrot(instoffset);
+ if(t)
+ return C_RACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+ Optab *otab;
+ Oprang *orange;
+
+ if(thumb){
+ otab = thumboptab;
+ orange = thumboprange;
+ }
+ else{
+ otab = optab;
+ orange = oprange;
+ }
+ a1 = p->optab;
+ if(a1)
+ return otab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ if(thumb)
+ a1 = thumbaclass(&p->from, p) + 1;
+ else
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ if(thumb)
+ a3 = thumbaclass(&p->to, p) + 1;
+ else
+ a3 = aclass(&p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = orange[r].start;
+ if(o == 0) {
+ a1 = opcross[repop[r]][a1][a2][a3];
+ if(a1) {
+ p->optab = a1+1;
+ return otab+a1;
+ }
+ o = orange[r].stop; /* just generate an error */
+ }
+ if(0) {
+ print("oplook %A %d %d %d\n",
+ (int)p->as, a1, a2, a3);
+ print(" %d %d\n", p->from.type, p->to.type);
+ }
+ e = orange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-otab)+1;
+ return o;
+ }
+ diag("illegal combination %A %d %d %d",
+ p->as, a1, a2, a3);
+ prasm(p);
+ if(o == 0)
+ o = otab;
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_RCON || b == C_NCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_RACON)
+ return 1;
+ break;
+ case C_LECON:
+ if(b == C_RECON)
+ return 1;
+ break;
+
+ case C_HFEXT:
+ return b == C_HEXT || b == C_FEXT;
+ case C_FEXT:
+ case C_HEXT:
+ return b == C_HFEXT;
+ case C_SEXT:
+ return cmp(C_HFEXT, b);
+ case C_LEXT:
+ return cmp(C_SEXT, b);
+
+ case C_HFAUTO:
+ return b == C_HAUTO || b == C_FAUTO;
+ case C_FAUTO:
+ case C_HAUTO:
+ return b == C_HFAUTO;
+ case C_SAUTO:
+ return cmp(C_HFAUTO, b);
+ case C_LAUTO:
+ return cmp(C_SAUTO, b);
+
+ case C_HFOREG:
+ return b == C_HOREG || b == C_FOREG;
+ case C_FOREG:
+ case C_HOREG:
+ return b == C_HFOREG;
+ case C_SROREG:
+ return cmp(C_SOREG, b) || cmp(C_ROREG, b);
+ case C_SOREG:
+ case C_ROREG:
+ return b == C_SROREG || cmp(C_HFOREG, b);
+ case C_LOREG:
+ return cmp(C_SROREG, b);
+
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_GBRA:
+ if(b == C_SBRA || b == C_LBRA)
+ return 1;
+
+ case C_HREG:
+ return cmp(C_SP, b) || cmp(C_PC, b);
+
+ }
+ return 0;
+}
+
+int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ armv4 = !debug['h'];
+ for(i=0; i<C_GOK; i++)
+ for(n=0; n<C_GOK; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ if((optab[n].flag & V4) && !armv4) {
+ optab[n].as = AXXX;
+ break;
+ }
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A", r);
+ errorexit();
+ case AADD:
+ oprange[AAND] = oprange[r];
+ oprange[AEOR] = oprange[r];
+ oprange[ASUB] = oprange[r];
+ oprange[ARSB] = oprange[r];
+ oprange[AADC] = oprange[r];
+ oprange[ASBC] = oprange[r];
+ oprange[ARSC] = oprange[r];
+ oprange[AORR] = oprange[r];
+ oprange[ABIC] = oprange[r];
+ break;
+ case ACMP:
+ oprange[ATST] = oprange[r];
+ oprange[ATEQ] = oprange[r];
+ oprange[ACMN] = oprange[r];
+ break;
+ case AMVN:
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ oprange[ABCS] = oprange[r];
+ oprange[ABHS] = oprange[r];
+ oprange[ABCC] = oprange[r];
+ oprange[ABLO] = oprange[r];
+ oprange[ABMI] = oprange[r];
+ oprange[ABPL] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABHI] = oprange[r];
+ oprange[ABLS] = oprange[r];
+ oprange[ABGE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ break;
+ case AMUL:
+ oprange[AMULU] = oprange[r];
+ break;
+ case ADIV:
+ oprange[AMOD] = oprange[r];
+ oprange[AMODU] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ break;
+ case AMOVW:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ break;
+ case ASWPW:
+ oprange[ASWPBU] = oprange[r];
+ break;
+ case AB:
+ case ABL:
+ case ABX:
+ case ABXRET:
+ case ASWI:
+ case AWORD:
+ case AMOVM:
+ case ARFE:
+ case ATEXT:
+ case ACASE:
+ case ABCASE:
+ break;
+ case AADDF:
+ oprange[AADDD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ break;
+
+ case ACMPF:
+ oprange[ACMPD] = oprange[r];
+ break;
+
+ case AMOVF:
+ oprange[AMOVD] = oprange[r];
+ break;
+
+ case AMOVFW:
+ oprange[AMOVWF] = oprange[r];
+ oprange[AMOVWD] = oprange[r];
+ oprange[AMOVDW] = oprange[r];
+ break;
+
+ case AMULL:
+ oprange[AMULA] = oprange[r];
+ oprange[AMULAL] = oprange[r];
+ oprange[AMULLU] = oprange[r];
+ oprange[AMULALU] = oprange[r];
+ break;
+ }
+ }
+}
+
+/*
+void
+buildrep(int x, int as)
+{
+ Opcross *p;
+ Optab *e, *s, *o;
+ int a1, a2, a3, n;
+
+ if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
+ diag("assumptions fail in buildrep");
+ errorexit();
+ }
+ repop[as] = x;
+ p = (opcross + x);
+ s = oprange[as].start;
+ e = oprange[as].stop;
+ for(o=e-1; o>=s; o--) {
+ n = o-optab;
+ for(a2=0; a2<2; a2++) {
+ if(a2) {
+ if(o->a2 == C_NONE)
+ continue;
+ } else
+ if(o->a2 != C_NONE)
+ continue;
+ for(a1=0; a1<32; a1++) {
+ if(!xcmp[a1][o->a1])
+ continue;
+ for(a3=0; a3<32; a3++)
+ if(xcmp[a3][o->a3])
+ (*p)[a1][a2][a3] = n;
+ }
+ }
+ }
+ oprange[as].start = 0;
+}
+*/
+
+enum{
+ ABSD = 0,
+ ABSU = 1,
+ RELD = 2,
+ RELU = 3,
+};
+
+int modemap[4] = { 0, 1, -1, 2, };
+
+typedef struct Reloc Reloc;
+
+struct Reloc
+{
+ int n;
+ int t;
+ uchar *m;
+ ulong *a;
+};
+
+Reloc rels;
+
+static void
+grow(Reloc *r)
+{
+ int t;
+ uchar *m, *nm;
+ ulong *a, *na;
+
+ t = r->t;
+ r->t += 64;
+ m = r->m;
+ a = r->a;
+ r->m = nm = malloc(r->t*sizeof(uchar));
+ r->a = na = malloc(r->t*sizeof(ulong));
+ memmove(nm, m, t*sizeof(uchar));
+ memmove(na, a, t*sizeof(ulong));
+ free(m);
+ free(a);
+}
+
+void
+dynreloc(Sym *s, long v, int abs)
+{
+ int i, k, n;
+ uchar *m;
+ ulong *a;
+ Reloc *r;
+
+ if(v&3)
+ diag("bad relocation address");
+ v >>= 2;
+ if(s != S && s->type == SUNDEF)
+ k = abs ? ABSU : RELU;
+ else
+ k = abs ? ABSD : RELD;
+ /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
+ k = modemap[k];
+ r = &rels;
+ n = r->n;
+ if(n >= r->t)
+ grow(r);
+ m = r->m;
+ a = r->a;
+ for(i = n; i > 0; i--){
+ if(v < a[i-1]){ /* happens occasionally for data */
+ m[i] = m[i-1];
+ a[i] = a[i-1];
+ }
+ else
+ break;
+ }
+ m[i] = k;
+ a[i] = v;
+ r->n++;
+}
+
+static int
+sput(char *s)
+{
+ char *p;
+
+ p = s;
+ while(*s)
+ cput(*s++);
+ cput(0);
+ return s-p+1;
+}
+
+void
+asmdyn()
+{
+ int i, n, t, c;
+ Sym *s;
+ ulong la, ra, *a;
+ vlong off;
+ uchar *m;
+ Reloc *r;
+
+ cflush();
+ off = seek(cout, 0, 1);
+ lput(0);
+ t = 0;
+ lput(imports);
+ t += 4;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SUNDEF){
+ lput(s->sig);
+ t += 4;
+ t += sput(s->name);
+ }
+
+ la = 0;
+ r = &rels;
+ n = r->n;
+ m = r->m;
+ a = r->a;
+ lput(n);
+ t += 4;
+ for(i = 0; i < n; i++){
+ ra = *a-la;
+ if(*a < la)
+ diag("bad relocation order");
+ if(ra < 256)
+ c = 0;
+ else if(ra < 65536)
+ c = 1;
+ else
+ c = 2;
+ cput((c<<6)|*m++);
+ t++;
+ if(c == 0){
+ cput(ra);
+ t++;
+ }
+ else if(c == 1){
+ wput(ra);
+ t += 2;
+ }
+ else{
+ lput(ra);
+ t += 4;
+ }
+ la = *a++;
+ }
+
+ cflush();
+ seek(cout, off, 0);
+ lput(t);
+
+ if(debug['v']){
+ Bprint(&bso, "import table entries = %d\n", imports);
+ Bprint(&bso, "export table entries = %d\n", exports);
+ }
+}
diff --git a/utils/5l/thumb.c b/utils/5l/thumb.c
new file mode 100644
index 00000000..9ec8ce5b
--- /dev/null
+++ b/utils/5l/thumb.c
@@ -0,0 +1,1637 @@
+#include "l.h"
+
+static long thumboprr(int);
+static long thumboprrr(int, int);
+static long thumbopirr(int , int);
+static long thumbopri(int);
+static long thumbophh(int);
+static long thumbopbra(int);
+static long thumbopmv(int, int);
+static void lowreg(Prog *, int);
+static void mult(Prog *, int, int);
+static void numr(Prog *, int, int, int);
+static void regis(Prog *, int, int, int);
+static void dis(int, int);
+
+// build a constant using neg, add and shift - only worth it if < 6 bytes */
+static int
+immbuildcon(int c, Prog *p)
+{
+ int n = 0;
+
+ USED(p);
+ if(c >= 0 && c <= 255)
+ return 0; // mv
+ if(c >= -255 && c < 0) // mv, neg
+ return 1;
+ if(c >= 256 && c <= 510) // mv, add
+ return 1;
+ if(c < 0)
+ return 0;
+ while(!(c & 1)){
+ n++;
+ c >>= 1;
+ }
+ if(c >= 0 && c <= 255) // mv, lsl
+ return 1;
+ return 0;
+}
+
+// positive 5 bit offset from register - O(R)
+// positive 8 bit offset from register - mov O, R then [R, R]
+// otherwise O goes in literal pool - mov O1(PC), R then [R, R]
+static int
+immoreg(int off, Prog *p)
+{
+ int v = 1;
+ int as = p->as;
+
+ if(off < 0)
+ return C_GOREG;
+ if(as == AMOVW)
+ v = 4;
+ else if(as == AMOVH || as == AMOVHU)
+ v = 2;
+ else if(as == AMOVB || as == AMOVBU)
+ v = 1;
+ else
+ diag("bad op in immoreg");
+ if(off/v <= 31)
+ return C_SOREG;
+ if(off <= 255)
+ return C_LOREG;
+ return C_GOREG;
+}
+
+// positive 8 bit - mov O, R then 0(R)
+// otherwise O goes in literal pool - mov O1(PC), R then 0(R)
+static int
+immacon(int off, Prog *p, int t1, int t2)
+{
+ USED(p);
+ if(off < 0)
+ return t2;
+ if(off <= 255)
+ return t1;
+ return t2;
+}
+
+// unsigned 8 bit in words
+static int
+immauto(int off, Prog *p)
+{
+ if(p->as != AMOVW)
+ diag("bad op in immauto");
+ mult(p, off, 4);
+ if(off >= 0 && off <= 1020)
+ return C_SAUTO;
+ return C_LAUTO;
+}
+
+static int
+immsmall(int off, Prog *p, int t1, int t2, int t3)
+{
+ USED(p);
+ if(off >= 0 && off <= 7)
+ return t1;
+ if(off >= 0 && off <= 255)
+ return t2;
+ return t3;
+}
+
+static int
+immcon(int off, Prog *p)
+{
+ int as = p->as;
+
+ if(as == ASLL || as == ASRL || as == ASRA)
+ return C_SCON;
+ if(p->to.type == D_REG && p->to.reg == REGSP){
+ if(as == AADD || as == ASUB){
+ if(off >= 0 && off <= 508)
+ return C_SCON;
+ if(as == ASUB){
+ p->as = AADD;
+ p->from.offset = -p->from.offset;
+ }
+ return C_LCON;
+ }
+ diag("unknown type in immcon");
+ }
+ if(as == AADD || as == ASUB){
+ if(p->reg != NREG)
+ return immsmall(off, p, C_SCON, C_LCON, C_GCON);
+ return immacon(off, p, C_SCON, C_LCON);
+ }
+ if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p))
+ return C_BCON;
+ if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p))
+ return C_BCON;
+ if(as == ACMP || as == AMOVW)
+ return immacon(off, p, C_SCON, C_LCON);
+ return C_LCON;
+}
+
+int
+thumbaclass(Adr *a, Prog *p)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+ case D_REG:
+ if(a->reg == REGSP)
+ return C_SP;
+ if(a->reg == REGPC)
+ return C_PC;
+ if(a->reg >= 8)
+ return C_HREG;
+ return C_REG;
+ case D_SHIFT:
+ diag("D_SHIFT in thumbaclass");
+ return C_SHIFT;
+ case D_FREG:
+ diag("D_FREG in thumbaclass");
+ return C_FREG;
+ case D_FPCR:
+ diag("D_FPCR in thumbaclass");
+ return C_FCR;
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s\n",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ instoffset = a->sym->value + a->offset + INITDAT;
+ return C_LEXT; /* INITDAT unknown at this stage */
+ // return immacon(instoffset, p, C_SEXT, C_LEXT);
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ return immauto(instoffset, p);
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+// print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4);
+ return immauto(instoffset, p);
+ case D_NONE:
+ instoffset = a->offset;
+ if(a->reg == REGSP)
+ return immauto(instoffset, p);
+ else
+ return immoreg(instoffset, p);
+ }
+ return C_GOK;
+ case D_PSR:
+ diag("D_PSR in thumbaclass");
+ return C_PSR;
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s\n",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ if(s->type == STEXT || s->type == SLEAF){
+ instoffset = s->value + a->offset;
+#ifdef CALLEEBX
+ instoffset += fnpinc(s);
+#else
+ if(s->thumb)
+ instoffset++; // T bit
+#endif
+ return C_LCON;
+ }
+ return C_LCON; /* INITDAT unknown at this stage */
+ // return immcon(instoffset, p);
+ }
+ return C_GOK;
+ case D_FCONST:
+ diag("D_FCONST in thumaclass");
+ return C_FCON;
+ case D_CONST:
+ switch(a->name) {
+ case D_NONE:
+ instoffset = a->offset;
+ if(a->reg != NREG)
+ goto aconsize;
+ return immcon(instoffset, p);
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ switch(t) {
+ case 0:
+ case SXREF:
+ diag("undefined external: %s in %s\n",
+ s->name, TNAME);
+ s->type = SDATA;
+ break;
+ case SCONST:
+ case STEXT:
+ case SLEAF:
+ instoffset = s->value + a->offset;
+#ifdef CALLEEBX
+ instoffset += fnpinc(s);
+#else
+ if(s->thumb)
+ instoffset++; // T bit
+#endif
+ return C_LCON;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ return C_LCON; /* INITDAT unknown at this stage */
+ // return immcon(instoffset, p);
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ goto aconsize;
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ aconsize:
+ if(p->from.reg == REGSP || p->from.reg == NREG)
+ return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON;
+ else if(p->from.reg == p->to.reg)
+ return immacon(instoffset, p, C_SACON, C_GACON);
+ return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON);
+ }
+ return C_GOK;
+ case D_BRANCH: {
+ int v, va;
+
+ p->align = 0;
+ v = -4;
+ va = 0;
+ if(p->cond != P){
+ v = (p->cond->pc - p->pc) - 4;
+ va = p->cond->pc;
+ }
+ instoffset = v;
+ if(p->as == AB){
+ if(v >= -2048 && v <= 2046)
+ return C_SBRA;
+ p->align = 4;
+ instoffset = va;
+ return C_LBRA;
+ }
+ if(p->as == ABL){
+#ifdef CALLEEBX
+ int e;
+
+ if((e = fninc(p->to.sym))) {
+ v += e;
+ va += e;
+ instoffset += e;
+ }
+#endif
+ if(v >= -4194304 && v <= 4194302)
+ return C_SBRA;
+ p->align = 2;
+ instoffset = va;
+ return C_LBRA;
+ }
+ if(p->as == ABX){
+ v = va;
+ if(v >= 0 && v <= 255)
+ return C_SBRA;
+ p->align = 2;
+ instoffset = va;
+ return C_LBRA;
+ }
+ if(v >= -256 && v <= 254)
+ return C_SBRA;
+ if(v >= -(2048-2) && v <= (2046+2))
+ return C_LBRA;
+ p->align = 2;
+ instoffset = va;
+ return C_GBRA;
+ }
+ }
+ return C_GOK;
+}
+
+// as a1 a2 a3 type size param lit vers
+Optab thumboptab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+ { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 },
+ { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 },
+ { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 },
+ { AADD, C_REG, C_REG, C_REG, 2, 2, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 },
+ { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 },
+ { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM },
+ // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM },
+ { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 },
+ { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 },
+ { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 },
+ { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM },
+ { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 },
+ { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 },
+ { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM },
+ { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 },
+ { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM },
+ // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM },
+ // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM },
+ { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 },
+ { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM },
+ { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 },
+ { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 },
+ { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 },
+ { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 },
+ { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 },
+ { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 },
+ { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 },
+ { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 },
+ { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 },
+ { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL },
+ { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 },
+ { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 },
+ { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL },
+ { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 },
+ { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 },
+ { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 },
+ { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 },
+ // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 },
+ // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 },
+ { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 },
+ { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 },
+ { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 },
+ { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 },
+ { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 },
+ { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 },
+ { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 },
+ { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP },
+ { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM },
+ // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM },
+ { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
+ { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
+ { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
+ { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
+ { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
+ { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 },
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO },
+ { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
+ { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
+ { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
+ { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
+ { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
+ { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 },
+ { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 },
+ { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 },
+ { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 },
+ { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 },
+ { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 },
+ { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 },
+ { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM },
+ { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 },
+ { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 },
+ { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
+ { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
+ { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
+ { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
+ { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
+ { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
+ { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
+ { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
+ { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
+ { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
+ { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
+ { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM },
+ { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM },
+ { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 },
+};
+
+#define OPCNTSZ 52
+int opcount[OPCNTSZ];
+
+// is this too pessimistic ?
+int
+brextra(Prog *p)
+{
+ int c;
+
+ // +2 is for padding
+ if(p->as == ATEXT)
+ return 0-0+2;
+ if(!isbranch(p))
+ diag("bad op in brextra()");
+ c = thumbaclass(&p->to, p);
+ switch(p->as){
+ case AB:
+ if(c != C_SBRA)
+ return 0;
+ return 8-2+2;
+ case ABL:
+ if(c != C_SBRA)
+ return 0;
+ return 14-4+2;
+ case ABX:
+ if(c == C_REG || c == C_HREG)
+ return 0;
+#ifdef CALLEEBX
+ diag("ABX $I in brextra");
+#endif
+ if(c != C_SBRA)
+ return 0;
+ return 14-10+2;
+ default:
+ if(c == C_GBRA)
+ return 0;
+ if(c == C_LBRA)
+ return 10-4+2;
+ return 10-2+2;
+ }
+ return 0;
+}
+
+#define high(r) ((r)>=8)
+
+static long
+mv(Prog *p, int r, int off)
+{
+ int v, o;
+ if(p != nil && p->cond != nil){ // in literal pool
+ v = p->cond->pc - p->pc - 4;
+ if(p->cond->pc & 3)
+ diag("mv: bad literal pool alignment");
+ if(v & 3)
+ v += 2; // ensure M(4) offset
+ mult(p, v, 4);
+ off = v/4;
+ numr(p, off, 0, 255);
+ o = 0x9<<11;
+ }
+ else{
+ numr(p, off, 0, 255);
+ o = 0x4<<11;
+ }
+ o |= (r<<8) | off;
+ return o;
+}
+
+static void
+mvcon(Prog *p, int r, int c, long *o1, long *o2)
+{
+ int op = 0, n = 0;
+
+ if(c >= 0 && c <= 255)
+ diag("bad c in mvcon");
+ if(c >= -255 && c < 0) // mv, neg
+ c = -c;
+ else if(c >= 256 && c <= 510){ // mv, add
+ n = rand()%(511-c) + (c-255);
+ c -= n;
+ // n = c-255;
+ // c = 255;
+ op = AADD;
+ }
+ else{
+ if(c < 0)
+ diag("-ve in mvcon");
+ while(!(c & 1)){
+ n++;
+ c >>= 1;
+ }
+ if(c >= 0 && c <= 255) // mv, lsl
+ op = ASLL;
+ else
+ diag("bad shift in mvcon");
+ }
+ *o1 = mv(p, r, c);
+ switch(op){
+ case 0:
+ *o2 = (1<<14) | (9<<6) | (r<<3) | r;
+ break;
+ case AADD:
+ *o2 = (6<<11) | (r<<8) | n;
+ break;
+ case ASLL:
+ *o2 = (n<<6) | (r<<3) | r;
+ break;
+ }
+}
+
+static long
+mvlh(int rs, int rd)
+{
+ int o = 0x46<<8;
+
+ if(high(rs)){
+ rs -= 8;
+ o |= 1<<6;
+ }
+ if(high(rd)){
+ rd -= 8;
+ o |= 1<<7;
+ }
+ o |= (rs<<3) | rd;
+ return o;
+}
+
+void
+thumbbuildop()
+{
+ int i, n, r;
+ Optab *optab = thumboptab;
+ Oprang *oprange = thumboprange;
+
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ oprange[ABCS] = oprange[r];
+ oprange[ABHS] = oprange[r];
+ oprange[ABCC] = oprange[r];
+ oprange[ABLO] = oprange[r];
+ oprange[ABMI] = oprange[r];
+ oprange[ABPL] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABHI] = oprange[r];
+ oprange[ABLS] = oprange[r];
+ oprange[ABGE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ break;
+ case AMVN:
+ oprange[AADC] = oprange[r];
+ oprange[ASBC] = oprange[r];
+ oprange[AMUL] = oprange[r];
+ oprange[AAND] = oprange[r];
+ oprange[AEOR] = oprange[r];
+ oprange[AORR] = oprange[r];
+ oprange[ABIC] = oprange[r];
+ oprange[AMULU] = oprange[r];
+ break;
+ case ACMN:
+ oprange[ATST] = oprange[r];
+ break;
+ case ASRL:
+ oprange[ASRA] = oprange[r];
+ oprange[ASLL] = oprange[r];
+ break;
+ case AADD:
+ oprange[ASUB] = oprange[r];
+ break;
+ }
+ }
+}
+
+void
+thumbasmout(Prog *p, Optab *o)
+{
+ long o1, o2, o3, o4, o5, o6, o7, v;
+ int r, rf, rt;
+
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0;
+if(debug['P']) print("%ulx: %P type %d %d\n", (ulong)(p->pc), p, o->type, p->align);
+ opcount[o->type] += o->size;
+ switch(o->type) {
+ default:
+ diag("unknown asm %d", o->type);
+ prasm(p);
+ break;
+ case 0: /* pseudo ops */
+if(debug['G']) print("%ulx: %s: thumb\n", (ulong)(p->pc), p->from.sym->name);
+ break;
+ case 1: /* op R, -, R or op R, R, - */
+ o1 = thumboprr(p->as);
+ if(rt == NREG)
+ rt = r;
+ lowreg(p, rf);
+ lowreg(p, rt);
+ o1 |= (0x10<<10) | (rf<<3) | rt;
+ break;
+ case 2: /* add/sub R, R, R or add/sub R, -, R */
+ o1 = p->as == AADD ? 0x0<<9 : 0x1<<9;
+ if(r == NREG)
+ r = rt;
+ lowreg(p, rf);
+ lowreg(p, r);
+ lowreg(p, rt);
+ o1 |= (0x6<<10) | (rf<<6) | (r<<3) | rt;
+ break;
+ case 3: /* add/sub $I, R, R or add/sub $I, -, R */
+ thumbaclass(&p->from, p);
+ o1 = p->as == AADD ? 0x0<<9 : 0x1<<9;
+ if(r == NREG)
+ r = rt;
+ numr(p, instoffset, 0, 7);
+ lowreg(p, r);
+ lowreg(p, rt);
+ o1 |= (0x7<<10) | (instoffset<<6) | (r<<3) | rt;
+ break;
+ case 4: /* shift $I, R, R or shift $I, -, R */
+ thumbaclass(&p->from, p);
+ if(instoffset < 0)
+ diag("negative shift in thumbasmout");
+ instoffset %= 32;
+ o1 = thumbopri(p->as);
+ if(r == NREG)
+ r = rt;
+ numr(p, instoffset, 0, 31);
+ lowreg(p, r);
+ lowreg(p, rt);
+ o1 |= (0x0<<13) | (instoffset<<6) | (r<<3) | rt;
+ break;
+ case 5: /* add/sub/mov $I, -, R or cmp $I, R, - */
+ thumbaclass(&p->from, p);
+ o1 = thumbopri(p->as);
+ if(rt == NREG)
+ rt = r;
+ numr(p, instoffset, 0, 255);
+ lowreg(p, rt);
+ o1 |= (0x1<<13) | (rt<<8) | instoffset;
+ break;
+ case 6: /* add $I, PC/SP, R */
+ if(p->as == ASUB)
+ diag("subtract in add $I, PC/SP, R");
+ thumbaclass(&p->from, p);
+ o1 = r == REGSP ? 0x1<<11 : 0x0<<11;
+ numr(p, instoffset, 0, 255);
+ regis(p, r, REGSP, REGPC);
+ lowreg(p, rt);
+ o1 |= (0xa<<12) | (rt<<8) | instoffset;
+ break;
+ case 7: /* add, sub $I, SP */
+ thumbaclass(&p->from, p);
+ o1 = p->as == AADD ? 0x0<<7 : 0x1<<7;
+ numr(p, instoffset, 0, 508);
+ mult(p, instoffset, 4);
+ regis(p, rt, REGSP, REGSP);
+ o1 |= (0xb0<<8) | (instoffset>>2);
+ break;
+ case 8: /* add/mov/cmp R, R where at least 1 reg is high */
+ o1 = 0;
+ if(rt == NREG)
+ rt = r;
+ if(high(rf)){
+ o1 |= 1<<6;
+ rf -= 8;
+ }
+ if(high(rt)){
+ o1 |= 2<<6;
+ rt -= 8;
+ }
+ if(o1 == 0)
+ diag("no high register(%P)", p);
+ o1 |= thumbophh(p->as);
+ o1 |= (0x11<<10) | (rf<<3) | rt;
+ break;
+ case 9: /* B $I */
+ thumbaclass(&p->to, p);
+ numr(p, instoffset, -2048, 2046);
+ o1 = (0x1c<<11) | ((instoffset>>1)&0x7ff);
+ break;
+ case 10: /* Bcc $I */
+ thumbaclass(&p->to, p);
+ numr(p, instoffset, -256, 254);
+ o1 = thumbopbra(p->as);
+ o1 |= (0xd<<12) | ((instoffset>>1)&0xff);
+ break;
+ case 11: /* BL $I */
+ thumbaclass(&p->to, p);
+ numr(p, instoffset, -4194304, 4194302);
+ o1 = (0x1e<<11) | ((instoffset>>12)&0x7ff);
+ o2 = (0x1f<<11) | ((instoffset>>1)&0x7ff);
+ break;
+ case 12: /* BX $I */
+#ifdef CALLEEBX
+ diag("BX $I case");
+#endif
+ thumbaclass(&p->to, p);
+ if(p->to.sym->thumb)
+ instoffset |= 1; // T bit
+ o1 = mvlh(REGPC, REGTMPT);
+ o2 = (0x6<<11) | (REGTMPT<<8) | 7; // add 7, RTMP (T bit + PC offset)
+ o3 = mvlh(REGTMPT, REGLINK);
+ o4 = mv(nil, REGTMPT, instoffset);
+ o5 = (0x11c<<6) | (REGTMPT<<3);
+ // o1 = mv(nil, REGTMPT, v);
+ // o2 = (0x11b<<6) | (REGPC<<3) | REGLINK;
+ // o3 = (0x11c<<6) | (REGTMPT<<3);
+ break;
+ case 13: /* B O(R) */
+ diag("B O(R)");
+ break;
+ case 14: /* BL O(R) */
+ diag("BL O(R)");
+ break;
+ case 15: /* BX R */
+ o1 = mvlh(REGPC, REGTMPT);
+ o2 = (0x6<<11) | (REGTMPT<<8) | 5; // add 5, RTMP (T bit + PC offset)
+ o3 = mvlh(REGTMPT, REGLINK);
+ o4 = 0;
+ if(high(rt)){
+ rt -= 8;
+ o4 |= 1<<6;
+ }
+ o4 |= (0x8e<<7) | (rt<<3);
+ // o1 = (0x11c<<6) | (rt<<3);
+ break;
+ case 16: /* SWI $I */
+ thumbaclass(&p->to, p);
+ numr(p, instoffset, 0, 255);
+ o1 = (0xdf<<8) | instoffset;
+ break;
+ case 17: /* AWORD */
+ thumbaclass(&p->to, p);
+ o1 = instoffset&0xffff;
+ o2 = (instoffset>>16)&0xffff;
+ break;
+ case 18: /* AMOVW O(SP), R and AMOVW O(PC), R */
+ thumbaclass(&p->from, p);
+ rf = o->param;
+ o1 = rf == REGSP ? 0x13<<11 : 0x9<<11;
+ regis(p, rf, REGSP, REGPC);
+ lowreg(p, rt);
+ mult(p, instoffset, 4);
+ numr(p, instoffset/4, 0, 255);
+ o1 |= (rt<<8) | (instoffset/4);
+ break;
+ case 19: /* AMOVW... O(R), R */
+ thumbaclass(&p->from, p);
+ o1 = thumbopmv(p->as, 1);
+ v = 4;
+ if(p->as == AMOVHU)
+ v = 2;
+ else if(p->as == AMOVBU)
+ v = 1;
+ mult(p, instoffset, v);
+ lowreg(p, rf);
+ lowreg(p, rt);
+ numr(p, instoffset/v, 0, 31);
+ o1 |= ((instoffset/v)<<6) | (rf<<3) | rt;
+ break;
+ case 20: /* AMOVW R, O(SP) */
+ thumbaclass(&p->to, p);
+ o1 = 0x12<<11;
+ if(rt != NREG) regis(p, rt, REGSP, REGSP);
+ lowreg(p, rf);
+ mult(p, instoffset, 4);
+ numr(p, instoffset/4, 0, 255);
+ o1 |= (rf<<8) | (instoffset/4);
+ break;
+ case 21: /* AMOVW... R, O(R) */
+ thumbaclass(&p->to, p);
+ o1 = thumbopmv(p->as, 0);
+ v = 4;
+ if(p->as == AMOVHU || p->as == AMOVH)
+ v = 2;
+ else if(p->as == AMOVBU || p->as == AMOVB)
+ v = 1;
+ lowreg(p, rf);
+ lowreg(p, rt);
+ mult(p, instoffset, v);
+ numr(p, instoffset/v, 0, 31);
+ o1 |= ((instoffset/v)<<6) | (rt<<3) | rf;
+ break;
+ case 22: /* AMOVW R, R -> ASLL $0, R, R */
+ o1 = thumbopri(ASLL);
+ lowreg(p, rf);
+ lowreg(p, rt);
+ o1 |= (0x0<<13) | (rf<<3) | rt;
+ break;
+ case 23: /* AMOVB/AMOVH/AMOVBU/AMOVHU R, R */
+ o1 = thumbopri(ASLL);
+ o2 = p->as == AMOVB || p->as == AMOVH ? thumbopri(ASRA) : thumbopri(ASRL);
+ v = p->as == AMOVB || p->as == AMOVBU ? 24 : 16;
+ lowreg(p, rf);
+ lowreg(p, rt);
+ o1 |= (0x0<<13) | (v<<6) | (rf<<3) | rt;
+ o2 |= (0x0<<13) | (v<<6) | (rt<<3) | rt;
+ break;
+ case 24: /* AMOVH/AMOVB O(R), R -> AMOVH/AMOVB [R, R], R */
+ thumbaclass(&p->from, p);
+ lowreg(p, rf);
+ lowreg(p, rt);
+ if(rf == rt)
+ r = REGTMPT;
+ else
+ r = rt;
+ if(p->as == AMOVB)
+ numr(p, instoffset, 0, 31);
+ else{
+ mult(p, instoffset, 2);
+ numr(p, instoffset, 0, 62);
+ }
+ o1 = mv(p, r, instoffset);
+ o2 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9;
+ o2 |= (r<<6) | (rf<<3) | rt;
+ break;
+ case 25: /* MOVW $sacon, R */
+ thumbaclass(&p->from, p);
+// print("25: %d %d %d %d\n", instoffset, rf, r, rt);
+ if(rf == NREG)
+ rf = REGSP;
+ lowreg(p, rt);
+ if(rf == REGSP){
+ mult(p, instoffset, 4);
+ numr(p, instoffset>>2, 0, 255);
+ o1 = (0x15<<11) | (rt<<8) | (instoffset>>2); // add $O, SP, R
+ }
+ else if(rf == rt){
+ numr(p, instoffset, 0, 255);
+ o1 = (0x6<<11) | (rt<<8) | instoffset; // add $O, R
+ }
+ else{
+ lowreg(p, rf);
+ numr(p, instoffset, 0, 7);
+ o1 = (0xe<<9) | (instoffset<<6) | (rf<<3) | rt; // add $O, Rs, Rd
+ }
+ break;
+ case 26: /* AMOVM $c, oreg -> stmia */
+ lowreg(p, rt);
+ numr(p, p->from.offset, -256, 255);
+ o1 = (0x18<<11) | (rt<<8) | (p->from.offset&0xff);
+ break;
+ case 27: /* AMOVM oreg, $c ->ldmia */
+ lowreg(p, rf);
+ numr(p, p->to.offset, -256, 256);
+ o1 = (0x19<<11) | (rf<<8) | (p->to.offset&0xff);
+ break;
+ case 28: /* AMOV* O(R), R -> AMOV* [R, R], R (offset large) */
+ thumbaclass(&p->from, p);
+ lowreg(p, rf);
+ lowreg(p, rt);
+ if(rf == rt)
+ r = REGTMPT;
+ else
+ r = rt;
+ o1 = mv(p, r, instoffset);
+ o2 = thumboprrr(p->as, 1);
+ o2 |= (r<<6) | (rf<<3) | rt;
+ break;
+ case 29: /* AMOV* R, O(R) -> AMOV* R, [R, R] (offset large) */
+ thumbaclass(&p->to, p);
+ lowreg(p, rf);
+ lowreg(p, rt);
+ if(rt == REGTMPT){ // used as tmp reg
+ if(instoffset >= 0 && instoffset <= 255){
+ o1 = (1<<13) | (2<<11) | (rt<<8) | instoffset; // add $O, R7
+ o2 = thumbopirr(p->as, 0);
+ o2 |= (0<<6) | (rt<<3) | rf; // mov* R, 0(R)
+ }
+ else
+ diag("big offset - case 29");
+ }
+ else{
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = thumboprrr(p->as, 0);
+ o2 |= (REGTMPT<<6) | (rt<<3) | rf;
+ }
+ break;
+ case 30: /* AMOVW... *addr, R */
+ thumbaclass(&p->from, p);
+ o1 = mv(p, rt, instoffset); // MOV addr, rtmp
+ o2 = thumbopmv(p->as, 1);
+ lowreg(p, rt);
+ o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R
+ break;
+ case 31: /* AMOVW... R, *addr */
+ thumbaclass(&p->to, p);
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = thumbopmv(p->as, 0);
+ lowreg(p, rf);
+ o2 |= (REGTMPT<<3) | rf;
+ break;
+ case 32: /* AMOVH/AMOVB *addr, R -> AMOVH/AMOVB [R, R], R */
+ thumbaclass(&p->from, p);
+ o1 = mv(p, rt, instoffset);
+ lowreg(p, rt);
+ o2 = mv(nil, REGTMPT, 0);
+ o3 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9;
+ o3 |= (REGTMPT<<6) | (rt<<3) | rt;
+ break;
+ case 33: /* AMOVW O(SP), R (O large) */
+ thumbaclass(&p->from, p);
+ lowreg(p, rt);
+ o1 = mv(p, rt, instoffset);
+ o2 = (0x111<<6) | (REGSP-8)<<3 | rt; // add SP, rt
+ o3 = thumbopmv(p->as, 1);
+ o3 |= (rt<<3) | rt;
+ break;
+ case 34: /* AMOVW R, O(SP) (O large) */
+ thumbaclass(&p->to, p);
+ lowreg(p, rf);
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = (0x111<<6) | (REGSP-8)<<3 | REGTMPT; // add SP, REGTMP
+ o3 = thumbopmv(p->as, 0);
+ o3 |= (REGTMPT<<3) | rf;
+ break;
+ case 35: /* AMOVW $lacon, R */
+ thumbaclass(&p->from, p);
+ lowreg(p, rt);
+ if(rf == NREG)
+ rf = REGSP;
+ if(rf == rt)
+ rf = r = REGTMPT;
+ else
+ r = rt;
+// print("35: io=%d rf=%d rt=%d\n", instoffset, rf, rt);
+ o1 = mv(p, r, instoffset); // mov O, Rd
+ if(high(rf))
+ o2 = (0x44<<8) | (0x1<<6) | ((rf-8)<<3) | rt; // add Rs, Rd
+ else
+ o2 = (0x6<<10) | (rf<<6) | (rt<<3) | rt; // add Rs, Rd
+ break;
+ case 36: /* AADD/ASUB $i, r, r when $i too big */
+ thumbaclass(&p->from, p);
+ lowreg(p, r);
+ lowreg(p, rt);
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
+ o2 |= (REGTMPT<<6) | (r<<3) | rt;
+ break;
+ case 37: /* AADD/ASUB $i, r when $i too big */
+ thumbaclass(&p->from, p);
+ lowreg(p, rt);
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
+ o2 |= (REGTMPT<<6) | (rt<<3) | rt;
+ break;
+ case 38: /* AMOVW $i, r when $i too big */
+ thumbaclass(&p->from, p);
+ lowreg(p, rt);
+ o1 = mv(p, rt, instoffset);
+ break;
+ case 39: /* ACMP $i, r when $i too big */
+ thumbaclass(&p->from, p);
+ lowreg(p, r);
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = (0x10a<<6) | (REGTMPT<<3) | r;
+ break;
+ case 40: /* add, sub $I, SP when $I large*/
+ thumbaclass(&p->from, p);
+ if(p->as == ASUB)
+ instoffset = -instoffset;
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = (0x112<<6) | (REGTMPT<<3) | (REGSP-8);
+ regis(p, rt, REGSP, REGSP);
+ break;
+ case 41: /* BL LBRA */
+ thumbaclass(&p->to, p);
+ o1 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7
+ o2 = mvlh(REGTMPT, REGPC); // mov r7, pc
+ o3 = instoffset&0xffff; // $lab
+ o4 = (instoffset>>16)&0xffff;
+ break;
+ case 42: /* Bcc GBRA */
+ thumbaclass(&p->to, p);
+ o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (6>>1); // bccnot
+ // ab lbra
+ o2 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7
+ o3 = mvlh(REGTMPT, REGPC); // mov r7, pc
+ o4 = instoffset&0xffff; // $lab
+ o5 = (instoffset>>16)&0xffff;
+ break;
+ case 43: /* BL LBRA */
+ thumbaclass(&p->to, p);
+ o1 = mvlh(REGPC, REGTMPT); // mov pc, r7
+ o2 = (0x6<<11) | (REGTMPT<<8) | 10; // add 10, r7
+ o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr
+ o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7
+ o5 = mvlh(REGTMPT, REGPC); // mov r7, pc
+ o6 = instoffset&0xffff; // $lab
+ o7 = (instoffset>>16)&0xffff;
+ break;
+ case 44: /* BX LBRA */
+#ifdef CALLEEBX
+ diag("BX LBRA case");
+#endif
+ thumbaclass(&p->to, p);
+ if(p->to.sym->thumb)
+ instoffset |= 1; // T bit
+ o1 = mvlh(REGPC, REGTMPT); // mov pc, r7
+ o2 = (0x6<<11) | (REGTMPT<<8) | 11; // add 11, r7
+ o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr
+ o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7
+ o5 = (0x11c<<6) | (REGTMPT<<3); // bx r7
+ o6 = instoffset&0xffff; // $lab
+ o7 = (instoffset>>16)&0xffff;
+ break;
+ case 45: /* BX R when returning from fn */
+ o1 = 0;
+ if(high(rt)){
+ rt -= 8;
+ o1 |= 1<<6;
+ }
+ o1 |= (0x8e<<7) | (rt<<3);
+ break;
+ case 46: /* Bcc LBRA */
+ thumbaclass(&p->to, p);
+ o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (0>>1); // bccnot
+ // ab lbra
+ instoffset -= 2;
+ numr(p, instoffset, -2048, 2046);
+ o2 = (0x1c<<11) | ((instoffset>>1)&0x7ff);
+ break;
+ case 47: /* mov $i, R where $i can be built */
+ thumbaclass(&p->from, p);
+ mvcon(p, rt, instoffset, &o1, &o2);
+ break;
+ case 48: /* ACMP $i, r when $i built up */
+ thumbaclass(&p->from, p);
+ lowreg(p, r);
+ mvcon(p, REGTMPT, instoffset, &o1, &o2);
+ o3 = (0x10a<<6) | (REGTMPT<<3) | r;
+ break;
+ case 49: /* AADD $i, r, r when $i is between 0 and 255 - could merge with case 36 */
+ thumbaclass(&p->from, p);
+ lowreg(p, r);
+ lowreg(p, rt);
+ numr(p, instoffset, 0, 255);
+ o1 = mv(p, REGTMPT, instoffset);
+ o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
+ o2 |= (REGTMPT<<6) | (r<<3) | rt;
+ break;
+ case 50: /* ADWORD */
+ thumbaclass(&p->from, p);
+ o1 = instoffset&0xffff;
+ o2 = (instoffset>>16)&0xffff;
+ thumbaclass(&p->to, p);
+ o3 = instoffset&0xffff;
+ o4 = (instoffset>>16)&0xffff;
+ break;
+ case 51: /* BL r */
+ o1 = mvlh(REGPC, REGLINK); // mov pc, lr
+ o2 = mvlh(rt, REGPC); // mov r, pc
+ break;
+ }
+
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 2:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ hputl(o1);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux\t%P\n", v, o1, o2, p);
+ hputl(o1);
+ hputl(o2);
+ break;
+ case 6:
+ if(debug['a'])
+ Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p);
+ hputl(o1);
+ hputl(o2);
+ hputl(o3);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, p);
+ hputl(o1);
+ hputl(o2);
+ hputl(o3);
+ hputl(o4);
+ break;
+ case 10:
+ if(debug['a'])
+ Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, p);
+ hputl(o1);
+ hputl(o2);
+ hputl(o3);
+ hputl(o4);
+ hputl(o5);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
+ hputl(o1);
+ hputl(o2);
+ hputl(o3);
+ hputl(o4);
+ hputl(o5);
+ hputl(o6);
+ break;
+ case 14:
+ if(debug['a'])
+ Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
+ hputl(o1);
+ hputl(o2);
+ hputl(o3);
+ hputl(o4);
+ hputl(o5);
+ hputl(o6);
+ hputl(o7);
+ break;
+ }
+ if(debug['G']){
+ if(o->type == 17){
+ print("%lx: word %ld\n", p->pc, (o2<<16)+o1);
+ return;
+ }
+ if(o->type == 50){
+ print("%lx: word %ld\n", p->pc, (o2<<16)+o1);
+ print("%lx: word %ld\n", p->pc, (o4<<16)+o3);
+ return;
+ }
+ if(o->size > 0) dis(o1, p->pc);
+ if(o->size > 2) dis(o2, p->pc+2);
+ if(o->size > 4) dis(o3, p->pc+4);
+ if(o->size > 6) dis(o4, p->pc+6);
+ if(o->size > 8) dis(o5, p->pc+8);
+ if(o->size > 10) dis(o6, p->pc+10);
+ if(o->size > 12) dis(o7, p->pc+12);
+ // if(o->size > 14) dis(o8, p->pc+14);
+ }
+}
+
+static long
+thumboprr(int a)
+{
+ switch(a) {
+ case AMVN: return 0xf<<6;
+ case ACMP: return 0xa<<6;
+ case ACMN: return 0xb<<6;
+ case ATST: return 0x8<<6;
+ case AADC: return 0x5<<6;
+ case ASBC: return 0x6<<6;
+ case AMUL:
+ case AMULU: return 0xd<<6;
+ case AAND: return 0x0<<6;
+ case AEOR: return 0x1<<6;
+ case AORR: return 0xc<<6;
+ case ABIC: return 0xe<<6;
+ case ASRL: return 0x3<<6;
+ case ASRA: return 0x4<<6;
+ case ASLL: return 0x2<<6;
+ }
+ diag("bad thumbop oprr %d", a);
+ prasm(curp);
+ return 0;
+}
+
+static long
+thumbopirr(int a, int ld)
+{
+ if(ld)
+ diag("load in thumbopirr");
+ switch(a){
+ case AMOVW: return 0xc<<11;
+ case AMOVH:
+ case AMOVHU: return 0x10<<11;
+ case AMOVB:
+ case AMOVBU: return 0xe<<11;
+ }
+ return 0;
+}
+
+static long
+thumboprrr(int a, int ld)
+{
+ if(ld){
+ switch(a){
+ case AMOVW: return 0x2c<<9;
+ case AMOVH: return 0x2f<<9;
+ case AMOVB: return 0x2b<<9;
+ case AMOVHU: return 0x2d<<9;
+ case AMOVBU: return 0x2e<<9;
+ }
+ }
+ else{
+ switch(a){
+ case AMOVW: return 0x28<<9;
+ case AMOVHU:
+ case AMOVH: return 0x29<<9;
+ case AMOVBU:
+ case AMOVB: return 0x2a<<9;
+ }
+ }
+ diag("bad thumbop oprrr %d", a);
+ prasm(curp);
+ return 0;
+}
+
+static long
+thumbopri(int a)
+{
+ switch(a) {
+ case ASRL: return 0x1<<11;
+ case ASRA: return 0x2<<11;
+ case ASLL: return 0x0<<11;
+ case AADD: return 0x2<<11;
+ case ASUB: return 0x3<<11;
+ case AMOVW: return 0x0<<11;
+ case ACMP: return 0x1<<11;
+ }
+ diag("bad thumbop opri %d", a);
+ prasm(curp);
+ return 0;
+}
+
+static long
+thumbophh(int a)
+{
+ switch(a) {
+ case AADD: return 0x0<<8;
+ case AMOVW: return 0x2<<8;
+ case ACMP: return 0x1<<8;
+ }
+ diag("bad thumbop ophh %d", a);
+ prasm(curp);
+ return 0;
+}
+
+static long
+thumbopbra(int a)
+{
+ switch(a) {
+ case ABEQ: return 0x0<<8;
+ case ABNE: return 0x1<<8;
+ case ABCS: return 0x2<<8;
+ case ABHS: return 0x2<<8;
+ case ABCC: return 0x3<<8;
+ case ABLO: return 0x3<<8;
+ case ABMI: return 0x4<<8;
+ case ABPL: return 0x5<<8;
+ case ABVS: return 0x6<<8;
+ case ABVC: return 0x7<<8;
+ case ABHI: return 0x8<<8;
+ case ABLS: return 0x9<<8;
+ case ABGE: return 0xa<<8;
+ case ABLT: return 0xb<<8;
+ case ABGT: return 0xc<<8;
+ case ABLE: return 0xd<<8;
+ }
+ diag("bad thumbop opbra %d", a);
+ prasm(curp);
+ return 0;
+}
+
+static long
+thumbopmv(int a, int ld)
+{
+ switch(a) {
+ case AMOVW: return (ld ? 0xd : 0xc)<<11;
+ case AMOVH:
+ case AMOVHU: return (ld ? 0x11: 0x10)<<11;
+ case AMOVB:
+ case AMOVBU: return (ld ? 0xf : 0xe)<<11;
+ }
+ diag("bad thumbop opmv %d", a);
+ prasm(curp);
+ return 0;
+}
+
+static void
+lowreg(Prog *p, int r)
+{
+ if(high(r))
+ diag("high reg [%P]", p);
+}
+
+static void
+mult(Prog *p, int n, int m)
+{
+ if(m*(n/m) != n)
+ diag("%d not M(%d) [%P]", n, m, p);
+}
+
+static void
+numr(Prog *p, int n, int min, int max)
+{
+ if(n < min || n > max)
+ diag("%d not in %d-%d [%P]", n, min, max, p);
+}
+
+static void
+regis(Prog *p, int r, int r1, int r2)
+{
+ if(r != r1 && r != r2)
+ diag("reg %d not %d or %d [%P]", r, r1, r2, p);
+}
+
+void
+hputl(int n)
+{
+ cbp[1] = n>>8;
+ cbp[0] = n;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+thumbcount()
+{
+ int i, c = 0, t = 0;
+
+ for (i = 0; i < OPCNTSZ; i++)
+ t += opcount[i];
+ if(t == 0)
+ return;
+ for (i = 0; i < OPCNTSZ; i++){
+ c += opcount[i];
+ print("%d: %d %d %d%%\n", i, opcount[i], c, (opcount[i]*100+t/2)/t);
+ }
+}
+
+char *op1[] = { "lsl", "lsr", "asr" };
+char *op2[] = { "add", "sub" };
+char *op3[] = { "movw", "cmp", "add", "sub" };
+char *op4[] = { "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
+ "tst", "neg", "cmp", "cmpn", "or", "mul", "bitc", "movn" };
+char *op5[] = { "add", "cmp", "movw", "bx" };
+char *op6[] = { "smovw", "smovh", "smovb", "lmovb", "lmovw", "lmovhu", "lmovbu", "lmovh" };
+char *op7[] = { "smovw", "lmovw", "smovb", "lmovbu" };
+char *op8[] = { "smovh", "lmovhu" };
+char *op9[] = { "smovw", "lmovw" };
+char *op10[] = { "push", "pop" };
+char *op11[] = { "stmia", "ldmia" };
+
+char *cond[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
+
+#define B(h, l) bits(i, h, l)
+#define IMM(h, l) B(h, l)
+#define REG(h, l) reg(B(h, l))
+#define LHREG(h, l, lh) lhreg(B(h, l), B(lh, lh))
+#define COND(h, l) cond[B(h, l)]
+#define OP1(h, l) op1[B(h, l)]
+#define OP2(h, l) op2[B(h, l)]
+#define OP3(h, l) op3[B(h, l)]
+#define OP4(h, l) op4[B(h, l)]
+#define OP5(h, l) op5[B(h, l)]
+#define OP6(h, l) op6[B(h, l)]
+#define OP7(h, l) op7[B(h, l)]
+#define OP8(h, l) op8[B(h, l)]
+#define OP9(h, l) op9[B(h, l)]
+#define OP10(h, l) op10[B(h, l)]
+#define OP11(h, l) op11[B(h, l)]
+#define SBZ(h, l) if(IMM(h, l) != 0) diag("%x: %x bits %d,%d not zero", pc, i, h, l)
+#define SNBZ(h, l) if(IMM(h, l) == 0) diag("%x: %x bits %d,%d zero", pc, i, h, l)
+#define SBO(h, l) if(IMM(h, l) != 1) diag("%x: %x bits %d,%d not one", pc, i, h, l)
+
+static int
+bits(int i, int h, int l)
+{
+ if(h < l)
+ diag("h < l in bits");
+ return (i&(((1<<(h-l+1))-1)<<l))>>l;
+}
+
+static char *
+reg(int r)
+{
+ static char s[4][4];
+ static int i = 0;
+
+ if(r < 0 || r > 7)
+ diag("register %d out of range", r);
+ i++;
+ if(i == 4)
+ i = 0;
+ sprint(s[i], "r%d", r);
+ return s[i];
+}
+
+static char *regnames[] = { "sp", "lr", "pc" };
+
+static char *
+lhreg(int r, int lh)
+{
+ static char s[4][4];
+ static int i = 0;
+
+ if(lh == 0)
+ return reg(r);
+ if(r < 0 || r > 7)
+ diag("high register %d out of range", r);
+ i++;
+ if(i == 4)
+ i = 0;
+ if(r >= 5)
+ sprint(s[i], "%s", regnames[r-5]);
+ else
+ sprint(s[i], "r%d", r+8);
+ return s[i];
+}
+
+static void
+illegal(int i, int pc)
+{
+ diag("%x: %x illegal instruction", pc, i);
+}
+
+static void
+dis(int i, int pc)
+{
+ static int lasto;
+ int o, l;
+ char *op;
+
+ print("%x: %x: ", pc, i);
+ if(i&0xffff0000)
+ illegal(i, pc);
+ o = B(15, 13);
+ switch(o){
+ case 0:
+ o = B(12, 11);
+ switch(o){
+ case 0:
+ case 1:
+ case 2:
+ print("%s %d, %s, %s\n", OP1(12, 11), IMM(10, 6), REG(5, 3), REG(2, 0));
+ return;
+ case 3:
+ if(B(10, 10) == 0)
+ print("%s %s, %s, %s\n", OP2(9, 9), REG(8, 6), REG(5, 3), REG(2, 0));
+ else
+ print("%s %d, %s, %s\n", OP2(9, 9), IMM(8, 6), REG(5, 3), REG(2, 0));
+ return;
+ }
+ case 1:
+ print("%s %d, %s\n", OP3(12, 11), IMM(7, 0), REG(10, 8));
+ return;
+ case 2:
+ o = B(12, 10);
+ if(o == 0){
+ print("%s %s, %s\n", OP4(9, 6), REG(5, 3), REG(2, 0));
+ return;
+ }
+ if(o == 1){
+ o = B(9, 8);
+ if(o == 3){
+ SBZ(7, 7);
+ SBZ(2, 0);
+ print("%s %s\n", OP5(9, 8), LHREG(5, 3, 6));
+ return;
+ }
+ SNBZ(7, 6);
+ print("%s %s, %s\n", OP5(9, 8), LHREG(5, 3, 6), LHREG(2, 0, 7));
+ return;
+ }
+ if(o == 2 || o == 3){
+ print("movw %d(pc)[%x], %s\n", 4*IMM(7, 0), 4*IMM(7, 0)+pc+4, REG(10, 8));
+ return;
+ }
+ op = OP6(11, 9);
+ if(*op == 'l')
+ print("%s [%s, %s], %s\n", op+1, REG(8, 6), REG(5, 3), REG(2, 0));
+ else
+ print("%s %s, [%s, %s]\n", op+1, REG(2, 0), REG(8, 6), REG(5, 3));
+ return;
+ case 3:
+ op = OP7(12, 11);
+ if(B(12, 11) == 0 || B(12,11) == 1)
+ l = 4;
+ else
+ l = 1;
+ if(*op == 'l')
+ print("%s %d(%s), %s\n", op+1, l*IMM(10, 6), REG(5, 3), REG(2, 0));
+ else
+ print("%s %s, %d(%s)\n", op+1, REG(2, 0), l*IMM(10, 6), REG(5, 3));
+ return;
+ case 4:
+ if(B(12, 12) == 0){
+ op = OP8(11, 11);
+ if(*op == 'l')
+ print("%s %d(%s), %s\n", op+1, 2*IMM(10, 6), REG(5, 3), REG(2, 0));
+ else
+ print("%s %s, %d(%s)\n", op+1, REG(2, 0), 2*IMM(10, 6), REG(5, 3));
+ return;
+ }
+ op = OP9(11, 11);
+ if(*op == 'l')
+ print("%s %d(sp), %s\n", op+1, 4*IMM(7, 0), REG(10, 8));
+ else
+ print("%s %s, %d(sp)\n", op+1, REG(10, 8), 4*IMM(7, 0));
+ return;
+ case 5:
+ if(B(12, 12) == 0){
+ if(B(11, 11) == 0)
+ print("add %d, pc, %s\n", 4*IMM(7, 0), REG(10, 8));
+ else
+ print("add %d, sp, %s\n", 4*IMM(7, 0), REG(10, 8));
+ return;
+ }
+ if(B(11, 8) == 0){
+ print("%s %d, sp\n", OP2(7, 7), 4*IMM(6, 0));
+ return;
+ }
+ SBO(10, 10);
+ SBZ(9, 9);
+ if(B(8, 8) == 0)
+ print("%s sp, %d\n", OP10(11, 11), IMM(7, 0));
+ else
+ print("%s sp, %d|15\n", OP10(11, 11), IMM(7, 0));
+ return;
+ case 6:
+ if(B(12, 12) == 0){
+ print("%s %s, %d\n", OP11(11, 11), REG(10, 8), IMM(7, 0));
+ return;
+ }
+ if(B(11, 8) == 0xf){
+ print("swi %d\n", IMM(7, 0));
+ return;
+ }
+ o = IMM(7, 0);
+ if(o&0x80)
+ o |= 0xffffff00;
+ o = pc+4+(o<<1);
+ print("b%s %x\n", COND(11, 8), o);
+ return;
+ case 7:
+ o = B(12, 11);
+ switch(o){
+ case 0:
+ o = IMM(10, 0);
+ if(o&0x400)
+ o |= 0xfffff800;
+ o = pc+4+(o<<1);
+ print("b %x\n", o);
+ return;
+ case 1:
+ illegal(i, pc);
+ return;
+ case 2:
+ lasto = IMM(10, 0);
+ print("bl\n");
+ return;
+ case 3:
+ if(lasto&0x400)
+ lasto |= 0xfffff800;
+ o = IMM(10, 0);
+ o = (pc-2)+4+(o<<1)+(lasto<<12);
+ print("bl %x\n", o);
+ return;
+ }
+ }
+}
diff --git a/utils/6c/6.out.h b/utils/6c/6.out.h
new file mode 100644
index 00000000..0766ea3d
--- /dev/null
+++ b/utils/6c/6.out.h
@@ -0,0 +1,820 @@
+#define NSYM 50
+#define NSNAME 8
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+/*
+ * amd64
+ */
+
+enum as
+{
+ AXXX,
+ AAAA,
+ AAAD,
+ AAAM,
+ AAAS,
+ AADCB,
+ AADCL,
+ AADCW,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AARPL,
+ ABOUNDL,
+ ABOUNDW,
+ ABSFL,
+ ABSFW,
+ ABSRL,
+ ABSRW,
+ ABTL,
+ ABTW,
+ ABTCL,
+ ABTCW,
+ ABTRL,
+ ABTRW,
+ ABTSL,
+ ABTSW,
+ ABYTE,
+ ACALL,
+ ACLC,
+ ACLD,
+ ACLI,
+ ACLTS,
+ ACMC,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ACMPSB,
+ ACMPSL,
+ ACMPSW,
+ ADAA,
+ ADAS,
+ ADATA,
+ ADECB,
+ ADECL,
+ ADECQ,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ AINCQ,
+ AINCW,
+ AINSB,
+ AINSL,
+ AINSW,
+ AINT,
+ AINTO,
+ AIRETL,
+ AIRETW,
+ AJCC,
+ AJCS,
+ AJCXZ,
+ AJEQ,
+ AJGE,
+ AJGT,
+ AJHI,
+ AJLE,
+ AJLS,
+ AJLT,
+ AJMI,
+ AJMP,
+ AJNE,
+ AJOC,
+ AJOS,
+ AJPC,
+ AJPL,
+ AJPS,
+ ALAHF,
+ ALARL,
+ ALARW,
+ ALEAL,
+ ALEAW,
+ ALEAVEL,
+ ALEAVEW,
+ ALOCK,
+ ALODSB,
+ ALODSL,
+ ALODSW,
+ ALONG,
+ ALOOP,
+ ALOOPEQ,
+ ALOOPNE,
+ ALSLL,
+ ALSLW,
+ AMOVB,
+ AMOVL,
+ AMOVW,
+ AMOVBLSX,
+ AMOVBLZX,
+ AMOVBQSX,
+ AMOVBQZX,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ AMOVWQSX,
+ AMOVWQZX,
+ AMOVSB,
+ AMOVSL,
+ AMOVSW,
+ AMULB,
+ AMULL,
+ AMULW,
+ ANAME,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ AOUTB,
+ AOUTL,
+ AOUTW,
+ AOUTSB,
+ AOUTSL,
+ AOUTSW,
+ APOPAL,
+ APOPAW,
+ APOPFL,
+ APOPFW,
+ APOPL,
+ APOPW,
+ APUSHAL,
+ APUSHAW,
+ APUSHFL,
+ APUSHFW,
+ APUSHL,
+ APUSHW,
+ ARCLB,
+ ARCLL,
+ ARCLW,
+ ARCRB,
+ ARCRL,
+ ARCRW,
+ AREP,
+ AREPN,
+ ARET,
+ AROLB,
+ AROLL,
+ AROLW,
+ ARORB,
+ ARORL,
+ ARORW,
+ ASAHF,
+ ASALB,
+ ASALL,
+ ASALW,
+ ASARB,
+ ASARL,
+ ASARW,
+ ASBBB,
+ ASBBL,
+ ASBBW,
+ ASCASB,
+ ASCASL,
+ ASCASW,
+ ASETCC,
+ ASETCS,
+ ASETEQ,
+ ASETGE,
+ ASETGT,
+ ASETHI,
+ ASETLE,
+ ASETLS,
+ ASETLT,
+ ASETMI,
+ ASETNE,
+ ASETOC,
+ ASETOS,
+ ASETPC,
+ ASETPL,
+ ASETPS,
+ ACDQ,
+ ACWD,
+ ASHLB,
+ ASHLL,
+ ASHLW,
+ ASHRB,
+ ASHRL,
+ ASHRW,
+ ASTC,
+ ASTD,
+ ASTI,
+ ASTOSB,
+ ASTOSL,
+ ASTOSW,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASYSCALL,
+ ATESTB,
+ ATESTL,
+ ATESTW,
+ ATEXT,
+ AVERR,
+ AVERW,
+ AWAIT,
+ AWORD,
+ AXCHGB,
+ AXCHGL,
+ AXCHGW,
+ AXLAT,
+ AXORB,
+ AXORL,
+ AXORW,
+
+ AFMOVB,
+ AFMOVBP,
+ AFMOVD,
+ AFMOVDP,
+ AFMOVF,
+ AFMOVFP,
+ AFMOVL,
+ AFMOVLP,
+ AFMOVV,
+ AFMOVVP,
+ AFMOVW,
+ AFMOVWP,
+ AFMOVX,
+ AFMOVXP,
+
+ AFCOMB,
+ AFCOMBP,
+ AFCOMD,
+ AFCOMDP,
+ AFCOMDPP,
+ AFCOMF,
+ AFCOMFP,
+ AFCOML,
+ AFCOMLP,
+ AFCOMW,
+ AFCOMWP,
+ AFUCOM,
+ AFUCOMP,
+ AFUCOMPP,
+
+ AFADDDP,
+ AFADDW,
+ AFADDL,
+ AFADDF,
+ AFADDD,
+
+ AFMULDP,
+ AFMULW,
+ AFMULL,
+ AFMULF,
+ AFMULD,
+
+ AFSUBDP,
+ AFSUBW,
+ AFSUBL,
+ AFSUBF,
+ AFSUBD,
+
+ AFSUBRDP,
+ AFSUBRW,
+ AFSUBRL,
+ AFSUBRF,
+ AFSUBRD,
+
+ AFDIVDP,
+ AFDIVW,
+ AFDIVL,
+ AFDIVF,
+ AFDIVD,
+
+ AFDIVRDP,
+ AFDIVRW,
+ AFDIVRL,
+ AFDIVRF,
+ AFDIVRD,
+
+ AFXCHD,
+ AFFREE,
+
+ AFLDCW,
+ AFLDENV,
+ AFRSTOR,
+ AFSAVE,
+ AFSTCW,
+ AFSTENV,
+ AFSTSW,
+
+ AF2XM1,
+ AFABS,
+ AFCHS,
+ AFCLEX,
+ AFCOS,
+ AFDECSTP,
+ AFINCSTP,
+ AFINIT,
+ AFLD1,
+ AFLDL2E,
+ AFLDL2T,
+ AFLDLG2,
+ AFLDLN2,
+ AFLDPI,
+ AFLDZ,
+ AFNOP,
+ AFPATAN,
+ AFPREM,
+ AFPREM1,
+ AFPTAN,
+ AFRNDINT,
+ AFSCALE,
+ AFSIN,
+ AFSINCOS,
+ AFSQRT,
+ AFTST,
+ AFXAM,
+ AFXTRACT,
+ AFYL2X,
+ AFYL2XP1,
+
+ AEND,
+
+ ADYNT,
+ AINIT,
+
+ ASIGNAME,
+
+ /* extra 32-bit operations */
+ ACMPXCHGB,
+ ACMPXCHGL,
+ ACMPXCHGW,
+ ACMPXCHG8B,
+ ACPUID,
+ AINVD,
+ AINVLPG,
+ ALFENCE,
+ AMFENCE,
+ AMOVNTIL,
+ ARDMSR,
+ ARDPMC,
+ ARDTSC,
+ ARSM,
+ ASFENCE,
+ ASYSRET,
+ AWBINVD,
+ AWRMSR,
+ AXADDB,
+ AXADDL,
+ AXADDW,
+
+ /* conditional move */
+ ACMOVLCC,
+ ACMOVLCS,
+ ACMOVLEQ,
+ ACMOVLGE,
+ ACMOVLGT,
+ ACMOVLHI,
+ ACMOVLLE,
+ ACMOVLLS,
+ ACMOVLLT,
+ ACMOVLMI,
+ ACMOVLNE,
+ ACMOVLOC,
+ ACMOVLOS,
+ ACMOVLPC,
+ ACMOVLPL,
+ ACMOVLPS,
+ ACMOVQCC,
+ ACMOVQCS,
+ ACMOVQEQ,
+ ACMOVQGE,
+ ACMOVQGT,
+ ACMOVQHI,
+ ACMOVQLE,
+ ACMOVQLS,
+ ACMOVQLT,
+ ACMOVQMI,
+ ACMOVQNE,
+ ACMOVQOC,
+ ACMOVQOS,
+ ACMOVQPC,
+ ACMOVQPL,
+ ACMOVQPS,
+ ACMOVWCC,
+ ACMOVWCS,
+ ACMOVWEQ,
+ ACMOVWGE,
+ ACMOVWGT,
+ ACMOVWHI,
+ ACMOVWLE,
+ ACMOVWLS,
+ ACMOVWLT,
+ ACMOVWMI,
+ ACMOVWNE,
+ ACMOVWOC,
+ ACMOVWOS,
+ ACMOVWPC,
+ ACMOVWPL,
+ ACMOVWPS,
+
+ /* 64-bit */
+ AADCQ,
+ AADDQ,
+ AANDQ,
+ ABSFQ,
+ ABSRQ,
+ ABTCQ,
+ ABTQ,
+ ABTRQ,
+ ABTSQ,
+ ACMPQ,
+ ACMPSQ,
+ ACMPXCHGQ,
+ ACQO,
+ ADIVQ,
+ AIDIVQ,
+ AIMULQ,
+ AIRETQ,
+ ALEAQ,
+ ALEAVEQ,
+ ALODSQ,
+ AMOVQ,
+ AMOVLQSX,
+ AMOVLQZX,
+ AMOVNTIQ,
+ AMOVSQ,
+ AMULQ,
+ ANEGQ,
+ ANOTQ,
+ AORQ,
+ APOPFQ,
+ APOPQ,
+ APUSHFQ,
+ APUSHQ,
+ ARCLQ,
+ ARCRQ,
+ AROLQ,
+ ARORQ,
+ AQUAD,
+ ASALQ,
+ ASARQ,
+ ASBBQ,
+ ASCASQ,
+ ASHLQ,
+ ASHRQ,
+ ASTOSQ,
+ ASUBQ,
+ ATESTQ,
+ AXADDQ,
+ AXCHGQ,
+ AXORQ,
+
+ /* media */
+ AADDPD,
+ AADDPS,
+ AADDSD,
+ AADDSS,
+ AANDNPD,
+ AANDNPS,
+ AANDPD,
+ AANDPS,
+ ACMPPD,
+ ACMPPS,
+ ACMPSD,
+ ACMPSS,
+ ACOMISD,
+ ACOMISS,
+ ACVTPD2PL,
+ ACVTPD2PS,
+ ACVTPL2PD,
+ ACVTPL2PS,
+ ACVTPS2PD,
+ ACVTPS2PL,
+ ACVTSD2SL,
+ ACVTSD2SQ,
+ ACVTSD2SS,
+ ACVTSL2SD,
+ ACVTSL2SS,
+ ACVTSQ2SD,
+ ACVTSQ2SS,
+ ACVTSS2SD,
+ ACVTSS2SL,
+ ACVTSS2SQ,
+ ACVTTPD2PL,
+ ACVTTPS2PL,
+ ACVTTSD2SL,
+ ACVTTSD2SQ,
+ ACVTTSS2SL,
+ ACVTTSS2SQ,
+ ADIVPD,
+ ADIVPS,
+ ADIVSD,
+ ADIVSS,
+ AEMMS,
+ AFXRSTOR,
+ AFXRSTOR64,
+ AFXSAVE,
+ AFXSAVE64,
+ ALDMXCSR,
+ AMASKMOVOU,
+ AMASKMOVQ,
+ AMAXPD,
+ AMAXPS,
+ AMAXSD,
+ AMAXSS,
+ AMINPD,
+ AMINPS,
+ AMINSD,
+ AMINSS,
+ AMOVAPD,
+ AMOVAPS,
+ AMOVOU,
+ AMOVHLPS,
+ AMOVHPD,
+ AMOVHPS,
+ AMOVLHPS,
+ AMOVLPD,
+ AMOVLPS,
+ AMOVMSKPD,
+ AMOVMSKPS,
+ AMOVNTO,
+ AMOVNTPD,
+ AMOVNTPS,
+ AMOVNTQ,
+ AMOVO,
+ AMOVQOZX,
+ AMOVSD,
+ AMOVSS,
+ AMOVUPD,
+ AMOVUPS,
+ AMULPD,
+ AMULPS,
+ AMULSD,
+ AMULSS,
+ AORPD,
+ AORPS,
+ APACKSSLW,
+ APACKSSWB,
+ APACKUSWB,
+ APADDB,
+ APADDL,
+ APADDQ,
+ APADDSB,
+ APADDSW,
+ APADDUSB,
+ APADDUSW,
+ APADDW,
+ APANDB,
+ APANDL,
+ APANDSB,
+ APANDSW,
+ APANDUSB,
+ APANDUSW,
+ APANDW,
+ APAND,
+ APANDN,
+ APAVGB,
+ APAVGW,
+ APCMPEQB,
+ APCMPEQL,
+ APCMPEQW,
+ APCMPGTB,
+ APCMPGTL,
+ APCMPGTW,
+ APEXTRW,
+ APFACC,
+ APFADD,
+ APFCMPEQ,
+ APFCMPGE,
+ APFCMPGT,
+ APFMAX,
+ APFMIN,
+ APFMUL,
+ APFNACC,
+ APFPNACC,
+ APFRCP,
+ APFRCPIT1,
+ APFRCPI2T,
+ APFRSQIT1,
+ APFRSQRT,
+ APFSUB,
+ APFSUBR,
+ APINSRW,
+ APMADDWL,
+ APMAXSW,
+ APMAXUB,
+ APMINSW,
+ APMINUB,
+ APMOVMSKB,
+ APMULHRW,
+ APMULHUW,
+ APMULHW,
+ APMULLW,
+ APMULULQ,
+ APOR,
+ APSADBW,
+ APSHUFHW,
+ APSHUFL,
+ APSHUFLW,
+ APSHUFW,
+ APSLLO,
+ APSLLL,
+ APSLLQ,
+ APSLLW,
+ APSRAL,
+ APSRAW,
+ APSRLO,
+ APSRLL,
+ APSRLQ,
+ APSRLW,
+ APSUBB,
+ APSUBL,
+ APSUBQ,
+ APSUBSB,
+ APSUBSW,
+ APSUBUSB,
+ APSUBUSW,
+ APSUBW,
+ APSWAPL,
+ APUNPCKHBW,
+ APUNPCKHLQ,
+ APUNPCKHQDQ,
+ APUNPCKHWL,
+ APUNPCKLBW,
+ APUNPCKLLQ,
+ APUNPCKLQDQ,
+ APUNPCKLWL,
+ APXOR,
+ ARCPPS,
+ ARCPSS,
+ ARSQRTPS,
+ ARSQRTSS,
+ ASHUFPD,
+ ASHUFPS,
+ ASQRTPD,
+ ASQRTPS,
+ ASQRTSD,
+ ASQRTSS,
+ ASTMXCSR,
+ ASUBPD,
+ ASUBPS,
+ ASUBSD,
+ ASUBSS,
+ AUCOMISD,
+ AUCOMISS,
+ AUNPCKHPD,
+ AUNPCKHPS,
+ AUNPCKLPD,
+ AUNPCKLPS,
+ AXORPD,
+ AXORPS,
+
+ APF2IW,
+ APF2IL,
+ API2FW,
+ API2FL,
+ ARETFW,
+ ARETFL,
+ ARETFQ,
+ ASWAPGS,
+
+ AMODE,
+
+ ALAST
+};
+
+enum
+{
+
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+ D_SPB,
+ D_BPB,
+ D_SIB,
+ D_DIB,
+ D_R8B,
+ D_R9B,
+ D_R10B,
+ D_R11B,
+ D_R12B,
+ D_R13B,
+ D_R14B,
+ D_R15B,
+
+ D_AX = 16,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+ D_R8,
+ D_R9,
+ D_R10,
+ D_R11,
+ D_R12,
+ D_R13,
+ D_R14,
+ D_R15,
+
+ D_AH = 32,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_F0 = 36,
+
+ D_M0 = 44,
+
+ D_X0 = 52,
+
+ D_CS = 68,
+ D_SS,
+ D_DS,
+ D_ES,
+ D_FS,
+ D_GS,
+
+ D_GDTR, /* global descriptor table register */
+ D_IDTR, /* interrupt descriptor table register */
+ D_LDTR, /* local descriptor table register */
+ D_MSW, /* machine status word */
+ D_TASK, /* task register */
+
+ D_CR = 79,
+ D_DR = 95,
+ D_TR = 103,
+
+ D_NONE = 111,
+
+ D_BRANCH = 112,
+ D_EXTERN = 113,
+ D_STATIC = 114,
+ D_AUTO = 115,
+ D_PARAM = 116,
+ D_CONST = 117,
+ D_FCONST = 118,
+ D_SCONST = 119,
+ D_ADDR = 120,
+
+ D_FILE,
+ D_FILE1,
+
+ D_INDIR, /* additive */
+
+ T_TYPE = 1<<0,
+ T_INDEX = 1<<1,
+ T_OFFSET = 1<<2,
+ T_FCONST = 1<<3,
+ T_SYM = 1<<4,
+ T_SCONST = 1<<5,
+ T_64 = 1<<6,
+
+ REGARG = D_BP, /* MIGHT CHANGE */
+ REGRET = D_AX,
+ FREGRET = D_X0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+ REGEXT = D_R15, /* compiler allocates external registers R15 down */
+ FREGMIN = D_X0+5, /* first register variable */
+ FREGEXT = D_X0+7 /* first external register */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/8a/a.h b/utils/8a/a.h
new file mode 100644
index 00000000..82afc593
--- /dev/null
+++ b/utils/8a/a.h
@@ -0,0 +1,194 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../8c/8.out.h"
+
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Ref Ref;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Gen2 Gen2;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ Ref* ref;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct Ref
+{
+ int class;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ double dval;
+ char sval[8];
+ long offset;
+ Sym* sym;
+ short type;
+ short index;
+ short scale;
+};
+struct Gen2
+{
+ Gen from;
+ Gen to;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void checkscale(int);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen2*);
+void outhist(void);
+void zaddr(Gen*, int);
+void zname(char*, int, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * Posix.c/Inferno.c/Nt.c
+ */
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/8a/a.y b/utils/8a/a.y
new file mode 100644
index 00000000..167234b4
--- /dev/null
+++ b/utils/8a/a.y
@@ -0,0 +1,520 @@
+%{
+#include "a.h"
+%}
+%union {
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI
+%token <lval> LCONST LFP LPC LSB
+%token <lval> LBREG LLREG LSREG LFREG
+%token <dval> LFCONST
+%token <sval> LSCONST LSP
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset
+%type <gen> mem imm reg nam rel rem rim rom omem nmem
+%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
+%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+ LNAME '=' expr
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LTYPE0 nonnon { outcode($1, &$2); }
+| LTYPE1 nonrem { outcode($1, &$2); }
+| LTYPE2 rimnon { outcode($1, &$2); }
+| LTYPE3 rimrem { outcode($1, &$2); }
+| LTYPE4 remrim { outcode($1, &$2); }
+| LTYPER nonrel { outcode($1, &$2); }
+| LTYPED spec1 { outcode($1, &$2); }
+| LTYPET spec2 { outcode($1, &$2); }
+| LTYPEC spec3 { outcode($1, &$2); }
+| LTYPEN spec4 { outcode($1, &$2); }
+| LTYPES spec5 { outcode($1, &$2); }
+| LTYPEM spec6 { outcode($1, &$2); }
+| LTYPEI spec7 { outcode($1, &$2); }
+
+nonnon:
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+| ','
+ {
+ $$.from = nullgen;
+ $$.to = nullgen;
+ }
+
+rimrem:
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+remrim:
+ rem ',' rim
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+rimnon:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+
+nonrem:
+ ',' rem
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rem
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+nonrel:
+ ',' rel
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rel
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec1: /* DATA */
+ nam '/' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec2: /* TEXT */
+ mem ',' imm
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| mem ',' con ',' imm
+ {
+ $$.from = $1;
+ $$.from.scale = $3;
+ $$.to = $5;
+ }
+
+spec3: /* JMP/CALL */
+ ',' rom
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ }
+| rom
+ {
+ $$.from = nullgen;
+ $$.to = $1;
+ }
+
+spec4: /* NOP */
+ nonnon
+| nonrem
+
+spec5: /* SHL/SHR */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LLREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.from.index != D_NONE)
+ yyerror("dp shift with lhs index");
+ $$.from.index = $5;
+ }
+
+spec6: /* MOVW/MOVL */
+ rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+| rim ',' rem ':' LSREG
+ {
+ $$.from = $1;
+ $$.to = $3;
+ if($$.to.index != D_NONE)
+ yyerror("dp move with lhs index");
+ $$.to.index = $5;
+ }
+
+spec7:
+ rim ','
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim
+ {
+ $$.from = $1;
+ $$.to = nullgen;
+ }
+| rim ',' rem
+ {
+ $$.from = $1;
+ $$.to = $3;
+ }
+
+rem:
+ reg
+| mem
+
+rom:
+ rel
+| nmem
+| '*' reg
+ {
+ $$ = $2;
+ }
+| '*' omem
+ {
+ $$ = $2;
+ }
+| reg
+| omem
+
+rim:
+ rem
+| imm
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+reg:
+ LBREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LFREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LLREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+| LSP
+ {
+ $$ = nullgen;
+ $$.type = D_SP;
+ }
+| LSREG
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ }
+
+imm:
+ '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' nam
+ {
+ $$ = $2;
+ $$.index = $2.type;
+ $$.type = D_ADDR;
+ /*
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ */
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '(' LFCONST ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $3;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+mem:
+ omem
+| nmem
+
+omem:
+ con
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ }
+| con '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
+| con '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ $$.offset = $1;
+ }
+| con '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.offset = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+| con '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ $$.index = $6;
+ $$.scale = $8;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ }
+| '(' LSP ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_SP;
+ }
+| '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+D_NONE;
+ $$.index = $2;
+ $$.scale = $4;
+ checkscale($$.scale);
+ }
+| '(' LLREG ')' '(' LLREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$2;
+ $$.index = $5;
+ $$.scale = $7;
+ checkscale($$.scale);
+ }
+
+nmem:
+ nam
+ {
+ $$ = $1;
+ }
+| nam '(' LLREG '*' con ')'
+ {
+ $$ = $1;
+ $$.index = $3;
+ $$.scale = $5;
+ checkscale($$.scale);
+ }
+
+nam:
+ LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+ {
+ $$ = D_AUTO;
+ }
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/8a/l.s b/utils/8a/l.s
new file mode 100644
index 00000000..09980d48
--- /dev/null
+++ b/utils/8a/l.s
@@ -0,0 +1,704 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
+
+#define MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ (20) /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+
+/*
+ * Fundamental addresses
+ */
+
+/*
+ * Address spaces
+ *
+ * User is at 0-2GB
+ * Kernel is at 2GB-4GB
+ *
+ * To avoid an extra page map, both the user stack (USTKTOP) and
+ * the temporary user stack (TSTKTOP) should be in the the same
+ * 4 meg.
+ */
+#define UZERO 0 /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define KZERO 0x80000000 /* base of kernel address space */
+#define KTZERO KZERO /* first address in kernel text */
+#define USERADDR 0xC0000000 /* struct User */
+#define UREGADDR (USERADDR+BY2PG-4*19)
+#define TSTKTOP USERADDR /* end of new stack in sysexec */
+#define TSTKSIZ 10
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */
+#define ROMBIOS (KZERO|0xF0000)
+
+#define MACHSIZE 4096
+
+#define isphys(x) (((ulong)x)&KZERO)
+
+/*
+ * known 80386 segments (in GDT) and their selectors
+ */
+#define NULLSEG 0 /* null segment */
+#define KDSEG 1 /* kernel data/stack */
+#define KESEG 2 /* kernel executable */
+#define UDSEG 3 /* user data/stack */
+#define UESEG 4 /* user executable */
+#define TSSSEG 5 /* task segment */
+
+#define SELGDT (0<<3) /* selector is in gdt */
+#define SELLDT (1<<3) /* selector is in ldt */
+
+#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
+
+#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
+#define KESEL SELECTOR(KESEG, SELGDT, 0)
+#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
+#define UESEL SELECTOR(UESEG, SELGDT, 3)
+#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
+#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
+
+/*
+ * fields in segment descriptors
+ */
+#define SEGDATA (0x10<<8) /* data/stack segment */
+#define SEGEXEC (0x18<<8) /* executable segment */
+#define SEGTSS (0x9<<8) /* TSS segment */
+#define SEGCG (0x0C<<8) /* call gate */
+#define SEGIG (0x0E<<8) /* interrupt gate */
+#define SEGTG (0x0F<<8) /* task gate */
+#define SEGTYPE (0x1F<<8)
+
+#define SEGP (1<<15) /* segment present */
+#define SEGPL(x) ((x)<<13) /* priority level */
+#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
+#define SEGG (1<<23) /* granularity 1==4k (for other) */
+#define SEGE (1<<10) /* expand down */
+#define SEGW (1<<9) /* writable (for data/stack) */
+#define SEGR (1<<9) /* readable (for code) */
+#define SEGD (1<<22) /* default 1==32bit (for code) */
+
+/*
+ * virtual MMU
+ */
+#define PTEMAPMEM (1024*1024) /* ??? */
+#define SEGMAPSIZE 16 /* ??? */
+#define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */
+#define PPN(x) ((x)&~(BY2PG-1))
+
+/*
+ * physical MMU
+ */
+#define PTEVALID (1<<0)
+#define PTEUNCACHED 0 /* everything is uncached */
+#define PTEWRITE (1<<1)
+#define PTERONLY (0<<1)
+#define PTEKERNEL (0<<2)
+#define PTEUSER (1<<2)
+
+/*
+ * flag register bits that we care about
+ */
+#define IFLAG 0x200
+
+#define OP16 BYTE $0x66
+
+/*
+ * about to walk all over ms/dos - turn off interrupts
+ */
+TEXT origin(SB),$0
+
+ CLI
+
+#ifdef BOOT
+/*
+ * This part of l.s is used only in the boot kernel.
+ * It assumes that we are in real address mode, i.e.,
+ * that we look like an 8086.
+ */
+/*
+ * relocate everything to a half meg and jump there
+ * - looks wierd because it is being assembled by a 32 bit
+ * assembler for a 16 bit world
+ */
+ MOVL $0,BX
+ INCL BX
+ SHLL $15,BX
+ MOVL BX,CX
+ MOVW BX,ES
+ MOVL $0,SI
+ MOVL SI,DI
+ CLD; REP; MOVSL
+/* JMPFAR 0X8000:$lowcore(SB) /**/
+ BYTE $0xEA
+ WORD $lowcore(SB)
+ WORD $0X8000
+
+TEXT lowcore(SB),$0
+
+/*
+ * now that we're in low core, update the DS
+ */
+
+ MOVW BX,DS
+
+/*
+ * goto protected mode
+ */
+/* MOVL tgdtptr(SB),GDTR /**/
+ BYTE $0x0f
+ BYTE $0x01
+ BYTE $0x16
+ WORD $tgdtptr(SB)
+ MOVL CR0,AX
+ ORL $1,AX
+ MOVL AX,CR0
+
+/*
+ * clear prefetch queue (wierd code to avoid optimizations)
+ */
+ CLC
+ JCC flush
+ MOVL AX,AX
+flush:
+
+/*
+ * set all segs
+ */
+/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/
+ BYTE $0xc7
+ BYTE $0xc0
+ WORD $SELECTOR(1, SELGDT, 0)
+ MOVW AX,DS
+ MOVW AX,SS
+ MOVW AX,ES
+ MOVW AX,FS
+ MOVW AX,GS
+
+/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
+ BYTE $0x66
+ BYTE $0xEA
+ LONG $mode32bit-KZERO(SB)
+ WORD $SELECTOR(2, SELGDT, 0)
+
+TEXT mode32bit(SB),$0
+
+#endif BOOT
+
+ /*
+ * Clear BSS
+ */
+ LEAL edata-KZERO(SB),SI
+ MOVL SI,DI
+ ADDL $4,DI
+ MOVL $0,AX
+ MOVL AX,(SI)
+ LEAL end-KZERO(SB),CX
+ SUBL DI,CX
+ SHRL $2,CX
+ CLD; REP; MOVSL
+
+ /*
+ * make a bottom level page table page that maps the first
+ * 16 meg of physical memory
+ */
+ LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */
+ ADDL $(BY2PG-1),AX /* must be page alligned */
+ ANDL $(~(BY2PG-1)),AX /* ... */
+ MOVL $(4*1024),CX /* pte's per page */
+ MOVL $((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
+setpte:
+ MOVL BX,-4(AX)(CX*4)
+ SUBL $(1<<PGSHIFT),BX
+ LOOP setpte
+
+ /*
+ * make a top level page table page that maps the first
+ * 16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
+ */
+ MOVL AX,BX
+ ADDL $(4*BY2PG),AX
+ ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX
+ MOVL BX,0(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
+ ADDL $BY2PG,BX
+ MOVL BX,4(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
+ ADDL $BY2PG,BX
+ MOVL BX,8(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
+ ADDL $BY2PG,BX
+ MOVL BX,12(AX)
+ MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)
+
+ /*
+ * point processor to top level page & turn on paging
+ */
+ MOVL AX,CR3
+ MOVL CR0,AX
+ ORL $0X80000000,AX
+ ANDL $~(0x8|0x2),AX /* TS=0, MP=0 */
+ MOVL AX,CR0
+
+ /*
+ * use a jump to an absolute location to get the PC into
+ * KZERO.
+ */
+ LEAL tokzero(SB),AX
+ JMP* AX
+
+TEXT tokzero(SB),$0
+
+ /*
+ * stack and mach
+ */
+ MOVL $mach0(SB),SP
+ MOVL SP,m(SB)
+ MOVL $0,0(SP)
+ ADDL $(MACHSIZE-4),SP /* start stack under machine struct */
+ MOVL $0, u(SB)
+
+ /*
+ * clear flags
+ */
+ MOVL $0,AX
+ PUSHL AX
+ POPFL
+
+ CALL main(SB)
+
+loop:
+ JMP loop
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL u(SB), $4
+GLOBL m(SB), $4
+GLOBL tpt(SB), $(BY2PG*6)
+
+/*
+ * gdt to get us to 32-bit/segmented/unpaged mode
+ */
+TEXT tgdt(SB),$0
+
+ /* null descriptor */
+ LONG $0
+ LONG $0
+
+ /* data segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
+
+ /* exec segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
+
+/*
+ * pointer to initial gdt
+ */
+TEXT tgdtptr(SB),$0
+
+ WORD $(3*8)
+ LONG $tgdt-KZERO(SB)
+
+/*
+ * input a byte
+ */
+TEXT inb(SB),$0
+
+ MOVL p+0(FP),DX
+ XORL AX,AX
+ INB
+ RET
+
+/*
+ * output a byte
+ */
+TEXT outb(SB),$0
+
+ MOVL p+0(FP),DX
+ MOVL b+4(FP),AX
+ OUTB
+ RET
+
+/*
+ * input a string of shorts from a port
+ */
+TEXT inss(SB),$0
+ MOVL p+0(FP),DX
+ MOVL a+4(FP),DI
+ MOVL c+8(FP),CX
+ CLD; REP; OP16; INSL
+ RET
+
+/*
+ * output a string of shorts to a port
+ */
+TEXT outss(SB),$0
+ MOVL p+0(FP),DX
+ MOVL a+4(FP),SI
+ MOVL c+8(FP),CX
+ CLD; REP; OP16; OUTSL
+ RET
+
+/*
+ * test and set
+ */
+TEXT tas(SB),$0
+ MOVL $0xdeadead,AX
+ MOVL l+0(FP),BX
+ XCHGL AX,(BX)
+ RET
+
+/*
+ * routines to load/read various system registers
+ */
+GLOBL idtptr(SB),$6
+TEXT putidt(SB),$0 /* interrupt descriptor table */
+ MOVL t+0(FP),AX
+ MOVL AX,idtptr+2(SB)
+ MOVL l+4(FP),AX
+ MOVW AX,idtptr(SB)
+ MOVL idtptr(SB),IDTR
+ RET
+
+GLOBL gdtptr(SB),$6
+TEXT putgdt(SB),$0 /* global descriptor table */
+ MOVL t+0(FP),AX
+ MOVL AX,gdtptr+2(SB)
+ MOVL l+4(FP),AX
+ MOVW AX,gdtptr(SB)
+ MOVL gdtptr(SB),GDTR
+ RET
+
+TEXT putcr3(SB),$0 /* top level page table pointer */
+ MOVL t+0(FP),AX
+ MOVL AX,CR3
+ RET
+
+TEXT puttr(SB),$0 /* task register */
+ MOVL t+0(FP),AX
+ MOVW AX,TASK
+ RET
+
+TEXT getcr0(SB),$0 /* coprocessor bits */
+ MOVL CR0,AX
+ RET
+
+TEXT getcr2(SB),$0 /* fault address */
+ MOVL CR2,AX
+ RET
+
+#define FPOFF\
+ WAIT;\
+ MOVL CR0,AX;\
+ ORL $0x4,AX /* EM=1 */;\
+ MOVL AX,CR0
+
+#define FPON\
+ MOVL CR0,AX;\
+ ANDL $~0x4,AX /* EM=0 */;\
+ MOVL AX,CR0
+
+TEXT fpoff(SB),$0 /* turn off floating point */
+ FPOFF
+ RET
+
+TEXT fpinit(SB),$0 /* turn on & init the floating point */
+ FPON
+ FINIT
+ WAIT
+ PUSHW $0x0330
+ FLDCW 0(SP) /* ignore underflow/precision, signal others */
+ POPW AX
+ WAIT
+ RET
+
+TEXT fpsave(SB),$0 /* save floating point state and turn off */
+ MOVL p+0(FP),AX
+ WAIT
+ FSAVE 0(AX)
+ FPOFF
+ RET
+
+TEXT fprestore(SB),$0 /* turn on floating point and restore regs */
+ FPON
+ MOVL p+0(FP),AX
+ FRSTOR 0(AX)
+ WAIT
+ RET
+
+TEXT fpstatus(SB),$0 /* get floating point status */
+ FSTSW AX
+ RET
+
+/*
+ * special traps
+ */
+TEXT intr0(SB),$0
+ PUSHL $0
+ PUSHL $0
+ JMP intrcommon
+TEXT intr1(SB),$0
+ PUSHL $0
+ PUSHL $1
+ JMP intrcommon
+TEXT intr2(SB),$0
+ PUSHL $0
+ PUSHL $2
+ JMP intrcommon
+TEXT intr3(SB),$0
+ PUSHL $0
+ PUSHL $3
+ JMP intrcommon
+TEXT intr4(SB),$0
+ PUSHL $0
+ PUSHL $4
+ JMP intrcommon
+TEXT intr5(SB),$0
+ PUSHL $0
+ PUSHL $5
+ JMP intrcommon
+TEXT intr6(SB),$0
+ PUSHL $0
+ PUSHL $6
+ JMP intrcommon
+TEXT intr7(SB),$0
+ PUSHL $0
+ PUSHL $7
+ JMP intrcommon
+TEXT intr8(SB),$0
+ PUSHL $8
+ JMP intrscommon
+TEXT intr9(SB),$0
+ PUSHL $0
+ PUSHL $9
+ JMP intrcommon
+TEXT intr10(SB),$0
+ PUSHL $10
+ JMP intrscommon
+TEXT intr11(SB),$0
+ PUSHL $11
+ JMP intrscommon
+TEXT intr12(SB),$0
+ PUSHL $12
+ JMP intrscommon
+TEXT intr13(SB),$0
+ PUSHL $13
+ JMP intrscommon
+TEXT intr14(SB),$0
+ PUSHL $14
+ JMP intrscommon
+TEXT intr15(SB),$0
+ PUSHL $0
+ PUSHL $15
+ JMP intrcommon
+TEXT intr16(SB),$0
+ PUSHL $0
+ PUSHL $16
+ JMP intrcommon
+TEXT intr24(SB),$0
+ PUSHL $0
+ PUSHL $24
+ JMP intrcommon
+TEXT intr25(SB),$0
+ PUSHL $0
+ PUSHL $25
+ JMP intrcommon
+TEXT intr26(SB),$0
+ PUSHL $0
+ PUSHL $26
+ JMP intrcommon
+TEXT intr27(SB),$0
+ PUSHL $0
+ PUSHL $27
+ JMP intrcommon
+TEXT intr28(SB),$0
+ PUSHL $0
+ PUSHL $28
+ JMP intrcommon
+TEXT intr29(SB),$0
+ PUSHL $0
+ PUSHL $29
+ JMP intrcommon
+TEXT intr30(SB),$0
+ PUSHL $0
+ PUSHL $30
+ JMP intrcommon
+TEXT intr31(SB),$0
+ PUSHL $0
+ PUSHL $31
+ JMP intrcommon
+TEXT intr32(SB),$0
+ PUSHL $0
+ PUSHL $16
+ JMP intrcommon
+TEXT intr33(SB),$0
+ PUSHL $0
+ PUSHL $33
+ JMP intrcommon
+TEXT intr34(SB),$0
+ PUSHL $0
+ PUSHL $34
+ JMP intrcommon
+TEXT intr35(SB),$0
+ PUSHL $0
+ PUSHL $35
+ JMP intrcommon
+TEXT intr36(SB),$0
+ PUSHL $0
+ PUSHL $36
+ JMP intrcommon
+TEXT intr37(SB),$0
+ PUSHL $0
+ PUSHL $37
+ JMP intrcommon
+TEXT intr38(SB),$0
+ PUSHL $0
+ PUSHL $38
+ JMP intrcommon
+TEXT intr39(SB),$0
+ PUSHL $0
+ PUSHL $39
+ JMP intrcommon
+TEXT intr64(SB),$0
+ PUSHL $0
+ PUSHL $64
+ JMP intrcommon
+TEXT intrbad(SB),$0
+ PUSHL $0
+ PUSHL $0x1ff
+ JMP intrcommon
+
+intrcommon:
+ PUSHL DS
+ PUSHL ES
+ PUSHL FS
+ PUSHL GS
+ PUSHAL
+ MOVL $(KDSEL),AX
+ MOVW AX,DS
+ MOVW AX,ES
+ LEAL 0(SP),AX
+ PUSHL AX
+ CALL trap(SB)
+ POPL AX
+ POPAL
+ POPL GS
+ POPL FS
+ POPL ES
+ POPL DS
+ ADDL $8,SP /* error code and trap type */
+ IRETL
+
+intrscommon:
+ PUSHL DS
+ PUSHL ES
+ PUSHL FS
+ PUSHL GS
+ PUSHAL
+ MOVL $(KDSEL),AX
+ MOVW AX,DS
+ MOVW AX,ES
+ LEAL 0(SP),AX
+ PUSHL AX
+ CALL trap(SB)
+ POPL AX
+ POPAL
+ POPL GS
+ POPL FS
+ POPL ES
+ POPL DS
+ ADDL $8,SP /* error code and trap type */
+ IRETL
+
+/*
+ * interrupt level is interrupts on or off
+ */
+TEXT spllo(SB),$0
+ PUSHFL
+ POPL AX
+ STI
+ RET
+
+TEXT splhi(SB),$0
+ PUSHFL
+ POPL AX
+ CLI
+ RET
+
+TEXT splx(SB),$0
+ MOVL s+0(FP),AX
+ PUSHL AX
+ POPFL
+ RET
+
+/*
+ * do nothing whatsoever till interrupt happens
+ */
+TEXT idle(SB),$0
+ HLT
+ RET
+
+/*
+ * label consists of a stack pointer and a PC
+ */
+TEXT gotolabel(SB),$0
+ MOVL l+0(FP),AX
+ MOVL 0(AX),SP /* restore sp */
+ MOVL 4(AX),AX /* put return pc on the stack */
+ MOVL AX,0(SP)
+ MOVL $1,AX /* return 1 */
+ RET
+
+TEXT setlabel(SB),$0
+ MOVL l+0(FP),AX
+ MOVL SP,0(AX) /* store sp */
+ MOVL 0(SP),BX /* store return pc */
+ MOVL BX,4(AX)
+ MOVL $0,AX /* return 0 */
+ RET
+
+/*
+ * Used to get to the first process.
+ * Set up an interrupt return frame and IRET to user level.
+ */
+TEXT touser(SB),$0
+ PUSHL $(UDSEL) /* old ss */
+ PUSHL $(USTKTOP) /* old sp */
+ PUSHFL /* old flags */
+ PUSHL $(UESEL) /* old cs */
+ PUSHL $(UTZERO+32) /* old pc */
+ MOVL $(UDSEL),AX
+ MOVW AX,DS
+ MOVW AX,ES
+ MOVW AX,GS
+ MOVW AX,FS
+ IRETL
+
+/*
+ * set configuration register
+ */
+TEXT config(SB),$0
+ MOVL l+0(FP),AX
+ MOVL $0x3F3,DX
+ OUTB
+ OUTB
+ RET
diff --git a/utils/8a/lex.c b/utils/8a/lex.c
new file mode 100644
index 00000000..0ec4dc17
--- /dev/null
+++ b/utils/8a/lex.c
@@ -0,0 +1,895 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = '8';
+ thestring = "386";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "AL", LBREG, D_AL,
+ "CL", LBREG, D_CL,
+ "DL", LBREG, D_DL,
+ "BL", LBREG, D_BL,
+ "AH", LBREG, D_AH,
+ "CH", LBREG, D_CH,
+ "DH", LBREG, D_DH,
+ "BH", LBREG, D_BH,
+
+ "AX", LLREG, D_AX,
+ "CX", LLREG, D_CX,
+ "DX", LLREG, D_DX,
+ "BX", LLREG, D_BX,
+/* "SP", LLREG, D_SP, */
+ "BP", LLREG, D_BP,
+ "SI", LLREG, D_SI,
+ "DI", LLREG, D_DI,
+
+ "F0", LFREG, D_F0+0,
+ "F1", LFREG, D_F0+1,
+ "F2", LFREG, D_F0+2,
+ "F3", LFREG, D_F0+3,
+ "F4", LFREG, D_F0+4,
+ "F5", LFREG, D_F0+5,
+ "F6", LFREG, D_F0+6,
+ "F7", LFREG, D_F0+7,
+
+ "CS", LSREG, D_CS,
+ "SS", LSREG, D_SS,
+ "DS", LSREG, D_DS,
+ "ES", LSREG, D_ES,
+ "FS", LSREG, D_FS,
+ "GS", LSREG, D_GS,
+
+ "GDTR", LBREG, D_GDTR,
+ "IDTR", LBREG, D_IDTR,
+ "LDTR", LBREG, D_LDTR,
+ "MSW", LBREG, D_MSW,
+ "TASK", LBREG, D_TASK,
+
+ "CR0", LBREG, D_CR+0,
+ "CR1", LBREG, D_CR+1,
+ "CR2", LBREG, D_CR+2,
+ "CR3", LBREG, D_CR+3,
+ "CR4", LBREG, D_CR+4,
+ "CR5", LBREG, D_CR+5,
+ "CR6", LBREG, D_CR+6,
+ "CR7", LBREG, D_CR+7,
+
+ "DR0", LBREG, D_DR+0,
+ "DR1", LBREG, D_DR+1,
+ "DR2", LBREG, D_DR+2,
+ "DR3", LBREG, D_DR+3,
+ "DR4", LBREG, D_DR+4,
+ "DR5", LBREG, D_DR+5,
+ "DR6", LBREG, D_DR+6,
+ "DR7", LBREG, D_DR+7,
+
+ "TR0", LBREG, D_TR+0,
+ "TR1", LBREG, D_TR+1,
+ "TR2", LBREG, D_TR+2,
+ "TR3", LBREG, D_TR+3,
+ "TR4", LBREG, D_TR+4,
+ "TR5", LBREG, D_TR+5,
+ "TR6", LBREG, D_TR+6,
+ "TR7", LBREG, D_TR+7,
+
+ "AAA", LTYPE0, AAAA,
+ "AAD", LTYPE0, AAAD,
+ "AAM", LTYPE0, AAAM,
+ "AAS", LTYPE0, AAAS,
+ "ADCB", LTYPE3, AADCB,
+ "ADCL", LTYPE3, AADCL,
+ "ADCW", LTYPE3, AADCW,
+ "ADDB", LTYPE3, AADDB,
+ "ADDL", LTYPE3, AADDL,
+ "ADDW", LTYPE3, AADDW,
+ "ADJSP", LTYPE2, AADJSP,
+ "ANDB", LTYPE3, AANDB,
+ "ANDL", LTYPE3, AANDL,
+ "ANDW", LTYPE3, AANDW,
+ "ARPL", LTYPE3, AARPL,
+ "BOUNDL", LTYPE3, ABOUNDL,
+ "BOUNDW", LTYPE3, ABOUNDW,
+ "BSFL", LTYPE3, ABSFL,
+ "BSFW", LTYPE3, ABSFW,
+ "BSRL", LTYPE3, ABSRL,
+ "BSRW", LTYPE3, ABSRW,
+ "BTCL", LTYPE3, ABTCL,
+ "BTCW", LTYPE3, ABTCW,
+ "BTL", LTYPE3, ABTL,
+ "BTRL", LTYPE3, ABTRL,
+ "BTRW", LTYPE3, ABTRW,
+ "BTSL", LTYPE3, ABTSL,
+ "BTSW", LTYPE3, ABTSW,
+ "BTW", LTYPE3, ABTW,
+ "BYTE", LTYPE2, ABYTE,
+ "CALL", LTYPEC, ACALL,
+ "CLC", LTYPE0, ACLC,
+ "CLD", LTYPE0, ACLD,
+ "CLI", LTYPE0, ACLI,
+ "CLTS", LTYPE0, ACLTS,
+ "CMC", LTYPE0, ACMC,
+ "CMPB", LTYPE4, ACMPB,
+ "CMPL", LTYPE4, ACMPL,
+ "CMPW", LTYPE4, ACMPW,
+ "CMPSB", LTYPE0, ACMPSB,
+ "CMPSL", LTYPE0, ACMPSL,
+ "CMPSW", LTYPE0, ACMPSW,
+ "DAA", LTYPE0, ADAA,
+ "DAS", LTYPE0, ADAS,
+ "DATA", LTYPED, ADATA,
+ "DECB", LTYPE1, ADECB,
+ "DECL", LTYPE1, ADECL,
+ "DECW", LTYPE1, ADECW,
+ "DIVB", LTYPE2, ADIVB,
+ "DIVL", LTYPE2, ADIVL,
+ "DIVW", LTYPE2, ADIVW,
+ "END", LTYPE0, AEND,
+ "ENTER", LTYPE2, AENTER,
+ "GLOBL", LTYPET, AGLOBL,
+ "HLT", LTYPE0, AHLT,
+ "IDIVB", LTYPE2, AIDIVB,
+ "IDIVL", LTYPE2, AIDIVL,
+ "IDIVW", LTYPE2, AIDIVW,
+ "IMULB", LTYPE2, AIMULB,
+ "IMULL", LTYPE2, AIMULL,
+ "IMULW", LTYPE2, AIMULW,
+ "INB", LTYPE0, AINB,
+ "INL", LTYPE0, AINL,
+ "INW", LTYPE0, AINW,
+ "INCB", LTYPE1, AINCB,
+ "INCL", LTYPE1, AINCL,
+ "INCW", LTYPE1, AINCW,
+ "INSB", LTYPE0, AINSB,
+ "INSL", LTYPE0, AINSL,
+ "INSW", LTYPE0, AINSW,
+ "INT", LTYPE2, AINT,
+ "INTO", LTYPE0, AINTO,
+ "IRETL", LTYPE0, AIRETL,
+ "IRETW", LTYPE0, AIRETW,
+
+ "JOS", LTYPER, AJOS,
+ "JO", LTYPER, AJOS, /* alternate */
+ "JOC", LTYPER, AJOC,
+ "JNO", LTYPER, AJOC, /* alternate */
+ "JCS", LTYPER, AJCS,
+ "JB", LTYPER, AJCS, /* alternate */
+ "JC", LTYPER, AJCS, /* alternate */
+ "JNAE", LTYPER, AJCS, /* alternate */
+ "JLO", LTYPER, AJCS, /* alternate */
+ "JCC", LTYPER, AJCC,
+ "JAE", LTYPER, AJCC, /* alternate */
+ "JNB", LTYPER, AJCC, /* alternate */
+ "JNC", LTYPER, AJCC, /* alternate */
+ "JHS", LTYPER, AJCC, /* alternate */
+ "JEQ", LTYPER, AJEQ,
+ "JE", LTYPER, AJEQ, /* alternate */
+ "JZ", LTYPER, AJEQ, /* alternate */
+ "JNE", LTYPER, AJNE,
+ "JNZ", LTYPER, AJNE, /* alternate */
+ "JLS", LTYPER, AJLS,
+ "JBE", LTYPER, AJLS, /* alternate */
+ "JNA", LTYPER, AJLS, /* alternate */
+ "JHI", LTYPER, AJHI,
+ "JA", LTYPER, AJHI, /* alternate */
+ "JNBE", LTYPER, AJHI, /* alternate */
+ "JMI", LTYPER, AJMI,
+ "JS", LTYPER, AJMI, /* alternate */
+ "JPL", LTYPER, AJPL,
+ "JNS", LTYPER, AJPL, /* alternate */
+ "JPS", LTYPER, AJPS,
+ "JP", LTYPER, AJPS, /* alternate */
+ "JPE", LTYPER, AJPS, /* alternate */
+ "JPC", LTYPER, AJPC,
+ "JNP", LTYPER, AJPC, /* alternate */
+ "JPO", LTYPER, AJPC, /* alternate */
+ "JLT", LTYPER, AJLT,
+ "JL", LTYPER, AJLT, /* alternate */
+ "JNGE", LTYPER, AJLT, /* alternate */
+ "JGE", LTYPER, AJGE,
+ "JNL", LTYPER, AJGE, /* alternate */
+ "JLE", LTYPER, AJLE,
+ "JNG", LTYPER, AJLE, /* alternate */
+ "JGT", LTYPER, AJGT,
+ "JG", LTYPER, AJGT, /* alternate */
+ "JNLE", LTYPER, AJGT, /* alternate */
+
+ "JCXZ", LTYPER, AJCXZ,
+ "JMP", LTYPEC, AJMP,
+ "LAHF", LTYPE0, ALAHF,
+ "LARL", LTYPE3, ALARL,
+ "LARW", LTYPE3, ALARW,
+ "LEAL", LTYPE3, ALEAL,
+ "LEAW", LTYPE3, ALEAW,
+ "LEAVEL", LTYPE0, ALEAVEL,
+ "LEAVEW", LTYPE0, ALEAVEW,
+ "LOCK", LTYPE0, ALOCK,
+ "LODSB", LTYPE0, ALODSB,
+ "LODSL", LTYPE0, ALODSL,
+ "LODSW", LTYPE0, ALODSW,
+ "LONG", LTYPE2, ALONG,
+ "LOOP", LTYPER, ALOOP,
+ "LOOPEQ", LTYPER, ALOOPEQ,
+ "LOOPNE", LTYPER, ALOOPNE,
+ "LSLL", LTYPE3, ALSLL,
+ "LSLW", LTYPE3, ALSLW,
+ "MOVB", LTYPE3, AMOVB,
+ "MOVL", LTYPEM, AMOVL,
+ "MOVW", LTYPEM, AMOVW,
+ "MOVBLSX", LTYPE3, AMOVBLSX,
+ "MOVBLZX", LTYPE3, AMOVBLZX,
+ "MOVBWSX", LTYPE3, AMOVBWSX,
+ "MOVBWZX", LTYPE3, AMOVBWZX,
+ "MOVWLSX", LTYPE3, AMOVWLSX,
+ "MOVWLZX", LTYPE3, AMOVWLZX,
+ "MOVSB", LTYPE0, AMOVSB,
+ "MOVSL", LTYPE0, AMOVSL,
+ "MOVSW", LTYPE0, AMOVSW,
+ "MULB", LTYPE2, AMULB,
+ "MULL", LTYPE2, AMULL,
+ "MULW", LTYPE2, AMULW,
+ "NEGB", LTYPE1, ANEGB,
+ "NEGL", LTYPE1, ANEGL,
+ "NEGW", LTYPE1, ANEGW,
+ "NOP", LTYPEN, ANOP,
+ "NOTB", LTYPE1, ANOTB,
+ "NOTL", LTYPE1, ANOTL,
+ "NOTW", LTYPE1, ANOTW,
+ "ORB", LTYPE3, AORB,
+ "ORL", LTYPE3, AORL,
+ "ORW", LTYPE3, AORW,
+ "OUTB", LTYPE0, AOUTB,
+ "OUTL", LTYPE0, AOUTL,
+ "OUTW", LTYPE0, AOUTW,
+ "OUTSB", LTYPE0, AOUTSB,
+ "OUTSL", LTYPE0, AOUTSL,
+ "OUTSW", LTYPE0, AOUTSW,
+ "POPAL", LTYPE0, APOPAL,
+ "POPAW", LTYPE0, APOPAW,
+ "POPFL", LTYPE0, APOPFL,
+ "POPFW", LTYPE0, APOPFW,
+ "POPL", LTYPE1, APOPL,
+ "POPW", LTYPE1, APOPW,
+ "PUSHAL", LTYPE0, APUSHAL,
+ "PUSHAW", LTYPE0, APUSHAW,
+ "PUSHFL", LTYPE0, APUSHFL,
+ "PUSHFW", LTYPE0, APUSHFW,
+ "PUSHL", LTYPE2, APUSHL,
+ "PUSHW", LTYPE2, APUSHW,
+ "RCLB", LTYPE3, ARCLB,
+ "RCLL", LTYPE3, ARCLL,
+ "RCLW", LTYPE3, ARCLW,
+ "RCRB", LTYPE3, ARCRB,
+ "RCRL", LTYPE3, ARCRL,
+ "RCRW", LTYPE3, ARCRW,
+ "REP", LTYPE0, AREP,
+ "REPN", LTYPE0, AREPN,
+ "RET", LTYPE0, ARET,
+ "ROLB", LTYPE3, AROLB,
+ "ROLL", LTYPE3, AROLL,
+ "ROLW", LTYPE3, AROLW,
+ "RORB", LTYPE3, ARORB,
+ "RORL", LTYPE3, ARORL,
+ "RORW", LTYPE3, ARORW,
+ "SAHF", LTYPE0, ASAHF,
+ "SALB", LTYPE3, ASALB,
+ "SALL", LTYPE3, ASALL,
+ "SALW", LTYPE3, ASALW,
+ "SARB", LTYPE3, ASARB,
+ "SARL", LTYPE3, ASARL,
+ "SARW", LTYPE3, ASARW,
+ "SBBB", LTYPE3, ASBBB,
+ "SBBL", LTYPE3, ASBBL,
+ "SBBW", LTYPE3, ASBBW,
+ "SCASB", LTYPE0, ASCASB,
+ "SCASL", LTYPE0, ASCASL,
+ "SCASW", LTYPE0, ASCASW,
+ "SETCC", LTYPE1, ASETCC,
+ "SETCS", LTYPE1, ASETCS,
+ "SETEQ", LTYPE1, ASETEQ,
+ "SETGE", LTYPE1, ASETGE,
+ "SETGT", LTYPE1, ASETGT,
+ "SETHI", LTYPE1, ASETHI,
+ "SETLE", LTYPE1, ASETLE,
+ "SETLS", LTYPE1, ASETLS,
+ "SETLT", LTYPE1, ASETLT,
+ "SETMI", LTYPE1, ASETMI,
+ "SETNE", LTYPE1, ASETNE,
+ "SETOC", LTYPE1, ASETOC,
+ "SETOS", LTYPE1, ASETOS,
+ "SETPC", LTYPE1, ASETPC,
+ "SETPL", LTYPE1, ASETPL,
+ "SETPS", LTYPE1, ASETPS,
+ "CDQ", LTYPE0, ACDQ,
+ "CWD", LTYPE0, ACWD,
+ "SHLB", LTYPE3, ASHLB,
+ "SHLL", LTYPES, ASHLL,
+ "SHLW", LTYPES, ASHLW,
+ "SHRB", LTYPE3, ASHRB,
+ "SHRL", LTYPES, ASHRL,
+ "SHRW", LTYPES, ASHRW,
+ "STC", LTYPE0, ASTC,
+ "STD", LTYPE0, ASTD,
+ "STI", LTYPE0, ASTI,
+ "STOSB", LTYPE0, ASTOSB,
+ "STOSL", LTYPE0, ASTOSL,
+ "STOSW", LTYPE0, ASTOSW,
+ "SUBB", LTYPE3, ASUBB,
+ "SUBL", LTYPE3, ASUBL,
+ "SUBW", LTYPE3, ASUBW,
+ "SYSCALL", LTYPE0, ASYSCALL,
+ "TESTB", LTYPE3, ATESTB,
+ "TESTL", LTYPE3, ATESTL,
+ "TESTW", LTYPE3, ATESTW,
+ "TEXT", LTYPET, ATEXT,
+ "VERR", LTYPE2, AVERR,
+ "VERW", LTYPE2, AVERW,
+ "WAIT", LTYPE0, AWAIT,
+ "WORD", LTYPE2, AWORD,
+ "XCHGB", LTYPE3, AXCHGB,
+ "XCHGL", LTYPE3, AXCHGL,
+ "XCHGW", LTYPE3, AXCHGW,
+ "XLAT", LTYPE2, AXLAT,
+ "XORB", LTYPE3, AXORB,
+ "XORL", LTYPE3, AXORL,
+ "XORW", LTYPE3, AXORW,
+
+ "FMOVB", LTYPE3, AFMOVB,
+ "FMOVBP", LTYPE3, AFMOVBP,
+ "FMOVD", LTYPE3, AFMOVD,
+ "FMOVDP", LTYPE3, AFMOVDP,
+ "FMOVF", LTYPE3, AFMOVF,
+ "FMOVFP", LTYPE3, AFMOVFP,
+ "FMOVL", LTYPE3, AFMOVL,
+ "FMOVLP", LTYPE3, AFMOVLP,
+ "FMOVV", LTYPE3, AFMOVV,
+ "FMOVVP", LTYPE3, AFMOVVP,
+ "FMOVW", LTYPE3, AFMOVW,
+ "FMOVWP", LTYPE3, AFMOVWP,
+ "FMOVX", LTYPE3, AFMOVX,
+ "FMOVXP", LTYPE3, AFMOVXP,
+ "FCOMB", LTYPE3, AFCOMB,
+ "FCOMBP", LTYPE3, AFCOMBP,
+ "FCOMD", LTYPE3, AFCOMD,
+ "FCOMDP", LTYPE3, AFCOMDP,
+ "FCOMDPP", LTYPE3, AFCOMDPP,
+ "FCOMF", LTYPE3, AFCOMF,
+ "FCOMFP", LTYPE3, AFCOMFP,
+ "FCOML", LTYPE3, AFCOML,
+ "FCOMLP", LTYPE3, AFCOMLP,
+ "FCOMW", LTYPE3, AFCOMW,
+ "FCOMWP", LTYPE3, AFCOMWP,
+ "FUCOM", LTYPE3, AFUCOM,
+ "FUCOMP", LTYPE3, AFUCOMP,
+ "FUCOMPP", LTYPE3, AFUCOMPP,
+ "FADDW", LTYPE3, AFADDW,
+ "FADDL", LTYPE3, AFADDL,
+ "FADDF", LTYPE3, AFADDF,
+ "FADDD", LTYPE3, AFADDD,
+ "FADDDP", LTYPE3, AFADDDP,
+ "FSUBDP", LTYPE3, AFSUBDP,
+ "FSUBW", LTYPE3, AFSUBW,
+ "FSUBL", LTYPE3, AFSUBL,
+ "FSUBF", LTYPE3, AFSUBF,
+ "FSUBD", LTYPE3, AFSUBD,
+ "FSUBRDP", LTYPE3, AFSUBRDP,
+ "FSUBRW", LTYPE3, AFSUBRW,
+ "FSUBRL", LTYPE3, AFSUBRL,
+ "FSUBRF", LTYPE3, AFSUBRF,
+ "FSUBRD", LTYPE3, AFSUBRD,
+ "FMULDP", LTYPE3, AFMULDP,
+ "FMULW", LTYPE3, AFMULW,
+ "FMULL", LTYPE3, AFMULL,
+ "FMULF", LTYPE3, AFMULF,
+ "FMULD", LTYPE3, AFMULD,
+ "FDIVDP", LTYPE3, AFDIVDP,
+ "FDIVW", LTYPE3, AFDIVW,
+ "FDIVL", LTYPE3, AFDIVL,
+ "FDIVF", LTYPE3, AFDIVF,
+ "FDIVD", LTYPE3, AFDIVD,
+ "FDIVRDP", LTYPE3, AFDIVRDP,
+ "FDIVRW", LTYPE3, AFDIVRW,
+ "FDIVRL", LTYPE3, AFDIVRL,
+ "FDIVRF", LTYPE3, AFDIVRF,
+ "FDIVRD", LTYPE3, AFDIVRD,
+ "FXCHD", LTYPE3, AFXCHD,
+ "FFREE", LTYPE1, AFFREE,
+ "FLDCW", LTYPE2, AFLDCW,
+ "FLDENV", LTYPE1, AFLDENV,
+ "FRSTOR", LTYPE2, AFRSTOR,
+ "FSAVE", LTYPE1, AFSAVE,
+ "FSTCW", LTYPE1, AFSTCW,
+ "FSTENV", LTYPE1, AFSTENV,
+ "FSTSW", LTYPE1, AFSTSW,
+ "F2XM1", LTYPE0, AF2XM1,
+ "FABS", LTYPE0, AFABS,
+ "FCHS", LTYPE0, AFCHS,
+ "FCLEX", LTYPE0, AFCLEX,
+ "FCOS", LTYPE0, AFCOS,
+ "FDECSTP", LTYPE0, AFDECSTP,
+ "FINCSTP", LTYPE0, AFINCSTP,
+ "FINIT", LTYPE0, AFINIT,
+ "FLD1", LTYPE0, AFLD1,
+ "FLDL2E", LTYPE0, AFLDL2E,
+ "FLDL2T", LTYPE0, AFLDL2T,
+ "FLDLG2", LTYPE0, AFLDLG2,
+ "FLDLN2", LTYPE0, AFLDLN2,
+ "FLDPI", LTYPE0, AFLDPI,
+ "FLDZ", LTYPE0, AFLDZ,
+ "FNOP", LTYPE0, AFNOP,
+ "FPATAN", LTYPE0, AFPATAN,
+ "FPREM", LTYPE0, AFPREM,
+ "FPREM1", LTYPE0, AFPREM1,
+ "FPTAN", LTYPE0, AFPTAN,
+ "FRNDINT", LTYPE0, AFRNDINT,
+ "FSCALE", LTYPE0, AFSCALE,
+ "FSIN", LTYPE0, AFSIN,
+ "FSINCOS", LTYPE0, AFSINCOS,
+ "FSQRT", LTYPE0, AFSQRT,
+ "FTST", LTYPE0, AFTST,
+ "FXAM", LTYPE0, AFXAM,
+ "FXTRACT", LTYPE0, AFXTRACT,
+ "FYL2X", LTYPE0, AFYL2X,
+ "FYL2XP1", LTYPE0, AFYL2XP1,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+ nullgen.type = D_NONE;
+ nullgen.index = D_NONE;
+ nullgen.scale = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ if(s->type != LNAME)
+ yyerror("double initialization %s", itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+checkscale(int scale)
+{
+
+ switch(scale) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return;
+ }
+ yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+ Gen2 g2;
+
+ g2.from = nullgen;
+ g2.to = nullgen;
+ outcode(AEND, &g2);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME); /* as(2) */
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(a->offset != 0)
+ t |= T_OFFSET;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ case D_NONE:
+ break;
+ }
+ Bputc(&obuf, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(&obuf, a->index);
+ Bputc(&obuf, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(&obuf, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ l = e.h;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(&obuf, a->type);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+
+jackpot:
+ sf = 0;
+ s = g2->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g2->from.type;
+ if(t == D_ADDR)
+ t = g2->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->to.type;
+ if(t == D_ADDR)
+ t = g2->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, a>>8);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(&g2->from, sf);
+ zaddr(&g2->to, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, ANAME>>8);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, AHISTORY>>8);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/8a/mkfile b/utils/8a/mkfile
new file mode 100644
index 00000000..b021d34f
--- /dev/null
+++ b/utils/8a/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=8a
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../8c/8.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/8c/8.out.h b/utils/8c/8.out.h
new file mode 100644
index 00000000..fdfd0ca7
--- /dev/null
+++ b/utils/8c/8.out.h
@@ -0,0 +1,445 @@
+#define NSYM 50
+#define NSNAME 8
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+enum as
+{
+ AXXX,
+ AAAA,
+ AAAD,
+ AAAM,
+ AAAS,
+ AADCB,
+ AADCL,
+ AADCW,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AARPL,
+ ABOUNDL,
+ ABOUNDW,
+ ABSFL,
+ ABSFW,
+ ABSRL,
+ ABSRW,
+ ABTL,
+ ABTW,
+ ABTCL,
+ ABTCW,
+ ABTRL,
+ ABTRW,
+ ABTSL,
+ ABTSW,
+ ABYTE,
+ ACALL,
+ ACLC,
+ ACLD,
+ ACLI,
+ ACLTS,
+ ACMC,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ACMPSB,
+ ACMPSL,
+ ACMPSW,
+ ADAA,
+ ADAS,
+ ADATA,
+ ADECB,
+ ADECL,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ AINCW,
+ AINSB,
+ AINSL,
+ AINSW,
+ AINT,
+ AINTO,
+ AIRETL,
+ AIRETW,
+ AJCC,
+ AJCS,
+ AJCXZ,
+ AJEQ,
+ AJGE,
+ AJGT,
+ AJHI,
+ AJLE,
+ AJLS,
+ AJLT,
+ AJMI,
+ AJMP,
+ AJNE,
+ AJOC,
+ AJOS,
+ AJPC,
+ AJPL,
+ AJPS,
+ ALAHF,
+ ALARL,
+ ALARW,
+ ALEAL,
+ ALEAW,
+ ALEAVEL,
+ ALEAVEW,
+ ALOCK,
+ ALODSB,
+ ALODSL,
+ ALODSW,
+ ALONG,
+ ALOOP,
+ ALOOPEQ,
+ ALOOPNE,
+ ALSLL,
+ ALSLW,
+ AMOVB,
+ AMOVL,
+ AMOVW,
+ AMOVBLSX,
+ AMOVBLZX,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ AMOVSB,
+ AMOVSL,
+ AMOVSW,
+ AMULB,
+ AMULL,
+ AMULW,
+ ANAME,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ AOUTB,
+ AOUTL,
+ AOUTW,
+ AOUTSB,
+ AOUTSL,
+ AOUTSW,
+ APOPAL,
+ APOPAW,
+ APOPFL,
+ APOPFW,
+ APOPL,
+ APOPW,
+ APUSHAL,
+ APUSHAW,
+ APUSHFL,
+ APUSHFW,
+ APUSHL,
+ APUSHW,
+ ARCLB,
+ ARCLL,
+ ARCLW,
+ ARCRB,
+ ARCRL,
+ ARCRW,
+ AREP,
+ AREPN,
+ ARET,
+ AROLB,
+ AROLL,
+ AROLW,
+ ARORB,
+ ARORL,
+ ARORW,
+ ASAHF,
+ ASALB,
+ ASALL,
+ ASALW,
+ ASARB,
+ ASARL,
+ ASARW,
+ ASBBB,
+ ASBBL,
+ ASBBW,
+ ASCASB,
+ ASCASL,
+ ASCASW,
+ ASETCC,
+ ASETCS,
+ ASETEQ,
+ ASETGE,
+ ASETGT,
+ ASETHI,
+ ASETLE,
+ ASETLS,
+ ASETLT,
+ ASETMI,
+ ASETNE,
+ ASETOC,
+ ASETOS,
+ ASETPC,
+ ASETPL,
+ ASETPS,
+ ACDQ,
+ ACWD,
+ ASHLB,
+ ASHLL,
+ ASHLW,
+ ASHRB,
+ ASHRL,
+ ASHRW,
+ ASTC,
+ ASTD,
+ ASTI,
+ ASTOSB,
+ ASTOSL,
+ ASTOSW,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASYSCALL,
+ ATESTB,
+ ATESTL,
+ ATESTW,
+ ATEXT,
+ AVERR,
+ AVERW,
+ AWAIT,
+ AWORD,
+ AXCHGB,
+ AXCHGL,
+ AXCHGW,
+ AXLAT,
+ AXORB,
+ AXORL,
+ AXORW,
+
+ AFMOVB,
+ AFMOVBP,
+ AFMOVD,
+ AFMOVDP,
+ AFMOVF,
+ AFMOVFP,
+ AFMOVL,
+ AFMOVLP,
+ AFMOVV,
+ AFMOVVP,
+ AFMOVW,
+ AFMOVWP,
+ AFMOVX,
+ AFMOVXP,
+
+ AFCOMB,
+ AFCOMBP,
+ AFCOMD,
+ AFCOMDP,
+ AFCOMDPP,
+ AFCOMF,
+ AFCOMFP,
+ AFCOML,
+ AFCOMLP,
+ AFCOMW,
+ AFCOMWP,
+ AFUCOM,
+ AFUCOMP,
+ AFUCOMPP,
+
+ AFADDDP,
+ AFADDW,
+ AFADDL,
+ AFADDF,
+ AFADDD,
+
+ AFMULDP,
+ AFMULW,
+ AFMULL,
+ AFMULF,
+ AFMULD,
+
+ AFSUBDP,
+ AFSUBW,
+ AFSUBL,
+ AFSUBF,
+ AFSUBD,
+
+ AFSUBRDP,
+ AFSUBRW,
+ AFSUBRL,
+ AFSUBRF,
+ AFSUBRD,
+
+ AFDIVDP,
+ AFDIVW,
+ AFDIVL,
+ AFDIVF,
+ AFDIVD,
+
+ AFDIVRDP,
+ AFDIVRW,
+ AFDIVRL,
+ AFDIVRF,
+ AFDIVRD,
+
+ AFXCHD,
+ AFFREE,
+
+ AFLDCW,
+ AFLDENV,
+ AFRSTOR,
+ AFSAVE,
+ AFSTCW,
+ AFSTENV,
+ AFSTSW,
+
+ AF2XM1,
+ AFABS,
+ AFCHS,
+ AFCLEX,
+ AFCOS,
+ AFDECSTP,
+ AFINCSTP,
+ AFINIT,
+ AFLD1,
+ AFLDL2E,
+ AFLDL2T,
+ AFLDLG2,
+ AFLDLN2,
+ AFLDPI,
+ AFLDZ,
+ AFNOP,
+ AFPATAN,
+ AFPREM,
+ AFPREM1,
+ AFPTAN,
+ AFRNDINT,
+ AFSCALE,
+ AFSIN,
+ AFSINCOS,
+ AFSQRT,
+ AFTST,
+ AFXAM,
+ AFXTRACT,
+ AFYL2X,
+ AFYL2XP1,
+
+ AEND,
+
+ ADYNT,
+ AINIT,
+
+ ASIGNAME,
+
+ ALAST
+};
+
+enum
+{
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+
+ D_AH = 4,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_AX = 8,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+
+ D_F0 = 16,
+
+ D_CS = 24,
+ D_SS,
+ D_DS,
+ D_ES,
+ D_FS,
+ D_GS,
+
+ D_GDTR, /* global descriptor table register */
+ D_IDTR, /* interrupt descriptor table register */
+ D_LDTR, /* local descriptor table register */
+ D_MSW, /* machine status word */
+ D_TASK, /* task register */
+
+ D_CR = 35,
+ D_DR = 43,
+ D_TR = 51,
+
+ D_NONE = 59,
+
+ D_BRANCH = 60,
+ D_EXTERN = 61,
+ D_STATIC = 62,
+ D_AUTO = 63,
+ D_PARAM = 64,
+ D_CONST = 65,
+ D_FCONST = 66,
+ D_SCONST = 67,
+ D_ADDR = 68,
+
+ D_FILE,
+ D_FILE1,
+
+ D_INDIR, /* additive */
+
+ T_TYPE = 1<<0,
+ T_INDEX = 1<<1,
+ T_OFFSET = 1<<2,
+ T_FCONST = 1<<3,
+ T_SYM = 1<<4,
+ T_SCONST = 1<<5,
+
+ REGARG = 0,
+ REGRET = D_AX,
+ FREGRET = D_F0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/8c/cgen.c b/utils/8c/cgen.c
new file mode 100644
index 00000000..81521666
--- /dev/null
+++ b/utils/8c/cgen.c
@@ -0,0 +1,1821 @@
+#include "gc.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r, *t;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, hardleft;
+ long v, curs;
+ vlong c;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ if(cond(o) && typesuv[l->type->etype])
+ break;
+
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ hardleft = l->addable < INDEXED || l->complex >= FNX;
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OAS:
+ if(typefd[n->type->etype]) {
+ cgen(r, &fregnode0);
+ if(nn != Z)
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gmove(&fregnode0, &nod);
+ regfree(&nod);
+ } else
+ gmove(&fregnode0, l);
+ if(nn != Z)
+ gmove(&fregnode0, nn);
+ return;
+ }
+ if(l->op == OBIT)
+ goto bitas;
+ if(!hardleft) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ if(l->op == OINDEX && r->op == OCONST) {
+ gmove(r, l);
+ break;
+ }
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gmove(&nod1, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(r->op == OCONST) {
+ if(r->vconst == 0) {
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(o == OASHL && r->vconst == 1)
+ gopcode(OADD, n->type, &nod, &nod);
+ else
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod); /* probably a bug */
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+ if(nn->op == OREGISTER && nn->reg == D_CX)
+ regalloc(&nod1, l, Z);
+ else
+ regalloc(&nod1, l, nn);
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ cgen(l, &nod1);
+ } else {
+ cgen(l, &nod1);
+ cgen(r, &nod);
+ }
+ gopcode(o, n->type, &nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OAND:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ if(r->vconst == 0 && o != OAND) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+ && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+ c = l->right->vconst;
+ if(c > 0 && c <= 3) {
+ if(l->left->complex >= r->complex) {
+ regalloc(&nod, l->left, nn);
+ cgen(l->left, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ genmuladd(&nod, &nod, 1 << c, &nod1);
+ regfree(&nod1);
+ }
+ else
+ genmuladd(&nod, &nod, 1 << c, r);
+ }
+ else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l->left, Z);
+ cgen(l->left, &nod1);
+ genmuladd(&nod, &nod1, 1 << c, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ if(r->addable >= INDEXED) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ SET(v);
+ switch(o) {
+ case ODIV:
+ case OMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = log2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OMUL:
+ case OLMUL:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ switch(o) {
+ case OMUL:
+ case OLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case ODIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ case OLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ }
+ }
+
+ if(o == OMUL) {
+ if(l->addable >= INDEXED) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(OMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }else
+ gopcode(OMUL, n->type, r, &nod); /* addressible */
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+
+ if(r->op == OCONST && (o == ODIV || o == OLDIV)) {
+ reg[D_DX]++;
+ if(l->addable < INDEXED) {
+ regalloc(&nod2, l, Z);
+ cgen(l, &nod2);
+ l = &nod2;
+ }
+ if(o == ODIV)
+ sdivgen(l, r, &nod, &nod1);
+ else
+ udivgen(l, r, &nod, &nod1);
+ gmove(&nod1, nn);
+ if(l == &nod2)
+ regfree(l);
+ goto freeaxdx;
+ }
+
+ if(l->complex >= r->complex) {
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST) {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ gopcode(o, n->type, &nod3, Z);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ gopcode(o, n->type, &nod3, Z);
+ }
+ if(o == OMOD || o == OLMOD)
+ gmove(&nod1, nn);
+ else
+ gmove(&nod, nn);
+ freeaxdx:
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->op == OCONST)
+ goto asand;
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asfop;
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ } else {
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ cgen(r, &nod);
+ }
+
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ if(hardleft)
+ regfree(&nod1);
+ break;
+
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ asand:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype]||typefd[r->type->etype])
+ goto asfop;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(r->op != OCONST) {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, r, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype]||typefd[r->type->etype])
+ goto asfop;
+ if(r->op == OCONST) {
+ SET(v);
+ switch(o) {
+ case OASDIV:
+ case OASMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = log2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OASMUL:
+ case OASLMUL:
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, l, nn);
+ cgen(&nod2, &nod);
+ switch(o) {
+ case OASMUL:
+ case OASLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case OASDIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OASMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ havev:
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ goto done;
+ case OASLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, l, nn);
+ cgen(&nod2, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ goto havev;
+ }
+ }
+
+ if(o == OASMUL) {
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ if(r->complex >= FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ r = &nod1;
+ }
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->addable < INDEXED) {
+ if(r->complex < FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ }
+ gopcode(OASMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ else
+ gopcode(OASMUL, n->type, r, &nod);
+ if(r == &nod1)
+ regfree(r);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ if(hardleft)
+ regfree(&nod2);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+ reg[D_DX]++;
+
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->op == OCONST) {
+ switch(o) {
+ case OASDIV:
+ sdivgen(&nod2, r, &nod, &nod1);
+ goto divdone;
+ case OASLDIV:
+ udivgen(&nod2, r, &nod, &nod1);
+ divdone:
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ goto freelxaxdx;
+ }
+ }
+ if(o == OASDIV || o == OASMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST ||
+ !typeil[r->type->etype]) {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(o == OASDIV || o == OASMOD)
+ gins(ACDQ, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ }
+ if(o == OASMOD || o == OASLMOD) {
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ } else {
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ }
+ freelxaxdx:
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ fop:
+ if(l->complex >= r->complex) {
+ cgen(l, &fregnode0);
+ if(r->addable < INDEXED) {
+ cgen(r, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 0);
+ } else
+ fgopcode(o, r, &fregnode0, 0, 0);
+ } else {
+ cgen(r, &fregnode0);
+ if(l->addable < INDEXED) {
+ cgen(l, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, l, &fregnode0, 0, 1);
+ }
+ gmove(&fregnode0, nn);
+ break;
+
+ asfop:
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ cgen(r, &fregnode0);
+ } else {
+ cgen(r, &fregnode0);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ }
+ if(!typefd[l->type->etype]) {
+ gmove(&nod, &fregnode0);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, &nod, &fregnode0, 0, 1);
+ if(nn != Z)
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gmove(&fregnode0, &nod);
+ if(nn != Z)
+ gmove(&fregnode0, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+
+ if(typefd[nod3.type->etype])
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ else {
+ Node onod;
+
+ /* incredible grot ... */
+ onod = nod3;
+ onod.op = o;
+ onod.complex = 2;
+ onod.addable = 0;
+ onod.type = tfield;
+ onod.left = &nod4;
+ onod.right = &nod3;
+ cgen(&onod, Z);
+ }
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, nn);
+ nod.op = OREGISTER;
+ gopcode(OFUNC, n->type, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, n->type, Z, l);
+ if(REGARG && reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ if(typefd[n->type->etype])
+ gins(AFMOVDP, &fregnode0, &fregnode0);
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ if(typev[l->type->etype]) {
+ cgen64(n, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gmove(&nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+
+ if(typefd[n->type->etype])
+ goto fltinc;
+ gmove(&nod, nn);
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(typefd[n->type->etype])
+ goto fltinc;
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ fltinc:
+ gmove(&nod, &fregnode0);
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gins(AFLD1, Z, Z);
+ if(v < 0)
+ fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
+ else
+ fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
+ if(nn != Z && (o == OPREINC || o == OPREDEC))
+ gins(AFMOVD, &fregnode0, &fregnode0);
+ gmove(&fregnode0, &nod);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gmove(&nod, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+done:
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ gopcode(OADDR, n->type, n, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ if(typev[n->type->etype]) {
+ testv(n, true);
+ goto com;
+ }
+ o = ONE;
+ if(true)
+ o = OEQ;
+ if(typefd[n->type->etype]) {
+ if(n->addable < INDEXED) {
+ cgen(n, &fregnode0);
+ gins(AFLDZ, Z, Z);
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else {
+ gins(AFLDZ, Z, Z);
+ fgopcode(o, n, &fregnode0, 0, 1);
+ }
+ goto com;
+ }
+ /* bad, 13 is address of external that becomes constant */
+ if(n->addable >= INDEXED && n->addable != 13) {
+ gopcode(o, n->type, n, nodconst(0));
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ gopcode(o, n->type, &nod, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(typev[l->type->etype]) {
+ if(!true)
+ n->op = comrel[relindex(o)];
+ cgen64(n, Z);
+ goto com;
+ }
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(typefd[l->type->etype]) {
+ if(l->complex >= r->complex) {
+ cgen(l, &fregnode0);
+ if(r->addable < INDEXED) {
+ cgen(r, &fregnode0);
+ o = invrel[relindex(o)];
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, r, &fregnode0, 0, 1);
+ } else {
+ o = invrel[relindex(o)];
+ cgen(r, &fregnode0);
+ if(l->addable < INDEXED) {
+ cgen(l, &fregnode0);
+ o = invrel[relindex(o)];
+ fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+ } else
+ fgopcode(o, l, &fregnode0, 0, 1);
+ }
+ goto com;
+ }
+ if(l->op == OCONST) {
+ o = invrel[relindex(o)];
+ /* bad, 13 is address of external that becomes constant */
+ if(r->addable < INDEXED || r->addable == 13) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l->type, &nod, l);
+ regfree(&nod);
+ } else
+ gopcode(o, l->type, r, l);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, &nod, r);
+ regfree(&nod);
+ goto com;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED || l->addable == 13) {
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(typechlp[l->type->etype])
+ gopcode(o, types[TINT], &nod1, &nod);
+ else
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, l, &nod);
+ regfree(&nod);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gmove(nodconst(1L), nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gmove(nodconst(0L), nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r;
+ Type *t;
+ int c, v, x;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ break;
+ }
+ else if(!vaddr(nn, 0)) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ gmove(lo64(n), &nod1);
+ nod1.xoffset += SZ_LONG;
+ gmove(hi64(n), &nod1);
+ regfree(&nod1);
+ }
+ else {
+ gins(AMOVL, lo64(n), nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn);
+ nn->xoffset -= SZ_LONG;
+ break;
+ }
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ cgen(&nod2, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = nil;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+ nod0.right = l;
+
+ /* prtree(&nod0, "hand craft"); /* */
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ h = nn;
+ if(nn->op == OREGPAIR) {
+ regsalloc(&nod1, nn);
+ nn = &nod1;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ if(h->op == OREGPAIR)
+ loadpair(nn->left, h);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+
+ case OASMUL:
+ case OASLMUL:
+
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gins(AMOVL, &nod1, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ x = 0;
+ v = w == 8;
+ if(v) {
+ c = cursafe;
+ if(n->left != Z && n->left->complex >= FNX
+ && n->right != Z && n->right->complex >= FNX) {
+// warn(n, "toughie");
+ regsalloc(&nod1, n->right);
+ cgen(n->right, &nod1);
+ nod2 = *n;
+ nod2.right = &nod1;
+ cgen(&nod2, nn);
+ cursafe = c;
+ return;
+ }
+ if(cgen64(n, nn)) {
+ cursafe = c;
+ return;
+ }
+ if(n->op == OCOM) {
+ n = n->left;
+ x = 1;
+ }
+ }
+
+ /* botch, need to save in .safe */
+ c = 0;
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ if(v) {
+ regalloc(&nod0, n, Z);
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ else {
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHL, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(v) {
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ }
+ else {
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+ gins(APUSHL, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ }
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(v) {
+ regalloc(&nod0, nn, Z);
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ }
+ else {
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+ gins(APUSHL, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ }
+
+ t = n->type;
+ n->type = types[TLONG];
+ if(v) {
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ else {
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHL, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+ }
+ if(v) {
+ gins(AMOVL, n, &nod0);
+ if(x)
+ gins(ANOTL, Z, &nod0);
+ gins(AMOVL, &nod0, nn);
+ n->xoffset += SZ_LONG;
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n, &nod0);
+ if(x)
+ gins(ANOTL, Z, &nod0);
+ gins(AMOVL, &nod0, nn);
+ n->xoffset -= SZ_LONG;
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod2)
+ regfree(&nod2);
+ if(n == &nod1)
+ regfree(&nod1);
+ regfree(&nod0);
+ return;
+ }
+ nodreg(&nod3, n, D_CX);
+ if(reg[D_CX]) {
+ gins(APUSHL, &nod3, Z);
+ c |= 4;
+ reg[D_CX]++;
+ }
+ gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
+ gins(ACLD, Z, Z);
+ gins(AREP, Z, Z);
+ gins(AMOVSL, Z, Z);
+ if(c & 4) {
+ gins(APOPL, Z, &nod3);
+ reg[D_CX]--;
+ }
+ if(c & 2) {
+ gins(APOPL, Z, &nod2);
+ reg[nod2.reg]--;
+ }
+ if(c & 1) {
+ gins(APOPL, Z, &nod1);
+ reg[nod1.reg]--;
+ }
+}
diff --git a/utils/8c/cgen64.c b/utils/8c/cgen64.c
new file mode 100644
index 00000000..6a1e835e
--- /dev/null
+++ b/utils/8c/cgen64.c
@@ -0,0 +1,2711 @@
+#include "gc.h"
+
+void
+zeroregm(Node *n)
+{
+ gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+ switch(n->op) {
+ case ONAME:
+ if(a)
+ return 1;
+ return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+ case OCONST:
+ case OREGISTER:
+ case OINDREG:
+ return 1;
+ }
+ return 0;
+}
+
+long
+hi64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)(n->vconst) & ~0L;
+ else
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+}
+
+long
+lo64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+ else
+ return (long)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+ return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+ return nodconst(lo64v(n));
+}
+
+static Node *
+anonreg(void)
+{
+ Node *n;
+
+ n = new(OREGISTER, Z, Z);
+ n->reg = D_NONE;
+ n->type = types[TLONG];
+ return n;
+}
+
+static Node *
+regpair(Node *n, Node *t)
+{
+ Node *r;
+
+ if(n != Z && n->op == OREGPAIR)
+ return n;
+ r = new(OREGPAIR, anonreg(), anonreg());
+ if(n != Z)
+ r->type = n->type;
+ else
+ r->type = t->type;
+ return r;
+}
+
+static void
+evacaxdx(Node *r)
+{
+ Node nod1, nod2;
+
+ if(r->reg == D_AX || r->reg == D_DX) {
+ reg[D_AX]++;
+ reg[D_DX]++;
+ /*
+ * this is just an optim that should
+ * check for spill
+ */
+ r->type = types[TULONG];
+ regalloc(&nod1, r, Z);
+ nodreg(&nod2, Z, r->reg);
+ gins(AMOVL, &nod2, &nod1);
+ regfree(r);
+ r->reg = nod1.reg;
+ reg[D_AX]--;
+ reg[D_DX]--;
+ }
+}
+
+/* lazy instantiation of register pair */
+static int
+instpair(Node *n, Node *l)
+{
+ int r;
+
+ r = 0;
+ if(n->left->reg == D_NONE) {
+ if(l != Z) {
+ n->left->reg = l->reg;
+ r = 1;
+ }
+ else
+ regalloc(n->left, n->left, Z);
+ }
+ if(n->right->reg == D_NONE)
+ regalloc(n->right, n->right, Z);
+ return r;
+}
+
+static void
+zapreg(Node *n)
+{
+ if(n->reg != D_NONE) {
+ regfree(n);
+ n->reg = D_NONE;
+ }
+}
+
+static void
+freepair(Node *n)
+{
+ regfree(n->left);
+ regfree(n->right);
+}
+
+/* n is not OREGPAIR, nn is */
+void
+loadpair(Node *n, Node *nn)
+{
+ Node nod;
+
+ instpair(nn, Z);
+ if(n->op == OCONST) {
+ gins(AMOVL, lo64(n), nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn->right);
+ n->xoffset -= SZ_LONG;
+ return;
+ }
+ if(!vaddr(n, 0)) {
+ /* steal the right register for the laddr */
+ nod = regnode;
+ nod.reg = nn->right->reg;
+ lcgen(n, &nod);
+ n = &nod;
+ regind(n, n);
+ n->xoffset = 0;
+ }
+ gins(AMOVL, n, nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, n, nn->right);
+ n->xoffset -= SZ_LONG;
+}
+
+/* n is OREGPAIR, nn is not */
+static void
+storepair(Node *n, Node *nn, int f)
+{
+ Node nod;
+
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod, nn, Z);
+ nn = &nod;
+ }
+ gins(AMOVL, n->left, nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n->right, nn);
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod)
+ regfree(&nod);
+ if(f)
+ freepair(n);
+}
+
+/* generate a cast t from n to tt */
+static void
+cast(Node *n, Type *t, Node *nn)
+{
+ Node *r;
+
+ r = new(OCAST, n, Z);
+ r->type = t;
+ sugen(r, nn, 8);
+}
+
+static void
+swapregs(Node *a, Node *b)
+{
+ int t;
+
+ t = a->reg;
+ a->reg = b->reg;
+ b->reg = t;
+}
+
+static void
+swappairs(Node *a, Node *b)
+{
+ swapregs(a->left, b->left);
+ swapregs(a->right, b->right);
+}
+
+static int
+saveme(Node *n)
+{
+ int r;
+
+ r = n->reg;
+ return r >= D_AX && r <= D_DI;
+}
+
+static void
+saveit(Node *n, Node *t, Node *r)
+{
+ Node nod;
+
+ if(saveme(n)) {
+ t->reg = n->reg;
+ gins(AMOVL, t, r);
+ r->xoffset += SZ_LONG;
+ if(n->reg == D_AX) {
+ regalloc(&nod, n, Z);
+ regfree(n);
+ n->reg = nod.reg;
+ }
+ }
+}
+
+static void
+restoreit(Node *n, Node *t, Node *r)
+{
+ if(saveme(n)) {
+ t->reg = n->reg;
+ gins(AMOVL, r, t);
+ r->xoffset += SZ_LONG;
+ }
+}
+
+enum
+{
+/* 4 only, see WW */
+ WNONE = 0,
+ WCONST,
+ WADDR,
+ WHARD,
+};
+
+static int
+whatof(Node *n, int a)
+{
+ if(n->op == OCONST)
+ return WCONST;
+ return !vaddr(n, a) ? WHARD : WADDR;
+}
+
+/* can upgrade an extern to addr for AND */
+static int
+reduxv(Node *n)
+{
+ return lo64v(n) == 0 || hi64v(n) == 0;
+}
+
+int
+cond(int op)
+{
+ switch(op) {
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * for a func operand call it and then return
+ * the safe node
+ */
+static Node *
+vfunc(Node *n, Node *nn)
+{
+ Node *t;
+
+ if(n->op != OFUNC)
+ return n;
+ t = new(0, Z, Z);
+ if(nn == Z || nn == nodret)
+ nn = n;
+ regsalloc(t, nn);
+ sugen(n, t, 8);
+ return t;
+}
+
+static int
+forcereg(Node *d, int r, int o, Node *t)
+{
+ int a;
+
+ if(d->reg != D_NONE)
+ diag(Z, "force alloc");
+ d->reg = r;
+ a = 0;
+ if(reg[r]) {
+ reg[o]++;
+ regalloc(t, d, Z);
+ a = 1;
+ gins(AMOVL, d, t);
+ reg[o]--;
+ }
+ reg[r]++;
+ return a;
+}
+
+/* try to steal a reg */
+static int
+getreg(Node **np, Node *t, int r)
+{
+ Node *n, *p;
+
+ n = *np;
+ if(n->reg == r) {
+ p = new(0, Z, Z);
+ regalloc(p, n, Z);
+ gins(AMOVL, n, p);
+ *t = *n;
+ *np = p;
+ return 1;
+ }
+ return 0;
+}
+
+static Node *
+snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
+{
+ if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
+ if(nodreg(t, Z, r)) {
+ regalloc(c, d, Z);
+ gins(AMOVL, t, c);
+ reg[r]++;
+ return c;
+ }
+ reg[r]++;
+ }
+ return Z;
+}
+
+enum
+{
+ Vstart = OEND,
+
+ Vgo,
+ Vamv,
+ Vmv,
+ Vzero,
+ Vop,
+ Vopx,
+ Vins,
+ Vins0,
+ Vinsl,
+ Vinsr,
+ Vinsla,
+ Vinsra,
+ Vinsx,
+ Vmul,
+ Vshll,
+ VT,
+ VF,
+ V_l_lo_f,
+ V_l_hi_f,
+ V_l_lo_t,
+ V_l_hi_t,
+ V_l_lo_u,
+ V_l_hi_u,
+ V_r_lo_f,
+ V_r_hi_f,
+ V_r_lo_t,
+ V_r_hi_t,
+ V_r_lo_u,
+ V_r_hi_u,
+ Vspazz,
+ Vend,
+
+ V_T0,
+ V_T1,
+ V_F0,
+ V_F1,
+
+ V_a0,
+ V_a1,
+ V_f0,
+ V_f1,
+
+ V_p0,
+ V_p1,
+ V_p2,
+ V_p3,
+ V_p4,
+
+ V_s0,
+ V_s1,
+ V_s2,
+ V_s3,
+ V_s4,
+
+ C00,
+ C01,
+ C31,
+ C32,
+
+ O_l_lo,
+ O_l_hi,
+ O_r_lo,
+ O_r_hi,
+ O_t_lo,
+ O_t_hi,
+ O_l,
+ O_r,
+ O_l_rp,
+ O_r_rp,
+ O_t_rp,
+ O_r0,
+ O_r1,
+ O_Zop,
+
+ O_a0,
+ O_a1,
+
+ V_C0,
+ V_C1,
+
+ V_S0,
+ V_S1,
+
+ VOPS = 5,
+ VLEN = 5,
+ VARGS = 2,
+
+ S00 = 0,
+ Sc0,
+ Sc1,
+ Sc2,
+ Sac3,
+ Sac4,
+ S10,
+
+ SAgen = 0,
+ SAclo,
+ SAc32,
+ SAchi,
+ SAdgen,
+ SAdclo,
+ SAdc32,
+ SAdchi,
+
+ B0c = 0,
+ Bca,
+ Bac,
+
+ T0i = 0,
+ Tii,
+
+ Bop0 = 0,
+ Bop1,
+};
+
+/*
+ * _testv:
+ * CMPL lo,$0
+ * JNE true
+ * CMPL hi,$0
+ * JNE true
+ * GOTO false
+ * false:
+ * GOTO code
+ * true:
+ * GOTO patchme
+ * code:
+ */
+
+static uchar testi[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, C00},
+ {V_s0, Vop, ONE, O_l_hi, C00},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+/* shift left general case */
+static uchar shll00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsl, ASHLL, O_r, O_l_rp},
+ {Vins, ASHLL, O_r, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, ASHLL, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, V_p0, Vend},
+};
+
+/* shift left rp, const < 32 */
+static uchar shllc0[][VLEN] =
+{
+ {Vinsl, ASHLL, O_r, O_l_rp},
+ {Vshll, O_r, O_l_lo, Vend},
+};
+
+/* shift left rp, const == 32 */
+static uchar shllc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left rp, const > 32 */
+static uchar shllc2[][VLEN] =
+{
+ {Vshll, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left addr, const == 32 */
+static uchar shllac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left addr, const > 32 */
+static uchar shllac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vshll, O_r, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left of constant */
+static uchar shll10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo, V_p0, Vend},
+};
+
+static uchar (*shlltab[])[VLEN] =
+{
+ shll00,
+ shllc0,
+ shllc1,
+ shllc2,
+ shllac3,
+ shllac4,
+ shll10,
+};
+
+/* shift right general case */
+static uchar shrl00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {V_p0, Vend},
+};
+
+/* shift right rp, const < 32 */
+static uchar shrlc0[][VLEN] =
+{
+ {Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vend},
+};
+
+/* shift right rp, const == 32 */
+static uchar shrlc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right rp, const > 32 */
+static uchar shrlc2[][VLEN] =
+{
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right addr, const == 32 */
+static uchar shrlac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right addr, const > 32 */
+static uchar shrlac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {Vins, O_a0, O_r, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right of constant */
+static uchar shrl10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vins, O_a0, O_r, O_t_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
+ {V_l_hi_u, V_S1},
+ {V_T1, Vzero, O_t_hi, V_p0},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+static uchar (*shrltab[])[VLEN] =
+{
+ shrl00,
+ shrlc0,
+ shrlc1,
+ shrlc2,
+ shrlac3,
+ shrlac4,
+ shrl10,
+};
+
+/* shift asop left general case */
+static uchar asshllgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi, V_p0},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const < 32 */
+static uchar asshllclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const == 32 */
+static uchar asshllc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop left, const > 32 */
+static uchar asshllchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest left general case */
+static uchar asdshllgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest left, const < 32 */
+static uchar asdshllclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vshll, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest left, const == 32 */
+static uchar asdshllc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshllchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vshll, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshlltab[])[VLEN] =
+{
+ asshllgen,
+ asshllclo,
+ asshllc32,
+ asshllchi,
+ asdshllgen,
+ asdshllclo,
+ asdshllc32,
+ asdshllchi,
+};
+
+/* shift asop right general case */
+static uchar asshrlgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vinsx, Bop0, O_r, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_p0, V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const < 32 */
+static uchar asshrlclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const == 32 */
+static uchar asshrlc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop right, const > 32 */
+static uchar asshrlchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vinsx, Bop0, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest right general case */
+static uchar asdshrlgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest right, const < 32 */
+static uchar asdshrlclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest right, const == 32 */
+static uchar asdshrlc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshrlchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshrltab[])[VLEN] =
+{
+ asshrlgen,
+ asshrlclo,
+ asshrlc32,
+ asshrlchi,
+ asdshrlgen,
+ asdshrlclo,
+ asdshrlc32,
+ asdshrlchi,
+};
+
+static uchar shrlargs[] = { ASHRL, 1 };
+static uchar sarlargs[] = { ASARL, 0 };
+
+/* ++ -- */
+static uchar incdec[][VLEN] =
+{
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* ++ -- *p */
+static uchar incdecpre[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_t_lo},
+ {Vinsx, Bop1, C00, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vend},
+};
+
+/* *p ++ -- */
+static uchar incdecpost[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* binop rp, rp */
+static uchar binop00[][VLEN] =
+{
+ {Vinsx, Bop0, O_r_lo, O_l_lo},
+ {Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
+ {Vend},
+};
+
+/* binop rp, addr */
+static uchar binoptmp[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vinsx, Bop0, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r_hi, O_r0},
+ {Vinsx, Bop1, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* binop t = *a op *b */
+static uchar binop11[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
+};
+
+/* binop t = rp +- c */
+static uchar add0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp & c */
+static uchar and0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp | c */
+static uchar or0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = c - rp */
+static uchar sub10[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vinsx, Bop0, O_r_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r_lo},
+ {Vinsx, Bop1, O_r_hi, O_r_lo},
+ {Vspazz, V_f0, Vend},
+};
+
+/* binop t = c + *b */
+static uchar addca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c & *b */
+static uchar andca[][VLEN] =
+{
+ {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vzero, O_t_lo},
+ {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {V_l_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c | *b */
+static uchar orca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c - *b */
+static uchar subca[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a +- c */
+static uchar addac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a | c */
+static uchar orac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a & c */
+static uchar andac[][VLEN] =
+{
+ {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vzero, O_t_lo},
+ {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
+ {V_r_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar ADDargs[] = { AADDL, AADCL };
+static uchar ANDargs[] = { AANDL, AANDL };
+static uchar ORargs[] = { AORL, AORL };
+static uchar SUBargs[] = { ASUBL, ASBBL };
+static uchar XORargs[] = { AXORL, AXORL };
+
+static uchar (*ADDtab[])[VLEN] =
+{
+ add0c, addca, addac,
+};
+
+static uchar (*ANDtab[])[VLEN] =
+{
+ and0c, andca, andac,
+};
+
+static uchar (*ORtab[])[VLEN] =
+{
+ or0c, orca, orac,
+};
+
+static uchar (*SUBtab[])[VLEN] =
+{
+ add0c, subca, addac,
+};
+
+/* mul of const32 */
+static uchar mulc32[][VLEN] =
+{
+ {V_a0, Vop, ONE, O_l_hi, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vmul, O_r_lo, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul of const64 */
+static uchar mulc64[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vmul, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vmul, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul general */
+static uchar mull[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AIMULL, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AIMULL, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* cast rp l to rp t */
+static uchar castrp[][VLEN] =
+{
+ {Vmv, O_l, O_t_lo},
+ {VT, Vins, AMOVL, O_t_lo, O_t_hi},
+ {VT, Vins, ASARL, C31, O_t_hi},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* cast rp l to addr t */
+static uchar castrpa[][VLEN] =
+{
+ {VT, V_a0, Vmv, O_l, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_lo},
+ {VT, Vins, ASARL, C31, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_hi},
+ {VT, V_f0},
+ {VF, Vmv, O_l, O_t_lo},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar netab0i[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, O_r_lo},
+ {V_s0, Vop, ONE, O_l_hi, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+static uchar netabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vop, ONE, O_r0, O_r_lo},
+ {V_s0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {V_f0, Vend},
+};
+
+static uchar cmptab0i[][VLEN] =
+{
+ {Vopx, Bop0, O_l_hi, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {Vend},
+};
+
+static uchar cmptabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vopx, Bop0, O_r0, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vins, AMOVL, O_l_lo, O_r0},
+ {Vopx, Bop1, O_r0, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {V_f0, Vend},
+};
+
+static uchar (*NEtab[])[VLEN] =
+{
+ netab0i, netabii,
+};
+
+static uchar (*cmptab[])[VLEN] =
+{
+ cmptab0i, cmptabii,
+};
+
+static uchar GEargs[] = { OGT, OHS };
+static uchar GTargs[] = { OGT, OHI };
+static uchar HIargs[] = { OHI, OHI };
+static uchar HSargs[] = { OHI, OHS };
+
+/* Big Generator */
+static void
+biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
+{
+ int i, j, g, oc, op, lo, ro, to, xo, *xp;
+ Type *lt;
+ Prog *pr[VOPS];
+ Node *ot, *tl, *tr, tmps[2];
+ uchar *c, (*cp)[VLEN], args[VARGS];
+
+ if(a != nil)
+ memmove(args, a, VARGS);
+//print("biggen %d %d %d\n", args[0], args[1], args[2]);
+//if(l) prtree(l, "l");
+//if(r) prtree(r, "r");
+//if(t) prtree(t, "t");
+ lo = ro = to = 0;
+ cp = code;
+
+ for (;;) {
+ c = *cp++;
+ g = 1;
+ i = 0;
+//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
+ for(;;) {
+ switch(op = c[i]) {
+ case Vgo:
+ if(g)
+ gbranch(OGOTO);
+ i++;
+ break;
+
+ case Vamv:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ if(g)
+ args[c[i - 1]] = args[c[i - 2]];
+ break;
+
+ case Vzero:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 1;
+ goto op;
+
+ case Vspazz: // nasty hack to save a reg in SUB
+//print("spazz\n");
+ if(g) {
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ ot = r->right;
+ r->right = r->left;
+ tl = new(0, Z, Z);
+ *tl = tmps[0];
+ r->left = tl;
+ tmps[0] = *ot;
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ }
+ i++;
+ break;
+
+ case Vmv:
+ case Vmul:
+ case Vshll:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ case Vins0:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ gins(c[i - 1], Z, Z);
+ break;
+
+ case Vop:
+ case Vopx:
+ case Vins:
+ case Vinsl:
+ case Vinsr:
+ case Vinsla:
+ case Vinsra:
+ case Vinsx:
+ i += 4;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ op:
+ if(!g)
+ break;
+ tl = Z;
+ tr = Z;
+ for(; j < i; j++) {
+ switch(c[j]) {
+ case C00:
+ ot = nodconst(0);
+ break;
+ case C01:
+ ot = nodconst(1);
+ break;
+ case C31:
+ ot = nodconst(31);
+ break;
+ case C32:
+ ot = nodconst(32);
+ break;
+
+ case O_l:
+ case O_l_lo:
+ ot = l; xp = &lo; xo = 0;
+ goto op0;
+ case O_l_hi:
+ ot = l; xp = &lo; xo = SZ_LONG;
+ goto op0;
+ case O_r:
+ case O_r_lo:
+ ot = r; xp = &ro; xo = 0;
+ goto op0;
+ case O_r_hi:
+ ot = r; xp = &ro; xo = SZ_LONG;
+ goto op0;
+ case O_t_lo:
+ ot = t; xp = &to; xo = 0;
+ goto op0;
+ case O_t_hi:
+ ot = t; xp = &to; xo = SZ_LONG;
+ goto op0;
+ case O_l_rp:
+ ot = l;
+ break;
+ case O_r_rp:
+ ot = r;
+ break;
+ case O_t_rp:
+ ot = t;
+ break;
+ case O_r0:
+ case O_r1:
+ ot = &tmps[c[j] - O_r0];
+ break;
+ case O_Zop:
+ ot = Z;
+ break;
+
+ op0:
+ switch(ot->op) {
+ case OCONST:
+ if(xo)
+ ot = hi64(ot);
+ else
+ ot = lo64(ot);
+ break;
+ case OREGPAIR:
+ if(xo)
+ ot = ot->right;
+ else
+ ot = ot->left;
+ break;
+ case OREGISTER:
+ break;
+ default:
+ if(xo != *xp) {
+ ot->xoffset += xo - *xp;
+ *xp = xo;
+ }
+ }
+ break;
+
+ default:
+ diag(l, "bad V_lop");
+ return;
+ }
+ if(tl == nil)
+ tl = ot;
+ else
+ tr = ot;
+ }
+ if(op == Vzero) {
+ zeroregm(tl);
+ break;
+ }
+ oc = c[i - 3];
+ if(op == Vinsx || op == Vopx) {
+//print("%d -> %d\n", oc, args[oc]);
+ oc = args[oc];
+ }
+ else {
+ switch(oc) {
+ case O_a0:
+ case O_a1:
+ oc = args[oc - O_a0];
+ break;
+ }
+ }
+ switch(op) {
+ case Vmul:
+ mulgen(tr->type, tl, tr);
+ break;
+ case Vmv:
+ gmove(tl, tr);
+ break;
+ case Vshll:
+ shiftit(tr->type, tl, tr);
+ break;
+ case Vop:
+ case Vopx:
+ gopcode(oc, types[TULONG], tl, tr);
+ break;
+ case Vins:
+ case Vinsx:
+ gins(oc, tl, tr);
+ break;
+ case Vinsl:
+ gins(oc, tl, tr->right);
+ p->from.index = tr->left->reg;
+ break;
+ case Vinsr:
+ gins(oc, tl, tr->left);
+ p->from.index = tr->right->reg;
+ break;
+ case Vinsla:
+ gins(oc, tl, tr + 1);
+ p->from.index = tr->reg;
+ break;
+ case Vinsra:
+ gins(oc, tl, tr);
+ p->from.index = (tr + 1)->reg;
+ break;
+ }
+ break;
+
+ case VT:
+ g = true;
+ i++;
+ break;
+ case VF:
+ g = !true;
+ i++;
+ break;
+
+ case V_T0: case V_T1:
+ g = args[op - V_T0];
+ i++;
+ break;
+
+ case V_F0: case V_F1:
+ g = !args[op - V_F0];
+ i++;
+ break;
+
+ case V_C0: case V_C1:
+ if(g)
+ args[op - V_C0] = 0;
+ i++;
+ break;
+
+ case V_S0: case V_S1:
+ if(g)
+ args[op - V_S0] = 1;
+ i++;
+ break;
+
+ case V_l_lo_f:
+ g = lo64v(l) == 0;
+ i++;
+ break;
+ case V_l_hi_f:
+ g = hi64v(l) == 0;
+ i++;
+ break;
+ case V_l_lo_t:
+ g = lo64v(l) != 0;
+ i++;
+ break;
+ case V_l_hi_t:
+ g = hi64v(l) != 0;
+ i++;
+ break;
+ case V_l_lo_u:
+ g = lo64v(l) >= 0;
+ i++;
+ break;
+ case V_l_hi_u:
+ g = hi64v(l) >= 0;
+ i++;
+ break;
+ case V_r_lo_f:
+ g = lo64v(r) == 0;
+ i++;
+ break;
+ case V_r_hi_f:
+ g = hi64v(r) == 0;
+ i++;
+ break;
+ case V_r_lo_t:
+ g = lo64v(r) != 0;
+ i++;
+ break;
+ case V_r_hi_t:
+ g = hi64v(r) != 0;
+ i++;
+ break;
+ case V_r_lo_u:
+ g = lo64v(r) >= 0;
+ i++;
+ break;
+ case V_r_hi_u:
+ g = hi64v(r) >= 0;
+ i++;
+ break;
+
+ case Vend:
+ goto out;
+
+ case V_a0: case V_a1:
+ if(g) {
+ lt = l->type;
+ l->type = types[TULONG];
+ regalloc(&tmps[op - V_a0], l, Z);
+ l->type = lt;
+ }
+ i++;
+ break;
+
+ case V_f0: case V_f1:
+ if(g)
+ regfree(&tmps[op - V_f0]);
+ i++;
+ break;
+
+ case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
+ if(g)
+ patch(pr[op - V_p0], pc);
+ i++;
+ break;
+
+ case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
+ if(g)
+ pr[op - V_s0] = p;
+ i++;
+ break;
+
+ default:
+ diag(l, "bad biggen: %d", op);
+ return;
+ }
+ if(i == VLEN || c[i] == 0)
+ break;
+ }
+ }
+out:
+ if(lo)
+ l->xoffset -= lo;
+ if(ro)
+ r->xoffset -= ro;
+ if(to)
+ t->xoffset -= to;
+}
+
+int
+cgen64(Node *n, Node *nn)
+{
+ Type *dt;
+ uchar *args, (*cp)[VLEN], (**optab)[VLEN];
+ int li, ri, lri, dr, si, m, op, sh, cmp, true;
+ Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
+
+ if(debug['g']) {
+ prtree(nn, "cgen64 lhs");
+ prtree(n, "cgen64");
+ print("AX = %d\n", reg[D_AX]);
+ }
+ cmp = 0;
+ sh = 0;
+
+ switch(n->op) {
+ case ONEG:
+ d = regpair(nn, n);
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->right);
+ gins(ANEGL, Z, d->left);
+ gins(ASBBL, nodconst(-1), d->right);
+ break;
+
+ case OCOM:
+ if(!vaddr(n->left, 0) || !vaddr(nn, 0))
+ d = regpair(nn, n);
+ else
+ return 0;
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->left);
+ gins(ANOTL, Z, d->right);
+ break;
+
+ case OADD:
+ optab = ADDtab;
+ args = ADDargs;
+ goto twoop;
+ case OAND:
+ optab = ANDtab;
+ args = ANDargs;
+ goto twoop;
+ case OOR:
+ optab = ORtab;
+ args = ORargs;
+ goto twoop;
+ case OSUB:
+ optab = SUBtab;
+ args = SUBargs;
+ goto twoop;
+ case OXOR:
+ optab = ORtab;
+ args = XORargs;
+ goto twoop;
+ case OASHL:
+ sh = 1;
+ args = nil;
+ optab = shlltab;
+ goto twoop;
+ case OLSHR:
+ sh = 1;
+ args = shrlargs;
+ optab = shrltab;
+ goto twoop;
+ case OASHR:
+ sh = 1;
+ args = sarlargs;
+ optab = shrltab;
+ goto twoop;
+ case OEQ:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case ONE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHI:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLO:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+
+twoop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ if(sh)
+ r = n->right;
+ else
+ r = vfunc(n->right, nn);
+
+ li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
+ ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
+
+#define IMM(l, r) ((l) | ((r) << 1))
+
+ lri = IMM(li, ri);
+
+ /* find out what is so easy about some operands */
+ if(li)
+ li = whatof(l, sh | cmp);
+ if(ri)
+ ri = whatof(r, cmp);
+
+ if(sh)
+ goto shift;
+
+ if(cmp)
+ goto cmp;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ switch(lri) {
+ case IMM(0, 0):
+ bin00:
+ if(l->complex > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
+ lri = IMM(0, 0);
+ goto bin00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+#define WW(l, r) ((l) | ((r) << 2))
+ d = Z;
+ dt = nn->type;
+ nn->type = types[TLONG];
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, binop00, args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, 0, binoptmp, args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB) {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ case WCONST:
+ biggen(l, r, Z, 0, sub10, args);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ }
+ else {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(r, l, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(r, l, Z, 0, binoptmp, args);
+ if(li == WHARD)
+ regfree(l);
+ break;
+ }
+ }
+ break;
+ case IMM(1, 1):
+ switch(WW(li, ri)) {
+ case WW(WCONST, WHARD):
+ if(r->op == ONAME && n->op == OAND && reduxv(l))
+ ri = WADDR;
+ break;
+ case WW(WHARD, WCONST):
+ if(l->op == ONAME && n->op == OAND && reduxv(r))
+ li = WADDR;
+ break;
+ }
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WCONST, WADDR):
+ case WW(WCONST, WHARD):
+ biggen(l, r, d, 0, optab[Bca], args);
+ break;
+
+ case WW(WADDR, WCONST):
+ case WW(WHARD, WCONST):
+ biggen(l, r, d, 0, optab[Bac], args);
+ break;
+
+ case WW(WADDR, WADDR):
+ case WW(WADDR, WHARD):
+ case WW(WHARD, WADDR):
+ case WW(WHARD, WHARD):
+ biggen(l, r, d, 0, binop11, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ nn->type = dt;
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ if(!dr)
+ storepair(r, nn, 1);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ shift:
+ c = Z;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ /* must also secure CX. not as many optims as binop. */
+ switch(lri) {
+ case IMM(0, 0):
+ imm00:
+ if(l->complex + 1 > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = &nod1;
+ c = snarfreg(l, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ }
+ else {
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ imm01:
+ if(ri != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ imm10:
+ if(li != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ break;
+ case IMM(1, 1):
+ if(ri != WCONST) {
+ lri = IMM(1, 0);
+ goto imm10;
+ }
+ if(li == WHARD) {
+ lri = IMM(0, 1);
+ goto imm01;
+ }
+ break;
+ }
+
+ d = Z;
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, optab[S00], args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ case WADDR:
+ case WHARD:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32)
+ cp = optab[Sc0];
+ else if(m == 32)
+ cp = optab[Sc1];
+ else
+ cp = optab[Sc2];
+ biggen(l, s, Z, 0, cp, args);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ /* left is const */
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[S10], args);
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WADDR, WCONST):
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32) {
+ loadpair(l, d);
+ l = d;
+ cp = optab[Sc0];
+ }
+ else if(m == 32)
+ cp = optab[Sac3];
+ else
+ cp = optab[Sac4];
+ biggen(l, s, d, 0, cp, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ break;
+ }
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ regfree(r);
+ /* fall thru */
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ cmp:
+ op = n->op;
+ /* evaluate hard subexps */
+ switch(lri) {
+ case IMM(0, 0):
+ if(l->complex > r->complex) {
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(1, 0):
+ t = r;
+ r = l;
+ l = t;
+ ri = li;
+ op = invrel[relindex(op)];
+ /* fall thru */
+ case IMM(0, 1):
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+ true = 1;
+ optab = cmptab;
+ switch(op) {
+ case OEQ:
+ optab = NEtab;
+ true = 0;
+ break;
+ case ONE:
+ optab = NEtab;
+ break;
+ case OLE:
+ args = GTargs;
+ true = 0;
+ break;
+ case OGT:
+ args = GTargs;
+ break;
+ case OLS:
+ args = HIargs;
+ true = 0;
+ break;
+ case OHI:
+ args = HIargs;
+ break;
+ case OLT:
+ args = GEargs;
+ true = 0;
+ break;
+ case OGE:
+ args = GEargs;
+ break;
+ case OLO:
+ args = HSargs;
+ true = 0;
+ break;
+ case OHS:
+ args = HSargs;
+ break;
+ default:
+ diag(n, "bad cmp\n");
+ SET(optab);
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ switch(ri) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, true, optab[T0i], args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 1):
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ biggen(l, r, Z, true, optab[Tii], args);
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ freepair(l);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ case OASMUL:
+ case OASLMUL:
+ m = 0;
+ goto mulop;
+
+ case OMUL:
+ case OLMUL:
+ m = 1;
+ goto mulop;
+
+ mulop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ r = vfunc(n->right, nn);
+ if(r->op != OCONST) {
+ if(l->complex > r->complex) {
+ if(m) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ else if(!vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ evacaxdx(r->left);
+ evacaxdx(r->right);
+ if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ c = Z;
+ d = Z;
+ if(!nodreg(&nod1, t->left, D_AX)) {
+ if(t->left->reg != D_AX){
+ t->left->reg = D_AX;
+ reg[D_AX]++;
+ }else if(reg[D_AX] == 0)
+ fatal(Z, "vlong mul AX botch");
+ }
+ if(!nodreg(&nod2, t->right, D_DX)) {
+ if(t->right->reg != D_DX){
+ t->right->reg = D_DX;
+ reg[D_DX]++;
+ }else if(reg[D_DX] == 0)
+ fatal(Z, "vlong mul DX botch");
+ }
+ if(m)
+ sugen(l, t, 8);
+ else
+ loadpair(l, t);
+ if(t->left->reg != D_AX) {
+ c = &nod3;
+ regsalloc(c, t->left);
+ gmove(&nod1, c);
+ gmove(t->left, &nod1);
+ zapreg(t->left);
+ }
+ if(t->right->reg != D_DX) {
+ d = &nod4;
+ regsalloc(d, t->right);
+ gmove(&nod2, d);
+ gmove(t->right, &nod2);
+ zapreg(t->right);
+ }
+ if(c != Z || d != Z) {
+ s = regpair(Z, n);
+ s->left = &nod1;
+ s->right = &nod2;
+ }
+ else
+ s = t;
+ if(r->op == OCONST) {
+ if(hi64v(r) == 0)
+ biggen(s, r, Z, 0, mulc32, nil);
+ else
+ biggen(s, r, Z, 0, mulc64, nil);
+ }
+ else
+ biggen(s, r, Z, 0, mull, nil);
+ instpair(t, Z);
+ if(c != Z) {
+ gmove(&nod1, t->left);
+ gmove(&nod3, &nod1);
+ }
+ if(d != Z) {
+ gmove(&nod2, t->right);
+ gmove(&nod4, &nod2);
+ }
+ if(r->op == OREGPAIR)
+ freepair(r);
+ if(!m)
+ storepair(t, l, 0);
+ if(l == &nod5)
+ regfree(l);
+ if(!dr) {
+ if(nn != Z)
+ storepair(t, nn, 1);
+ else
+ freepair(t);
+ }
+ return 1;
+
+ case OASADD:
+ args = ADDargs;
+ goto vasop;
+ case OASAND:
+ args = ANDargs;
+ goto vasop;
+ case OASOR:
+ args = ORargs;
+ goto vasop;
+ case OASSUB:
+ args = SUBargs;
+ goto vasop;
+ case OASXOR:
+ args = XORargs;
+ goto vasop;
+
+ vasop:
+ l = n->left;
+ r = n->right;
+ dr = nn != Z && nn->op == OREGPAIR;
+ m = 0;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ }
+ else {
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+ if(nn != Z) {
+ if(n->op == OASSUB)
+ biggen(l, r, Z, 0, sub10, args);
+ else
+ biggen(r, l, Z, 0, binoptmp, args);
+ storepair(r, l, 0);
+ }
+ else {
+ if(m)
+ biggen(l, r, Z, 0, binop00, args);
+ else
+ biggen(l, r, Z, 0, binoptmp, args);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(m) {
+ if(nn == Z)
+ freepair(r);
+ else if(!dr)
+ storepair(r, nn, 1);
+ }
+ return 1;
+
+ case OASASHL:
+ args = nil;
+ optab = asshlltab;
+ goto assh;
+ case OASLSHR:
+ args = shrlargs;
+ optab = asshrltab;
+ goto assh;
+ case OASASHR:
+ args = sarlargs;
+ optab = asshrltab;
+ goto assh;
+
+ assh:
+ c = Z;
+ l = n->left;
+ r = n->right;
+ if(r->op == OCONST) {
+ m = r->vconst & 63;
+ if(m < 32)
+ m = SAclo;
+ else if(m == 32)
+ m = SAc32;
+ else
+ m = SAchi;
+ }
+ else
+ m = SAgen;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(m == SAgen) {
+ t = &nod2;
+ if(l->reg == D_CX) {
+ regalloc(t, r, Z);
+ gmove(l, t);
+ l->reg = t->reg;
+ t->reg = D_CX;
+ }
+ else
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ }
+ else {
+ if(m == SAgen) {
+ t = &nod2;
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+
+ if(nn != Z) {
+ m += SAdgen - SAgen;
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[m], args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(r == &nod2 && c == Z) {
+ regfree(&nod2);
+ r = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, r, Z, 0, optab[m], args);
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(r == &nod2)
+ regfree(&nod2);
+ return 1;
+
+ case OPOSTINC:
+ args = ADDargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPOSTDEC:
+ args = SUBargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPREINC:
+ args = ADDargs;
+ cp = incdecpre;
+ goto vinc;
+ case OPREDEC:
+ args = SUBargs;
+ cp = incdecpre;
+ goto vinc;
+
+ vinc:
+ l = n->left;
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+
+ if(nn != Z) {
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, Z, d, 0, cp, args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, Z, Z, 0, incdec, args);
+
+ if(l == &nod1)
+ regfree(&nod1);
+ return 1;
+
+ case OCAST:
+ l = n->left;
+ if(typev[l->type->etype]) {
+ if(!vaddr(l, 1)) {
+ if(l->complex + 1 > nn->complex) {
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ }
+ else {
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ }
+// d->left->type = r->type;
+ d->left->type = types[TLONG];
+ gmove(d->left, r);
+ freepair(d);
+ }
+ else {
+ if(nn->op != OREGISTER && !vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+// l->type = r->type;
+ l->type = types[TLONG];
+ gmove(l, r);
+ }
+ if(r != nn)
+ regfree(r);
+ }
+ else {
+ if(typeu[l->type->etype] || cond(l->op))
+ si = TUNSIGNED;
+ else
+ si = TSIGNED;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(nn->op == OREGPAIR) {
+ m = instpair(nn, &nod1);
+ biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
+ }
+ else {
+ m = 0;
+ if(!vaddr(nn, si != TSIGNED)) {
+ dt = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = dt;
+ nn = &nod2;
+ }
+ dt = nn->type;
+ nn->type = types[TLONG];
+ biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
+ nn->type = dt;
+ if(nn == &nod2)
+ regfree(&nod2);
+ }
+ if(!m)
+ regfree(&nod1);
+ }
+ return 1;
+
+ default:
+ if(n->op == OREGPAIR) {
+ storepair(n, nn, 1);
+ return 1;
+ }
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ return 1;
+ }
+ return 0;
+ }
+finished:
+ if(d != nn)
+ storepair(d, nn, 1);
+ return 1;
+}
+
+void
+testv(Node *n, int true)
+{
+ Type *t;
+ Node *nn, nod;
+
+ switch(n->op) {
+ case OINDREG:
+ case ONAME:
+ biggen(n, Z, Z, true, testi, nil);
+ break;
+
+ default:
+ n = vfunc(n, n);
+ if(n->addable >= INDEXED) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod, n, Z);
+ n->type = t;
+ n = &nod;
+ biggen(n, Z, Z, true, testi, nil);
+ if(n == &nod)
+ regfree(n);
+ }
+ else {
+ nn = regpair(Z, n);
+ sugen(n, nn, 8);
+ biggen(nn, Z, Z, true, testi, nil);
+ freepair(nn);
+ }
+ }
+}
diff --git a/utils/8c/div.c b/utils/8c/div.c
new file mode 100644
index 00000000..cb588678
--- /dev/null
+++ b/utils/8c/div.c
@@ -0,0 +1,206 @@
+#include "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define TN(n) ((uvlong)1 << (n))
+#define T31 TN(31)
+#define T32 TN(32)
+
+int
+multiplier(ulong d, int p, uvlong *mp)
+{
+ int l;
+ uvlong mlo, mhi, tlo, thi;
+
+ l = topbit(d - 1) + 1;
+ mlo = (((TN(l) - d) << 32) / d) + T32;
+ if(l + p == 64)
+ mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+ else
+ mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+ /*assert(mlo < mhi);*/
+ while(l > 0) {
+ tlo = mlo >> 1;
+ thi = mhi >> 1;
+ if(tlo == thi)
+ break;
+ mlo = tlo;
+ mhi = thi;
+ l--;
+ }
+ *mp = mhi;
+ return l;
+}
+
+int
+sdiv(ulong d, ulong *mp, int *sp)
+{
+ int s;
+ uvlong m;
+
+ s = multiplier(d, 32 - 1, &m);
+ *mp = m;
+ *sp = s;
+ if(m >= T31)
+ return 1;
+ else
+ return 0;
+}
+
+int
+udiv(ulong d, ulong *mp, int *sp, int *pp)
+{
+ int p, s;
+ uvlong m;
+
+ s = multiplier(d, 32, &m);
+ p = 0;
+ if(m >= T32) {
+ while((d & 1) == 0) {
+ d >>= 1;
+ p++;
+ }
+ s = multiplier(d, 32 - p, &m);
+ }
+ *mp = m;
+ *pp = p;
+ if(m >= T32) {
+ /*assert(p == 0);*/
+ *sp = s - 1;
+ return 1;
+ }
+ else {
+ *sp = s;
+ return 0;
+ }
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s;
+ ulong m;
+ vlong c;
+
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ a = sdiv(c, &m, &s);
+//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
+ gins(AMOVL, nodconst(m), ax);
+ gins(AIMULL, l, Z);
+ gins(AMOVL, l, ax);
+ if(a)
+ gins(AADDL, ax, dx);
+ gins(ASHRL, nodconst(31), ax);
+ gins(ASARL, nodconst(s), dx);
+ gins(AADDL, ax, dx);
+ if(r->vconst < 0)
+ gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s, t;
+ ulong m;
+ Node nod;
+
+ a = udiv(r->vconst, &m, &s, &t);
+//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
+ if(t != 0) {
+ gins(AMOVL, l, ax);
+ gins(ASHRL, nodconst(t), ax);
+ gins(AMOVL, nodconst(m), dx);
+ gins(AMULL, dx, Z);
+ }
+ else if(a) {
+ if(l->op != OREGISTER) {
+ regalloc(&nod, l, Z);
+ gins(AMOVL, l, &nod);
+ l = &nod;
+ }
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ gins(AADDL, l, dx);
+ gins(ARCRL, nodconst(1), dx);
+ if(l == &nod)
+ regfree(l);
+ }
+ else {
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ }
+ if(s != 0)
+ gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+ if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+ reg[D_DX]++;
+ gins(ACDQ, Z, Z);
+ }
+ else {
+ regalloc(d, l, Z);
+ gins(AMOVL, s, d);
+ gins(ASARL, nodconst(31), d);
+ }
+}
+
+void
+sdiv2(long c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(v > 0) {
+ if(v > 1) {
+ sext(&nod, n, l);
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ regfree(&nod);
+ }
+ else {
+ gins(ACMPL, n, nodconst(0x80000000));
+ gins(ASBBL, nodconst(-1), n);
+ }
+ gins(ASARL, nodconst(v), n);
+ }
+ if(c < 0)
+ gins(ANEGL, Z, n);
+}
+
+void
+smod2(long c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(c == 1) {
+ zeroregm(n);
+ return;
+ }
+
+ sext(&nod, n, l);
+ if(v == 0) {
+ zeroregm(n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ else if(v > 1) {
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ gins(AANDL, nodconst((1 << v) - 1), n);
+ gins(ASUBL, &nod, n);
+ }
+ else {
+ gins(AANDL, nodconst(1), n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ regfree(&nod);
+}
diff --git a/utils/8c/enam.c b/utils/8c/enam.c
new file mode 100644
index 00000000..3e293a28
--- /dev/null
+++ b/utils/8c/enam.c
@@ -0,0 +1,337 @@
+char* anames[] =
+{
+ "XXX",
+ "AAA",
+ "AAD",
+ "AAM",
+ "AAS",
+ "ADCB",
+ "ADCL",
+ "ADCW",
+ "ADDB",
+ "ADDL",
+ "ADDW",
+ "ADJSP",
+ "ANDB",
+ "ANDL",
+ "ANDW",
+ "ARPL",
+ "BOUNDL",
+ "BOUNDW",
+ "BSFL",
+ "BSFW",
+ "BSRL",
+ "BSRW",
+ "BTL",
+ "BTW",
+ "BTCL",
+ "BTCW",
+ "BTRL",
+ "BTRW",
+ "BTSL",
+ "BTSW",
+ "BYTE",
+ "CALL",
+ "CLC",
+ "CLD",
+ "CLI",
+ "CLTS",
+ "CMC",
+ "CMPB",
+ "CMPL",
+ "CMPW",
+ "CMPSB",
+ "CMPSL",
+ "CMPSW",
+ "DAA",
+ "DAS",
+ "DATA",
+ "DECB",
+ "DECL",
+ "DECW",
+ "DIVB",
+ "DIVL",
+ "DIVW",
+ "ENTER",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "HLT",
+ "IDIVB",
+ "IDIVL",
+ "IDIVW",
+ "IMULB",
+ "IMULL",
+ "IMULW",
+ "INB",
+ "INL",
+ "INW",
+ "INCB",
+ "INCL",
+ "INCW",
+ "INSB",
+ "INSL",
+ "INSW",
+ "INT",
+ "INTO",
+ "IRETL",
+ "IRETW",
+ "JCC",
+ "JCS",
+ "JCXZ",
+ "JEQ",
+ "JGE",
+ "JGT",
+ "JHI",
+ "JLE",
+ "JLS",
+ "JLT",
+ "JMI",
+ "JMP",
+ "JNE",
+ "JOC",
+ "JOS",
+ "JPC",
+ "JPL",
+ "JPS",
+ "LAHF",
+ "LARL",
+ "LARW",
+ "LEAL",
+ "LEAW",
+ "LEAVEL",
+ "LEAVEW",
+ "LOCK",
+ "LODSB",
+ "LODSL",
+ "LODSW",
+ "LONG",
+ "LOOP",
+ "LOOPEQ",
+ "LOOPNE",
+ "LSLL",
+ "LSLW",
+ "MOVB",
+ "MOVL",
+ "MOVW",
+ "MOVBLSX",
+ "MOVBLZX",
+ "MOVBWSX",
+ "MOVBWZX",
+ "MOVWLSX",
+ "MOVWLZX",
+ "MOVSB",
+ "MOVSL",
+ "MOVSW",
+ "MULB",
+ "MULL",
+ "MULW",
+ "NAME",
+ "NEGB",
+ "NEGL",
+ "NEGW",
+ "NOP",
+ "NOTB",
+ "NOTL",
+ "NOTW",
+ "ORB",
+ "ORL",
+ "ORW",
+ "OUTB",
+ "OUTL",
+ "OUTW",
+ "OUTSB",
+ "OUTSL",
+ "OUTSW",
+ "POPAL",
+ "POPAW",
+ "POPFL",
+ "POPFW",
+ "POPL",
+ "POPW",
+ "PUSHAL",
+ "PUSHAW",
+ "PUSHFL",
+ "PUSHFW",
+ "PUSHL",
+ "PUSHW",
+ "RCLB",
+ "RCLL",
+ "RCLW",
+ "RCRB",
+ "RCRL",
+ "RCRW",
+ "REP",
+ "REPN",
+ "RET",
+ "ROLB",
+ "ROLL",
+ "ROLW",
+ "RORB",
+ "RORL",
+ "RORW",
+ "SAHF",
+ "SALB",
+ "SALL",
+ "SALW",
+ "SARB",
+ "SARL",
+ "SARW",
+ "SBBB",
+ "SBBL",
+ "SBBW",
+ "SCASB",
+ "SCASL",
+ "SCASW",
+ "SETCC",
+ "SETCS",
+ "SETEQ",
+ "SETGE",
+ "SETGT",
+ "SETHI",
+ "SETLE",
+ "SETLS",
+ "SETLT",
+ "SETMI",
+ "SETNE",
+ "SETOC",
+ "SETOS",
+ "SETPC",
+ "SETPL",
+ "SETPS",
+ "CDQ",
+ "CWD",
+ "SHLB",
+ "SHLL",
+ "SHLW",
+ "SHRB",
+ "SHRL",
+ "SHRW",
+ "STC",
+ "STD",
+ "STI",
+ "STOSB",
+ "STOSL",
+ "STOSW",
+ "SUBB",
+ "SUBL",
+ "SUBW",
+ "SYSCALL",
+ "TESTB",
+ "TESTL",
+ "TESTW",
+ "TEXT",
+ "VERR",
+ "VERW",
+ "WAIT",
+ "WORD",
+ "XCHGB",
+ "XCHGL",
+ "XCHGW",
+ "XLAT",
+ "XORB",
+ "XORL",
+ "XORW",
+ "FMOVB",
+ "FMOVBP",
+ "FMOVD",
+ "FMOVDP",
+ "FMOVF",
+ "FMOVFP",
+ "FMOVL",
+ "FMOVLP",
+ "FMOVV",
+ "FMOVVP",
+ "FMOVW",
+ "FMOVWP",
+ "FMOVX",
+ "FMOVXP",
+ "FCOMB",
+ "FCOMBP",
+ "FCOMD",
+ "FCOMDP",
+ "FCOMDPP",
+ "FCOMF",
+ "FCOMFP",
+ "FCOML",
+ "FCOMLP",
+ "FCOMW",
+ "FCOMWP",
+ "FUCOM",
+ "FUCOMP",
+ "FUCOMPP",
+ "FADDDP",
+ "FADDW",
+ "FADDL",
+ "FADDF",
+ "FADDD",
+ "FMULDP",
+ "FMULW",
+ "FMULL",
+ "FMULF",
+ "FMULD",
+ "FSUBDP",
+ "FSUBW",
+ "FSUBL",
+ "FSUBF",
+ "FSUBD",
+ "FSUBRDP",
+ "FSUBRW",
+ "FSUBRL",
+ "FSUBRF",
+ "FSUBRD",
+ "FDIVDP",
+ "FDIVW",
+ "FDIVL",
+ "FDIVF",
+ "FDIVD",
+ "FDIVRDP",
+ "FDIVRW",
+ "FDIVRL",
+ "FDIVRF",
+ "FDIVRD",
+ "FXCHD",
+ "FFREE",
+ "FLDCW",
+ "FLDENV",
+ "FRSTOR",
+ "FSAVE",
+ "FSTCW",
+ "FSTENV",
+ "FSTSW",
+ "F2XM1",
+ "FABS",
+ "FCHS",
+ "FCLEX",
+ "FCOS",
+ "FDECSTP",
+ "FINCSTP",
+ "FINIT",
+ "FLD1",
+ "FLDL2E",
+ "FLDL2T",
+ "FLDLG2",
+ "FLDLN2",
+ "FLDPI",
+ "FLDZ",
+ "FNOP",
+ "FPATAN",
+ "FPREM",
+ "FPREM1",
+ "FPTAN",
+ "FRNDINT",
+ "FSCALE",
+ "FSIN",
+ "FSINCOS",
+ "FSQRT",
+ "FTST",
+ "FXAM",
+ "FXTRACT",
+ "FYL2X",
+ "FYL2XP1",
+ "END",
+ "DYNT",
+ "INIT",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/8c/gc.h b/utils/8c/gc.h
new file mode 100644
index 00000000..4aeb11c0
--- /dev/null
+++ b/utils/8c/gc.h
@@ -0,0 +1,374 @@
+#include "../cc/cc.h"
+#include "../8c/8.out.h"
+
+/*
+ * 8c/386
+ * Intel 386
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Renv Renv;
+
+EXTERN struct
+{
+ Node* regtree;
+ Node* basetree;
+ short scale;
+ short reg;
+ short ptr;
+} idx;
+
+struct Adr
+{
+ long offset;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+struct Renv
+{
+ int safe;
+ Node base;
+ Node* saved;
+ Node* scope;
+};
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN int retok;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN Node fregnode0;
+EXTERN Node fregnode1;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[D_NONE];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+EXTERN int suppress;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+void indx(Node*);
+int bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void zeroregm(Node*);
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+int needreg(Node*, int);
+
+/*
+ * cgen64.c
+ */
+int vaddr(Node*, int);
+void loadpair(Node*, Node*);
+int cgen64(Node*, Node*);
+void testv(Node*, int);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nodfconst(double);
+int nodreg(Node*, Node*, int);
+int isreg(Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void fgopcode(int, Node*, Node*, int, int);
+void gopcode(int, Type*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Rconv(Fmt*);
+int Xconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+/*
+ * bound
+ */
+void comtarg(void);
+
+/*
+ * com64
+ */
+int cond(int);
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+long lo64v(Node*);
+long hi64v(Node*);
+Node* lo64(Node*);
+Node* hi64(Node*);
+
+/*
+ * div/mul
+ */
+void sdivgen(Node*, Node*, Node*, Node*);
+void udivgen(Node*, Node*, Node*, Node*);
+void sdiv2(long, int, Node*, Node*);
+void smod2(long, int, Node*, Node*);
+void mulgen(Type*, Node*, Node*);
+void genmuladd(Node*, Node*, int, Node*);
+void shiftit(Type*, Node*, Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+/* wrecklessly steal a field */
+
+#define rplink label
diff --git a/utils/8c/list.c b/utils/8c/list.c
new file mode 100644
index 00000000..8ee83383
--- /dev/null
+++ b/utils/8c/list.c
@@ -0,0 +1,282 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ if(p->as == ADATA)
+ sprint(str, " %A %D/%d,%D",
+ p->as, &p->from, p->from.scale, &p->to);
+ else if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D",
+ p->as, &p->from, p->from.scale, &p->to);
+ else
+ sprint(str, " %A %D,%D",
+ p->as, &p->from, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%ld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", a->sym->name,
+ a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /*[D_AL]*/
+ "CL",
+ "DL",
+ "BL",
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /*[D_AX]*/
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /*[D_F0]*/
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "CS", /*[D_CS]*/
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /*[D_GDTR]*/
+ "IDTR", /*[D_IDTR]*/
+ "LDTR", /*[D_LDTR]*/
+ "MSW", /*[D_MSW] */
+ "TASK", /*[D_TASK]*/
+
+ "CR0", /*[D_CR]*/
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+
+ "DR0", /*[D_DR]*/
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /*[D_TR]*/
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /*[D_NONE]*/
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/8c/machcap.c b/utils/8c/machcap.c
new file mode 100644
index 00000000..3a8831a7
--- /dev/null
+++ b/utils/8c/machcap.c
@@ -0,0 +1,86 @@
+#include "gc.h"
+
+int
+machcap(Node *n)
+{
+
+ if(n == Z)
+ return 1; /* test */
+
+ switch(n->op) {
+ case OMUL:
+ case OLMUL:
+ case OASMUL:
+ case OASLMUL:
+ if(typechl[n->type->etype])
+ return 1;
+ if(typev[n->type->etype]) {
+ return 1;
+ }
+ break;
+
+ case OCOM:
+ case ONEG:
+ case OADD:
+ case OAND:
+ case OOR:
+ case OSUB:
+ case OXOR:
+ case OASHL:
+ case OLSHR:
+ case OASHR:
+ if(typechlv[n->left->type->etype])
+ return 1;
+ break;
+
+ case OCAST:
+ if(typev[n->type->etype]) {
+ if(typechlp[n->left->type->etype])
+ return 1;
+ }
+ else if(!typefd[n->type->etype]) {
+ if(typev[n->left->type->etype])
+ return 1;
+ }
+ break;
+
+ case OCOND:
+ case OCOMMA:
+ case OLIST:
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ return 1;
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ return 1;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OGT:
+ case OLT:
+ case OGE:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/utils/8c/mkenam b/utils/8c/mkenam
new file mode 100644
index 00000000..f6364a34
--- /dev/null
+++ b/utils/8c/mkenam
@@ -0,0 +1,15 @@
+ed - ../8c/8.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/8c/mkfile b/utils/8c/mkfile
new file mode 100644
index 00000000..729cff24
--- /dev/null
+++ b/utils/8c/mkfile
@@ -0,0 +1,35 @@
+<../../mkconfig
+
+TARG=8c
+
+OFILES=\
+ cgen.$O\
+ enam.$O\
+ list.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ reg.$O\
+ peep.$O\
+ machcap.$O\
+ cgen64.$O\
+ div.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ 8.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/8c/mul.c b/utils/8c/mul.c
new file mode 100644
index 00000000..a60908c6
--- /dev/null
+++ b/utils/8c/mul.c
@@ -0,0 +1,428 @@
+#include "gc.h"
+
+typedef struct Malg Malg;
+typedef struct Mparam Mparam;
+
+struct Malg
+{
+ char vals[10];
+};
+
+struct Mparam
+{
+ ulong value;
+ char alg;
+ char neg;
+ char shift;
+ char arg;
+ char off;
+};
+
+static Mparam multab[32];
+static int mulptr;
+
+static Malg malgs[] =
+{
+ {0, 100},
+ {-1, 1, 100},
+ {-9, -5, -3, 3, 5, 9, 100},
+ {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+ {-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(ulong v)
+{
+ int s, i;
+ ulong m;
+
+ s = 0;
+ m = 0xFFFFFFFFUL;
+ for(i = 16; i > 0; i >>= 1) {
+ m >>= i;
+ if((v & m) == 0) {
+ v >>= i;
+ s += i;
+ }
+ }
+ return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+ Node nod;
+
+ nod.op = OINDEX;
+ nod.left = a;
+ nod.right = s;
+ nod.scale = m;
+ nod.type = types[TIND];
+ nod.xoffset = 0;
+ xcom(&nod);
+ gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(ulong m, Mparam *mp)
+{
+ int c, i, j, n, o, q, s;
+ int bc, bi, bn, bo, bq, bs, bt;
+ char *p;
+ long u;
+ ulong t;
+
+ bc = bq = 10;
+ bi = bn = bo = bs = bt = 0;
+ for(i = 0; i < nelem(malgs); i++) {
+ for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+ for(s = 0; s < 2; s++) {
+ c = 10;
+ q = 10;
+ u = m - o;
+ if(u == 0)
+ continue;
+ if(s) {
+ o = -o;
+ if(o > 0)
+ continue;
+ u = -u;
+ }
+ n = lowbit(u);
+ t = (ulong)u >> n;
+ switch(i) {
+ case 0:
+ if(t == 1) {
+ c = s + 1;
+ q = 0;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = s + 1;
+ if(n)
+ c++;
+ q = 0;
+ break;
+ }
+ if(s)
+ break;
+ switch(t) {
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ c = 2;
+ if(n)
+ c++;
+ q = 1;
+ break;
+ }
+ break;
+ case 1:
+ if(t == 1) {
+ c = 3;
+ q = 3;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 2:
+ if(t == 1) {
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 3:
+ if(s)
+ break;
+ if(t == 1) {
+ c = 3;
+ q = 1;
+ break;
+ }
+ break;
+ case 4:
+ if(t == 1) {
+ c = 3;
+ q = 0;
+ break;
+ }
+ break;
+ }
+ if(c < bc || (c == bc && q > bq)) {
+ bc = c;
+ bi = i;
+ bn = n;
+ bo = o;
+ bq = q;
+ bs = s;
+ bt = t;
+ }
+ }
+ }
+ mp->value = m;
+ if(bc <= 3) {
+ mp->alg = bi;
+ mp->shift = bn;
+ mp->off = bo;
+ mp->neg = bs;
+ mp->arg = bt;
+ }
+ else
+ mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+ switch(a) {
+ case -2:
+ case 2:
+ return 2;
+ case -3:
+ case 3:
+ return 2;
+ case -4:
+ case 4:
+ return 4;
+ case -5:
+ case 5:
+ return 4;
+ case 6:
+ return 2;
+ case -8:
+ case 8:
+ return 8;
+ case -9:
+ case 9:
+ return 8;
+ case 10:
+ return 4;
+ case 12:
+ return 2;
+ case 15:
+ return 2;
+ case 18:
+ return 8;
+ case 20:
+ return 4;
+ case 24:
+ return 2;
+ case 25:
+ return 4;
+ case 27:
+ return 2;
+ case 36:
+ return 8;
+ case 40:
+ return 4;
+ case 45:
+ return 4;
+ case 72:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m0");
+ return 0;
+}
+
+int
+m1(int a)
+{
+ switch(a) {
+ case 15:
+ return 4;
+ case 25:
+ return 4;
+ case 27:
+ return 8;
+ case 45:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m1");
+ return 0;
+}
+
+int
+m2(int a)
+{
+ switch(a) {
+ case 6:
+ return 2;
+ case 10:
+ return 2;
+ case 12:
+ return 4;
+ case 18:
+ return 2;
+ case 20:
+ return 4;
+ case 24:
+ return 8;
+ case 36:
+ return 4;
+ case 40:
+ return 8;
+ case 72:
+ return 8;
+ }
+ diag(Z, "bad m2");
+ return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+ long c;
+
+ c = (long)s->vconst & 31;
+ switch(c) {
+ case 0:
+ break;
+ case 1:
+ gopcode(OADD, t, d, d);
+ break;
+ default:
+ gopcode(OASHL, t, s, d);
+ }
+}
+
+static int
+mulgen1(ulong v, Node *n)
+{
+ int i, o;
+ Mparam *p;
+ Node nod, nods;
+
+ for(i = 0; i < nelem(multab); i++) {
+ p = &multab[i];
+ if(p->value == v)
+ goto found;
+ }
+
+ p = &multab[mulptr];
+ if(++mulptr == nelem(multab))
+ mulptr = 0;
+
+ mulparam(v, p);
+
+found:
+// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+ if(p->alg < 0)
+ return 0;
+
+ nods = *nodconst(p->shift);
+
+ o = OADD;
+ if(p->alg > 0) {
+ regalloc(&nod, n, Z);
+ if(p->off < 0)
+ o = OSUB;
+ }
+
+ switch(p->alg) {
+ case 0:
+ switch(p->arg) {
+ case 1:
+ shiftit(n->type, &nods, n);
+ break;
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ genmuladd(n, n, m1(p->arg), n);
+ /* fall thru */
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(n, n, m0(p->arg), n);
+ shiftit(n->type, &nods, n);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg == 1)
+ gins(ANEGL, Z, n);
+ break;
+ case 1:
+ switch(p->arg) {
+ case 1:
+ gmove(n, &nod);
+ shiftit(n->type, &nods, &nod);
+ break;
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(&nod, n, m0(p->arg), n);
+ shiftit(n->type, &nods, &nod);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg)
+ gopcode(o, n->type, &nod, n);
+ else {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ break;
+ case 2:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ goto comop;
+ case 3:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ genmuladd(n, &nod, m2(p->off), n);
+ break;
+ case 4:
+ genmuladd(&nod, n, m0(p->off), nodconst(0));
+ shiftit(n->type, &nods, n);
+ goto comop;
+ default:
+ diag(Z, "bad mul alg");
+ break;
+ comop:
+ if(p->neg) {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ else
+ gopcode(o, n->type, &nod, n);
+ }
+
+ if(p->alg > 0)
+ regfree(&nod);
+
+ return 1;
+
+bad:
+ diag(Z, "mulgen botch");
+ return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+ if(!mulgen1(r->vconst, n))
+ gopcode(OMUL, t, r, n);
+}
diff --git a/utils/8c/peep.c b/utils/8c/peep.c
new file mode 100644
index 00000000..8a2d79b7
--- /dev/null
+++ b/utils/8c/peep.c
@@ -0,0 +1,757 @@
+#include "gc.h"
+
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case ASBBL:
+ case ARCRL:
+ return 1;
+ case AADDL:
+ case ASUBL:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+
+ /*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+ pc = 0; /* speculating it won't kill */
+
+loop1:
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVL:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ if(regtyp(&p->to)) {
+ r1 = uniqs(r);
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type)
+ p1->as = AMOVL;
+ }
+ }
+ break;
+ case AADDL:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ break;
+ case ASUBL:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_DI)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+
+ case AMOVSL:
+ case AFSTSW:
+ return 0;
+
+ case AMOVL:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub %D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %D used+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %D set and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print("unknown op %A\n", p->as);
+ return 2;
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ADECL:
+ case ADECW:
+ case AINCL:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AFMOVB:
+ case AFMOVBP:
+ case AFMOVD:
+ case AFMOVDP:
+ case AFMOVF:
+ case AFMOVFP:
+ case AFMOVL:
+ case AFMOVLP:
+ case AFMOVV:
+ case AFMOVVP:
+ case AFMOVW:
+ case AFMOVWP:
+ case AFMOVX:
+ case AFMOVXP:
+ case AFADDDP:
+ case AFADDW:
+ case AFADDL:
+ case AFADDF:
+ case AFADDD:
+ case AFMULDP:
+ case AFMULW:
+ case AFMULL:
+ case AFMULF:
+ case AFMULD:
+ case AFSUBDP:
+ case AFSUBW:
+ case AFSUBL:
+ case AFSUBF:
+ case AFSUBD:
+ case AFSUBRDP:
+ case AFSUBRW:
+ case AFSUBRL:
+ case AFSUBRF:
+ case AFSUBRD:
+ case AFDIVDP:
+ case AFDIVW:
+ case AFDIVL:
+ case AFDIVF:
+ case AFDIVD:
+ case AFDIVRDP:
+ case AFDIVRW:
+ case AFDIVRL:
+ case AFDIVRF:
+ case AFDIVRD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+
+ case AFCOMB:
+ case AFCOMBP:
+ case AFCOMD:
+ case AFCOMDP:
+ case AFCOMDPP:
+ case AFCOMF:
+ case AFCOMFP:
+ case AFCOML:
+ case AFCOMLP:
+ case AFCOMW:
+ case AFCOMWP:
+ case AFUCOM:
+ case AFUCOMP:
+ case AFUCOMPP:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AFLDZ:
+ case AWAIT:
+ break;
+
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AMOVSL:
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ case AFSTSW:
+ if(v->type == D_AX)
+ return 2;
+ goto caseread;
+
+ case AJMP: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == REGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGARG && v->type == REGARG)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == v->type)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_DI) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if(s->type == D_BP && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/utils/8c/reg.c b/utils/8c/reg.c
new file mode 100644
index 00000000..12ad50ab
--- /dev/null
+++ b/utils/8c/reg.c
@@ -0,0 +1,1255 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = RtoB(D_SP) | RtoB(D_AX);
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case AIRETL:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPW:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVL:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AADDB:
+ case AADDL:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARW:
+ case AROLB:
+ case AROLL:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRW:
+ case AIMULL:
+ case AIMULW:
+ case ANEGL:
+ case ANOTL:
+ case AADCL:
+ case ASBBL:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case AFMOVDP:
+ case AFMOVFP:
+ case AFMOVVP:
+ case ACALL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AMULB:
+ case AMULL:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->regu |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSW:
+ r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASW:
+ r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ break;
+
+ case AFSTSW:
+ case ASAHF:
+ r->regu |= RtoB(D_AX);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] |
+ r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v']) {
+ print("%P\t", r->prog);
+ if(bany(&r->set))
+ print("s:%B ", r->set);
+ if(bany(&r->refahead))
+ print("ra:%B ", r->refahead);
+ if(bany(&r->calahead))
+ print("ca:%B ", r->calahead);
+ print("\n");
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L$%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ print("%L$%d %R: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+
+ p1->as = AMOVL;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVW;
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+ulong
+doregbits(int r)
+{
+ ulong b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_DI)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_BL)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ return b;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ r->regu |= doregbits(t);
+ r->regu |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ goto none;
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ a->type = t;
+ goto none;
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+ v->etype = et;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ACALL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(p->as == AFMOVL)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+regset(Reg *r, ulong bb)
+{
+ ulong b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = BtoR(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+ulong
+reguse(Reg *r, ulong bb)
+{
+ ulong b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = BtoR(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg, x;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->offset = 0;
+ a->type = rn;
+}
+
+long
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_DI)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(long b)
+{
+
+ b &= 0xffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
diff --git a/utils/8c/sgen.c b/utils/8c/sgen.c
new file mode 100644
index 00000000..f5fb2090
--- /dev/null
+++ b/utils/8c/sgen.c
@@ -0,0 +1,842 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ }
+ }
+
+ sp = p;
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ if(thisfn && thisfn->link && typefd[thisfn->link->etype])
+ gins(AFLDZ, Z, Z);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int f, o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ if(typefd[n->type->etype])
+ gins(AFLDZ, Z, Z);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ supgen(n->right->left);
+ gen(n->right->right);
+ }
+ else {
+ gen(n->right->left);
+ supgen(n->right->right);
+ }
+ }
+ else {
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = FREGRET;
+ }
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+ Node *l, *r;
+
+ l = n->left;
+ r = n->right;
+ if(r->complex > l->complex) {
+ n->left = r;
+ n->right = l;
+ }
+}
+
+void
+indexshift(Node *n)
+{
+ int g;
+
+ if(!typechlp[n->type->etype])
+ return;
+ simplifyshift(n);
+ if(n->op == OASHL && n->right->op == OCONST){
+ g = vconst(n->right);
+ if(g >= 0 && g < 4)
+ n->addable = 7;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * NAME ==> 10/11 name+value(SB/SP)
+ * REGISTER ==> 12 register
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 13 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (13) + (20) ==> 13 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(13) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
+ * (8) ==> &9(OINDEX) index, almost addressable
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 10;
+ if(n->class == CPARAM || n->class == CAUTO)
+ n->addable = 11;
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OINDREG:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 13;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ switch(r->addable) {
+ case 20:
+ switch(l->addable) {
+ case 1:
+ case 13:
+ commadd:
+ l->type = n->type;
+ *n = *l;
+ l = new(0, Z, Z);
+ *l = *(n->left);
+ l->xoffset += r->vconst;
+ n->left = l;
+ r = n->right;
+ goto brk;
+ }
+ break;
+
+ case 1:
+ case 13:
+ case 10:
+ case 11:
+ /* l is the base, r is the index */
+ if(l->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ switch(l->addable) {
+ case 20:
+ switch(r->addable) {
+ case 13:
+ case 1:
+ r = n->left;
+ l = n->right;
+ n->left = l;
+ n->right = r;
+ goto commadd;
+ }
+ break;
+
+ case 13:
+ case 1:
+ case 10:
+ case 11:
+ /* r is the base, l is the index */
+ if(r->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ if(n->addable == 8 && !side(n)) {
+ indx(n);
+ l = new1(OINDEX, idx.basetree, idx.regtree);
+ l->scale = idx.scale;
+ l->addable = 9;
+ l->complex = l->right->complex;
+ l->type = l->left->type;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 8;
+ break;
+ }
+ break;
+
+ case OINDEX:
+ xcom(l);
+ xcom(r);
+ n->addable = 9;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 13:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+commute(n);
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ break;
+
+ case OLSHR:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+brk:
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 3;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 3;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 2;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 2;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * compare operators, make const on left
+ */
+ if(r->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+indx(Node *n)
+{
+ Node *l, *r;
+
+ if(debug['x'])
+ prtree(n, "indx");
+
+ l = n->left;
+ r = n->right;
+ if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+ n->right = l;
+ n->left = r;
+ l = r;
+ r = n->right;
+ }
+ if(l->addable != 7) {
+ idx.regtree = l;
+ idx.scale = 1;
+ } else
+ if(l->right->addable == 20) {
+ idx.regtree = l->left;
+ idx.scale = 1 << l->right->vconst;
+ } else
+ if(l->left->addable == 20) {
+ idx.regtree = l->right;
+ idx.scale = 1 << l->left->vconst;
+ } else
+ diag(n, "bad index");
+
+ idx.basetree = r;
+ if(debug['x']) {
+ print("scale = %d\n", idx.scale);
+ prtree(idx.regtree, "index");
+ prtree(idx.basetree, "base");
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+ Node *b, nod;
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ if(typev[n->type->etype] && machcap(Z)) {
+ b = &nod;
+ b->op = ONE;
+ b->left = n;
+ b->right = new(0, Z, Z);
+ *b->right = *nodconst(0);
+ b->right->type = n->type;
+ b->type = types[TLONG];
+ cgen64(b, Z);
+ return 0;
+ }
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+ return 0;
+}
diff --git a/utils/8c/swt.c b/utils/8c/swt.c
new file mode 100644
index 00000000..02f3a1de
--- /dev/null
+++ b/utils/8c/swt.c
@@ -0,0 +1,647 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8lux\n", i, iq[i].val);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ swit1(iq, nc, def, n);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8lux\n", q->val);
+ gopcode(OEQ, n->type, n, nodconst(q->val));
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8lux\n", r->val);
+ gopcode(OGT, n->type, n, nodconst(r->val));
+ sp = p;
+ gbranch(OGOTO);
+ p->as = AJEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8lux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gmove(n2, n3);
+ gmove(n3, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
+ else
+ gopcode(OASHR, types[TLONG], nodconst(sh), n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod;
+ int sh;
+
+ regalloc(&nod, b->left, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ gmove(n1, &nod);
+ if(nn != Z)
+ gmove(n1, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+ v <<= sh;
+ gopcode(OAND, types[TLONG], nodconst(~v), n3);
+ gopcode(OOR, types[TLONG], n3, &nod);
+ gmove(&nod, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->from.scale = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0L));
+ p->from.offset += o+e;
+ p->from.scale = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, lo64(a));
+ p->from.offset += o;
+ p->from.scale = 4;
+ gpseudo(ADATA, s, hi64(a));
+ p->from.offset += o + 4;
+ p->from.scale = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->from.scale = w;
+ switch(p->to.type) {
+ default:
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ case D_CONST:
+ case D_FCONST:
+ case D_ADDR:
+ break;
+ }
+}
+
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cannot open %s", outfile);
+ return;
+ }
+ Binit(&b, f, OWRITE);
+ Bseek(&b, 0L, 2);
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&b, p->as);
+ Bputc(&b, p->as>>8);
+ Bputc(&b, p->lineno);
+ Bputc(&b, p->lineno>>8);
+ Bputc(&b, p->lineno>>16);
+ Bputc(&b, p->lineno>>24);
+ zaddr(&b, &p->from, sf);
+ zaddr(&b, &p->to, st);
+ }
+ Bflush(&b);
+ close(f);
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ Bputc(b, pg.as);
+ Bputc(b, pg.as>>8);
+ Bputc(b, pg.lineno);
+ Bputc(b, pg.lineno>>8);
+ Bputc(b, pg.lineno>>16);
+ Bputc(b, pg.lineno>>24);
+ zaddr(b, &pg.from, 0);
+ zaddr(b, &pg.to, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ case D_NONE:
+ if(a->offset != 0)
+ t |= T_OFFSET;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/utils/8c/txt.c b/utils/8c/txt.c
new file mode 100644
index 00000000..841116ab
--- /dev/null
+++ b/utils/8c/txt.c
@@ -0,0 +1,1410 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '8';
+ thestring = "386";
+ exregoffset = 0;
+ exfregoffset = 0;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ fregnode0 = regnode;
+ fregnode0.reg = D_F0;
+ fregnode0.type = types[TDOUBLE];
+
+ fregnode1 = fregnode0;
+ fregnode1.reg = D_F0+1;
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_DI && i != D_SP)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+int nareg(void)
+{
+ int i, n;
+
+ n = 0;
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i] == 0)
+ n++;
+ return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype] || typev[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typeilp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gmove(n, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gmove(tn1, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+ if(n->op == OREGISTER)
+ if(n->reg == r)
+ return 1;
+ return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+
+ *n = regnode;
+ n->reg = r;
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+ if(nn->op == OREGISTER)
+ if(nn->reg == r)
+ return 0;
+ }
+ return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_AX && i <= D_DI)
+ goto out;
+ }
+ for(i=D_AX; i<=D_DI; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ i = D_F0;
+ goto out;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->reg;
+ a->sym = S;
+ break;
+
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_DI)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ break;
+
+ case OINDEX:
+ a->type = idx.ptr;
+ if(n->left->op == OADDR || n->left->op == OCONST)
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_DI)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ a->index = idx.reg;
+ a->scale = n->scale;
+ a->offset += n->xoffset;
+ break;
+
+ case OINDREG:
+ a->type = n->reg+D_INDIR;
+ a->sym = S;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->right->op == OCONST) {
+ v = n->right->vconst;
+ naddr(n->left, a);
+ } else
+ if(n->left->op == OCONST) {
+ v = n->left->vconst;
+ naddr(n->right, a);
+ } else
+ goto bad;
+ a->offset += v;
+ break;
+
+ }
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod, nod1;
+ Prog *p1;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ if(debug['M'])
+ print("gop: %O %O[%s],%O[%s]\n", OAS,
+ f->op, tnames[ft], t->op, tnames[tt]);
+ if(typefd[ft] && f->op == OCONST) {
+ if(f->fconst == 0)
+ gins(AFLDZ, Z, Z);
+ else
+ if(f->fconst == 1)
+ gins(AFLD1, Z, Z);
+ else
+ gins(AFMOVD, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+/*
+ * load
+ */
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ goto ld;
+ case TSHORT:
+ if(typefd[tt]) {
+ gins(AFMOVW, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+ a = AMOVWLSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ goto ld;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(typefd[tt]) {
+ gins(AFMOVL, f, &fregnode0);
+ gmove(&fregnode0, t);
+ return;
+ }
+ a = AMOVL;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = types[TLONG];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ gins(AFMOVF, f, t);
+ return;
+ case TDOUBLE:
+ gins(AFMOVD, f, t);
+ return;
+ case TVLONG:
+ gins(AFMOVV, f, t);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVB; goto st;
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVW; goto st;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVL; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ gins(AFMOVFP, f, t);
+ return;
+ case TDOUBLE:
+ gins(AFMOVDP, f, t);
+ return;
+ case TVLONG:
+ gins(AFMOVVP, f, t);
+ return;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft,tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE( TCHAR, TCHAR):
+ case CASE( TUCHAR, TCHAR):
+ case CASE( TSHORT, TCHAR):
+ case CASE( TUSHORT,TCHAR):
+ case CASE( TINT, TCHAR):
+ case CASE( TUINT, TCHAR):
+ case CASE( TLONG, TCHAR):
+ case CASE( TULONG, TCHAR):
+ case CASE( TIND, TCHAR):
+
+ case CASE( TCHAR, TUCHAR):
+ case CASE( TUCHAR, TUCHAR):
+ case CASE( TSHORT, TUCHAR):
+ case CASE( TUSHORT,TUCHAR):
+ case CASE( TINT, TUCHAR):
+ case CASE( TUINT, TUCHAR):
+ case CASE( TLONG, TUCHAR):
+ case CASE( TULONG, TUCHAR):
+ case CASE( TIND, TUCHAR):
+
+ case CASE( TSHORT, TSHORT):
+ case CASE( TUSHORT,TSHORT):
+ case CASE( TINT, TSHORT):
+ case CASE( TUINT, TSHORT):
+ case CASE( TLONG, TSHORT):
+ case CASE( TULONG, TSHORT):
+ case CASE( TIND, TSHORT):
+
+ case CASE( TSHORT, TUSHORT):
+ case CASE( TUSHORT,TUSHORT):
+ case CASE( TINT, TUSHORT):
+ case CASE( TUINT, TUSHORT):
+ case CASE( TLONG, TUSHORT):
+ case CASE( TULONG, TUSHORT):
+ case CASE( TIND, TUSHORT):
+
+ case CASE( TINT, TINT):
+ case CASE( TUINT, TINT):
+ case CASE( TLONG, TINT):
+ case CASE( TULONG, TINT):
+ case CASE( TIND, TINT):
+
+ case CASE( TINT, TUINT):
+ case CASE( TUINT, TUINT):
+ case CASE( TLONG, TUINT):
+ case CASE( TULONG, TUINT):
+ case CASE( TIND, TUINT):
+
+ case CASE( TINT, TLONG):
+ case CASE( TUINT, TLONG):
+ case CASE( TLONG, TLONG):
+ case CASE( TULONG, TLONG):
+ case CASE( TIND, TLONG):
+
+ case CASE( TINT, TULONG):
+ case CASE( TUINT, TULONG):
+ case CASE( TLONG, TULONG):
+ case CASE( TULONG, TULONG):
+ case CASE( TIND, TULONG):
+
+ case CASE( TINT, TIND):
+ case CASE( TUINT, TIND):
+ case CASE( TLONG, TIND):
+ case CASE( TULONG, TIND):
+ case CASE( TIND, TIND):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TCHAR, TSHORT):
+ case CASE( TCHAR, TUSHORT):
+ case CASE( TCHAR, TINT):
+ case CASE( TCHAR, TUINT):
+ case CASE( TCHAR, TLONG):
+ case CASE( TCHAR, TULONG):
+ case CASE( TCHAR, TIND):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUCHAR, TSHORT):
+ case CASE( TUCHAR, TUSHORT):
+ case CASE( TUCHAR, TINT):
+ case CASE( TUCHAR, TUINT):
+ case CASE( TUCHAR, TLONG):
+ case CASE( TUCHAR, TULONG):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE( TFLOAT, TCHAR):
+ case CASE( TFLOAT, TUCHAR):
+ case CASE( TFLOAT, TSHORT):
+ case CASE( TFLOAT, TUSHORT):
+ case CASE( TFLOAT, TINT):
+ case CASE( TFLOAT, TUINT):
+ case CASE( TFLOAT, TLONG):
+ case CASE( TFLOAT, TULONG):
+ case CASE( TFLOAT, TIND):
+
+ case CASE( TDOUBLE,TCHAR):
+ case CASE( TDOUBLE,TUCHAR):
+ case CASE( TDOUBLE,TSHORT):
+ case CASE( TDOUBLE,TUSHORT):
+ case CASE( TDOUBLE,TINT):
+ case CASE( TDOUBLE,TUINT):
+ case CASE( TDOUBLE,TLONG):
+ case CASE( TDOUBLE,TULONG):
+ case CASE( TDOUBLE,TIND):
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TUCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TUSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TVLONG, TULONG):
+ case CASE( TVLONG, TIND):
+ if(fproundflg) {
+ regsalloc(&nod, &regnode);
+ gins(AFMOVLP, f, &nod);
+ gmove(&nod, t);
+ return;
+ }
+ regsalloc(&nod, &regnode);
+ regsalloc(&nod1, &regnode);
+ gins(AFSTCW, Z, &nod1);
+ nod1.xoffset += 2;
+ gins(AMOVW, nodconst(0xf7f), &nod1);
+ gins(AFLDCW, &nod1, Z);
+ gins(AFMOVLP, f, &nod);
+ nod1.xoffset -= 2;
+ gins(AFLDCW, &nod1, Z);
+ gmove(&nod, t);
+ return;
+
+/*
+ * ulong to float
+ */
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TFLOAT):
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regsalloc(&nod1, &regnode);
+ gmove(&nod, &nod1);
+ gins(AFMOVL, &nod1, &fregnode0);
+ gins(ACMPL, &nod, nodconst(0));
+ gins(AJGE, Z, Z);
+ p1 = p;
+ gins(AFADDD, nodfconst(4294967296.), &fregnode0);
+ patch(p1, pc);
+ regfree(&nod);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE( TCHAR, TFLOAT):
+ case CASE( TUCHAR, TFLOAT):
+ case CASE( TSHORT, TFLOAT):
+ case CASE( TUSHORT,TFLOAT):
+ case CASE( TINT, TFLOAT):
+ case CASE( TLONG, TFLOAT):
+ case CASE( TIND, TFLOAT):
+
+ case CASE( TCHAR, TDOUBLE):
+ case CASE( TUCHAR, TDOUBLE):
+ case CASE( TSHORT, TDOUBLE):
+ case CASE( TUSHORT,TDOUBLE):
+ case CASE( TINT, TDOUBLE):
+ case CASE( TLONG, TDOUBLE):
+ case CASE( TIND, TDOUBLE):
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TSHORT, TVLONG):
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TIND, TVLONG):
+ regsalloc(&nod, &regnode);
+ gmove(f, &nod);
+ gins(AFMOVL, &nod, &fregnode0);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ case CASE( TDOUBLE,TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+
+ case CASE( TFLOAT, TDOUBLE):
+ case CASE( TDOUBLE,TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TVLONG, TVLONG):
+ a = AFMOVD; break;
+ }
+ if(a == AMOVL || a == AFMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+ Node nod, nod1;
+ long v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+ regalloc(&nod, &regnode, Z);
+ v = constnode.vconst;
+ cgen(n->right, &nod);
+ idx.ptr = D_NONE;
+ if(n->left->op == OCONST)
+ idx.ptr = D_CONST;
+ else if(n->left->op == OREGISTER)
+ idx.ptr = n->left->reg;
+ else if(n->left->op != OADDR) {
+ reg[D_BP]++; // cant be used as a base
+ regalloc(&nod1, &regnode, Z);
+ cgen(n->left, &nod1);
+ idx.ptr = nod1.reg;
+ regfree(&nod1);
+ reg[D_BP]--;
+ }
+ idx.reg = nod.reg;
+ regfree(&nod);
+ constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ if(f != Z && f->op == OINDEX)
+ doindex(f);
+ if(t != Z && t->op == OINDEX)
+ doindex(t);
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+fgopcode(int o, Node *f, Node *t, int pop, int rev)
+{
+ int a, et;
+ Node nod;
+
+ et = TLONG;
+ if(f != Z && f->type != T)
+ et = f->type->etype;
+ if(!typefd[et]) {
+ diag(f, "fop: integer %O", o);
+ return;
+ }
+ if(debug['M']) {
+ if(t != Z && t->type != T)
+ print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
+ else
+ print("gop: %O %O-%s %O-%s\n", o,
+ f->op, tnames[et], t->op, tnames[t->type->etype]);
+ }
+ a = AGOK;
+ switch(o) {
+
+ case OASADD:
+ case OADD:
+ if(et == TFLOAT)
+ a = AFADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFADDD;
+ if(pop)
+ a = AFADDDP;
+ }
+ break;
+
+ case OASSUB:
+ case OSUB:
+ if(et == TFLOAT) {
+ a = AFSUBF;
+ if(rev)
+ a = AFSUBRF;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFSUBD;
+ if(pop)
+ a = AFSUBDP;
+ if(rev) {
+ a = AFSUBRD;
+ if(pop)
+ a = AFSUBRDP;
+ }
+ }
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT)
+ a = AFMULF;
+ else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFMULD;
+ if(pop)
+ a = AFMULDP;
+ }
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = AFDIVF;
+ if(rev)
+ a = AFDIVRF;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFDIVD;
+ if(pop)
+ a = AFDIVDP;
+ if(rev) {
+ a = AFDIVRD;
+ if(pop)
+ a = AFDIVRDP;
+ }
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ pop += rev;
+ if(et == TFLOAT) {
+ a = AFCOMF;
+ if(pop) {
+ a = AFCOMFP;
+ if(pop > 1)
+ a = AGOK;
+ }
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFCOMF;
+ if(pop) {
+ a = AFCOMDP;
+ if(pop > 1)
+ a = AFCOMDPP;
+ }
+ }
+ gins(a, f, t);
+ regalloc(&nod, &regnode, Z);
+ if(nod.reg != D_AX) {
+ regfree(&nod);
+ nod.reg = D_AX;
+ gins(APUSHL, &nod, Z);
+ gins(AWAIT, Z, Z);
+ gins(AFSTSW, Z, &nod);
+ gins(ASAHF, Z, Z);
+ gins(APOPL, Z, &nod);
+ } else {
+ gins(AWAIT, Z, Z);
+ gins(AFSTSW, Z, &nod);
+ gins(ASAHF, Z, Z);
+ regfree(&nod);
+ }
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJCS; break;
+ case OLE: a = AJLS; break;
+ case OGE: a = AJCC; break;
+ case OGT: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(typefd[et] && o != OADDR && o != OFUNC) {
+ diag(f, "gop: float %O", o);
+ return;
+ }
+ if(debug['M']) {
+ if(f != Z && f->type != T)
+ print("gop: %O %O[%s],", o, f->op, tnames[et]);
+ else
+ print("gop: %O Z,", o);
+ if(t != Z && t->type != T)
+ print("%O[%s]\n", t->op, tnames[t->type->etype]);
+ else
+ print("Z\n");
+ }
+ a = AGOK;
+ switch(o) {
+ case OCOM:
+ a = ANOTL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANOTB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANOTW;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ break;
+
+ case OADDR:
+ a = ALEAL;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ break;
+
+ case OFUNC:
+ a = ACALL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+ t = Z;
+ a = AIMULL;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMPL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ACMPB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ACMPW;
+ gins(a, f, t);
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJLT; break;
+ case OLE: a = AJLE; break;
+ case OGE: a = AJGE; break;
+ case OGT: a = AJGT; break;
+ case OLO: a = AJCS; break;
+ case OLS: a = AJLS; break;
+ case OHS: a = AJCC; break;
+ case OHI: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.scale = (profileflg ? 0 : NOPROF);
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ long v;
+
+ if(n->op == OCONST && !typefd[n->type->etype]) {
+ v = n->vconst;
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ }
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+
+ USED(t);
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /*[TXXX]*/
+ SZ_CHAR, /*[TCHAR]*/
+ SZ_CHAR, /*[TUCHAR]*/
+ SZ_SHORT, /*[TSHORT]*/
+ SZ_SHORT, /*[TUSHORT]*/
+ SZ_INT, /*[TINT]*/
+ SZ_INT, /*[TUINT]*/
+ SZ_LONG, /*[TLONG]*/
+ SZ_LONG, /*[TULONG]*/
+ SZ_VLONG, /*[TVLONG]*/
+ SZ_VLONG, /*[TUVLONG]*/
+ SZ_FLOAT, /*[TFLOAT]*/
+ SZ_DOUBLE, /*[TDOUBLE]*/
+ SZ_IND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ -1, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ -1, /*[TSTRUCT]*/
+ -1, /*[TUNION]*/
+ SZ_INT, /*[TENUM]*/
+};
+long ncast[NTYPE] =
+{
+ 0, /*[TXXX]*/
+ BCHAR|BUCHAR, /*[TCHAR]*/
+ BCHAR|BUCHAR, /*[TUCHAR]*/
+ BSHORT|BUSHORT, /*[TSHORT]*/
+ BSHORT|BUSHORT, /*[TUSHORT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
+ BVLONG|BUVLONG, /*[TVLONG]*/
+ BVLONG|BUVLONG, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BLONG|BULONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};
diff --git a/utils/8l/Nt.c b/utils/8l/Nt.c
new file mode 100644
index 00000000..73c6f795
--- /dev/null
+++ b/utils/8l/Nt.c
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/8l/Plan9.c b/utils/8l/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/8l/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/8l/Posix.c b/utils/8l/Posix.c
new file mode 100644
index 00000000..0da0ee0c
--- /dev/null
+++ b/utils/8l/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fails if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
diff --git a/utils/8l/asm.c b/utils/8l/asm.c
new file mode 100644
index 00000000..56eee141
--- /dev/null
+++ b/utils/8l/asm.c
@@ -0,0 +1,502 @@
+#include "l.h"
+
+#define Dbufslop 100
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ switch(s->type) {
+ case STEXT:
+ break;
+ case SDATA:
+ if(dlm)
+ return s->value+INITDAT;
+ default:
+ diag("entry not text: %s", s->name);
+ }
+ return s->value;
+}
+
+void
+wput(ushort w)
+{
+ cput(w);
+ cput(w>>8);
+}
+
+void
+wputb(ushort w)
+{
+ cput(w>>8);
+ cput(w);
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long v, magic;
+ int a;
+ uchar *op1;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asmb\n", cputime());
+ Bflush(&bso);
+
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ curp = firstp;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->pc != pc) {
+ if(!debug['a'])
+ print("%P\n", curp);
+ diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
+ pc = p->pc;
+ }
+ curp = p;
+ asmins(p);
+ if(cbc < sizeof(and))
+ cflush();
+ a = (andptr - and);
+ if(debug['a']) {
+ Bprint(&bso, pcstr, pc);
+ for(op1 = and; op1 < andptr; op1++)
+ Bprint(&bso, "%.2ux", *op1 & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ if(dlm) {
+ if(p->as == ATEXT)
+ reloca = nil;
+ else if(reloca != nil)
+ diag("reloc failure: %P", curp);
+ }
+ memmove(cbp, and, a);
+ cbp += a;
+ pc += a;
+ cbc -= a;
+ }
+ cflush();
+ switch(HEADTYPE) {
+ default:
+ diag("unknown header type %d", HEADTYPE);
+ case 0:
+ seek(cout, rnd(HEADR+textsize, 8192), 0);
+ break;
+ case 1:
+ textsize = rnd(HEADR+textsize, 4096)-HEADR;
+ seek(cout, textsize+HEADR, 0);
+ break;
+ case 2:
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 3:
+ case 4:
+ seek(cout, HEADR+rnd(textsize, INITRND), 0);
+ break;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+
+ if(dlm){
+ char buf[8];
+
+ write(cout, buf, INITDAT-textsize);
+ textsize = INITDAT;
+ }
+
+ for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
+ if(datsize-v > sizeof(buf)-Dbufslop)
+ datblk(v, sizeof(buf)-Dbufslop);
+ else
+ datblk(v, datsize-v);
+ }
+
+ symsize = 0;
+ spsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ default:
+ case 0:
+ seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ break;
+ case 1:
+ seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ break;
+ case 2:
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 3:
+ case 4:
+ debug['s'] = 1;
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ Bflush(&bso);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ if(dlm)
+ asmdyn();
+ cflush();
+ }
+ else if(dlm){
+ seek(cout, HEADR+textsize+datsize, 0);
+ asmdyn();
+ cflush();
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f headr\n", cputime());
+ Bflush(&bso);
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ default:
+ case 0: /* garbage */
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lput((0413<<16)|0437L); /* magic and version */
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT-HEADR); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ break;
+ lputl(0); /* x */
+ case 1: /* unix coff */
+ /*
+ * file header
+ */
+ lputl(0x0004014c); /* 4 sections, magic */
+ lputl(0); /* unix time stamp */
+ lputl(0); /* symbol table */
+ lputl(0); /* nsyms */
+ lputl(0x0003001c); /* flags, sizeof a.out header */
+ /*
+ * a.out header
+ */
+ lputl(0x10b); /* magic, version stamp */
+ lputl(rnd(textsize, INITRND)); /* text sizes */
+ lputl(datsize); /* data sizes */
+ lputl(bsssize); /* bss sizes */
+ lput(entryvalue()); /* va of entry */
+ lputl(INITTEXT); /* text start */
+ lputl(INITDAT); /* data start */
+ /*
+ * text section header
+ */
+ s8put(".text");
+ lputl(HEADR); /* pa */
+ lputl(HEADR); /* va */
+ lputl(textsize); /* text size */
+ lputl(HEADR); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x20); /* flags text only */
+ /*
+ * data section header
+ */
+ s8put(".data");
+ lputl(INITDAT); /* pa */
+ lputl(INITDAT); /* va */
+ lputl(datsize); /* data size */
+ lputl(HEADR+textsize); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x40); /* flags data only */
+ /*
+ * bss section header
+ */
+ s8put(".bss");
+ lputl(INITDAT+datsize); /* pa */
+ lputl(INITDAT+datsize); /* va */
+ lputl(bsssize); /* bss size */
+ lputl(0); /* file offset */
+ lputl(0); /* relocation */
+ lputl(0); /* line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x80); /* flags bss only */
+ /*
+ * comment section header
+ */
+ s8put(".comment");
+ lputl(0); /* pa */
+ lputl(0); /* va */
+ lputl(symsize+lcsize); /* comment size */
+ lputl(HEADR+textsize+datsize); /* file offset */
+ lputl(HEADR+textsize+datsize); /* offset of syms */
+ lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
+ lputl(0); /* relocation, line numbers */
+ lputl(0x200); /* flags comment only */
+ break;
+ case 2: /* plan9 */
+ magic = 4*11*11+7;
+ if(dlm)
+ magic |= 0x80000000;
+ lput(magic); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(spsize); /* sp offsets */
+ lput(lcsize); /* line offsets */
+ break;
+ case 3:
+ /* MS-DOS .COM */
+ break;
+ case 4:
+ /* fake MS-DOS .EXE */
+ v = rnd(HEADR+textsize, INITRND)+datsize;
+ wput(0x5A4D); /* 'MZ' */
+ wput(v % 512); /* bytes in last page */
+ wput(rnd(v, 512)/512); /* total number of pages */
+ wput(0x0000); /* number of reloc items */
+ v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
+ wput(v/16); /* size of header */
+ wput(0x0000); /* minimum allocation */
+ wput(0xFFFF); /* maximum allocation */
+ wput(0x0000); /* initial ss value */
+ wput(0x0100); /* initial sp value */
+ wput(0x0000); /* complemented checksum */
+ v = entryvalue();
+ wput(v); /* initial ip value (!) */
+ wput(0x0000); /* initial cs value */
+ wput(0x0000);
+ wput(0x0000);
+ wput(0x003E); /* reloc table offset */
+ wput(0x0000); /* overlay number */
+ break;
+ }
+ cflush();
+}
+
+void
+lput(long l)
+{
+ cput(l>>24);
+ cput(l>>16);
+ cput(l>>8);
+ cput(l);
+}
+
+void
+lputl(long l)
+{
+ cput(l);
+ cput(l>>8);
+ cput(l>>16);
+ cput(l>>24);
+}
+
+void
+s8put(char *n)
+{
+ char name[8];
+ int i;
+
+ strncpy(name, n, sizeof(name));
+ for(i=0; i<sizeof(name); i++)
+ cput(name[i]);
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+Dbufslop);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->from.scale;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (char*)&fl;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.scon[i];
+ l++;
+ }
+ break;
+ default:
+ fl = p->to.offset;
+ if(p->to.type == D_ADDR) {
+ if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
+ diag("DADDR type%P", p);
+ if(p->to.sym) {
+ if(p->to.sym->type == SUNDEF)
+ ckoff(p->to.sym, fl);
+ fl += p->to.sym->value;
+ if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
+ fl += INITDAT;
+ if(dlm)
+ dynreloc(p->to.sym, l+s+INITDAT, 1);
+ }
+ }
+ cast = (char*)&fl;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ if(debug['a'] && i == 0) {
+ Bprint(&bso, pcstr, l+s+INITDAT);
+ for(j=0; j<c; j++)
+ Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
+ Bprint(&bso, "\t%P\n", curp);
+ }
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/utils/8l/l.h b/utils/8l/l.h
new file mode 100644
index 00000000..5c274418
--- /dev/null
+++ b/utils/8l/l.h
@@ -0,0 +1,349 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../8c/8.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext?curtext->from.sym->name:noname)
+#define cput(c)\
+ { *cbp++ = c;\
+ if(--cbc <= 0)\
+ cflush(); }
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Sym Sym;
+typedef struct Auto Auto;
+typedef struct Optab Optab;
+
+struct Adr
+{
+ union
+ {
+ long u0offset;
+ char u0scon[8];
+ Prog *u0cond; /* not used, but should be D_BRANCH */
+ Ieee u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ short type;
+ char index;
+ char scale;
+};
+
+#define offset u0.u0offset
+#define scon u0.u0scon
+#define cond u0.u0cond
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog *forwd;
+ Prog* link;
+ Prog* pcond; /* work on this */
+ long pc;
+ long line;
+ uchar mark; /* work on these */
+ uchar back;
+
+ short as;
+ char width; /* fake for DATA */
+};
+struct Auto
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ uchar subtype;
+ ushort file;
+ long value;
+ long sig;
+ Sym* link;
+};
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[10];
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SFILE,
+ SCONST,
+ SUNDEF,
+
+ SIMPORT,
+ SEXPORT,
+
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 4,
+ STRINGSZ = 200,
+ MINLC = 1,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Yi32,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zil_,
+ Zil_rp,
+ Zilo_m,
+ Zjmp,
+ Zloop,
+ Zm_o,
+ Zm_r,
+ Zaut_r,
+ Zo_m,
+ Zpseudo,
+ Zr_m,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmov,
+ Zmax,
+
+ Px = 0,
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+
+ Roffset = 22, /* no. bits for offset in relocation address */
+ Rindex = 10, /* no. bits for index in relocation address */
+};
+
+EXTERN union
+{
+ struct
+ {
+ char obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+#pragma varargck type "A" uint
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+EXTERN long HEADR;
+EXTERN long HEADTYPE;
+EXTERN long INITDAT;
+EXTERN long INITRND;
+EXTERN long INITTEXT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN long casepc;
+EXTERN int cbc;
+EXTERN char* cbp;
+EXTERN char* pcstr;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN Prog* edatap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN char literal[32];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi8[8];
+EXTERN char fnuxi4[4];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN char ycover[Ymax*Ymax];
+EXTERN uchar* andptr;
+EXTERN uchar and[30];
+EXTERN char reg[D_NONE];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN int maxop;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long nsymbol;
+EXTERN char* noname;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN long spsize;
+EXTERN Sym* symlist;
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+EXTERN Adr* reloca;
+EXTERN int doexp, dlm;
+EXTERN int imports, nimports;
+EXTERN int exports, nexports;
+EXTERN char* EXPTAB;
+EXTERN Prog undefp;
+
+#define UP (&undefp)
+
+extern Optab optab[];
+extern char* anames[];
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Pconv(Fmt*);
+int Rconv(Fmt*);
+int Sconv(Fmt*);
+void addhist(long, int);
+Prog* appendp(Prog*);
+void asmb(void);
+void asmdyn(void);
+void asmins(Prog*);
+void asmlc(void);
+void asmsp(void);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brchain(Prog*);
+Prog* brloop(Prog*);
+void cflush(void);
+void ckoff(Sym*, long);
+Prog* copyp(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doinit(void);
+void doprof1(void);
+void doprof2(void);
+void dostkoff(void);
+void dynreloc(Sym*, ulong, int);
+long entryvalue(void);
+void errorexit(void);
+void export(void);
+int find1(long, int);
+int find2(long, int);
+void follow(void);
+void gethunk(void);
+void histtoauto(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void import(void);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void lputl(long);
+void main(int, char*[]);
+void mkfwd(void);
+void* mysbrk(ulong);
+void nuxiinit(void);
+void objfile(char*);
+int opsize(Prog*);
+void patch(void);
+Prog* prg(void);
+void readundefs(char*, int);
+int relinv(int);
+long reuse(Prog*, Sym*);
+long rnd(long, long);
+void s8put(char*);
+void span(void);
+void undef(void);
+void undefsym(Sym*);
+long vaddr(Adr*);
+void wputb(ushort);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+int zaddr(uchar*, Adr*, Sym*[]);
+void zerosig(char*);
+
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "A" int
diff --git a/utils/8l/list.c b/utils/8l/list.c
new file mode 100644
index 00000000..7fea4cb9
--- /dev/null
+++ b/utils/8l/list.c
@@ -0,0 +1,292 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('R', Rconv);
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('P', Pconv);
+}
+
+static Prog *bigP;
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ switch(p->as) {
+ case ATEXT:
+ if(p->from.scale) {
+ sprint(str, "(%ld) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ default:
+ sprint(str, "(%ld) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
+ break;
+ case ADATA:
+ case AINIT:
+ case ADYNT:
+ sprint(str, "(%ld) %A %D/%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ bigP = P;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ if(bigP != P && bigP->pcond != P)
+ if(a->sym != S)
+ sprint(str, "%lux+%s", bigP->pcond->pc,
+ a->sym->name);
+ else
+ sprint(str, "%lux", bigP->pcond->pc);
+ else
+ sprint(str, "%ld(PC)", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<%d>+%ld(SB)", a->sym->name,
+ a->sym->version, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%ld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%ld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->scon);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", a->index, a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 20) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/8l/mkfile b/utils/8l/mkfile
new file mode 100644
index 00000000..aa383d07
--- /dev/null
+++ b/utils/8l/mkfile
@@ -0,0 +1,29 @@
+<../../mkconfig
+
+TARG=8l
+
+OFILES=\
+ asm.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ list.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../8c/8.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+enam.$O: ../8c/enam.c
+ $CC $CFLAGS ../8c/enam.c
diff --git a/utils/8l/obj.c b/utils/8l/obj.c
new file mode 100644
index 00000000..07e5c53f
--- /dev/null
+++ b/utils/8l/obj.c
@@ -0,0 +1,1492 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = '8';
+char *thestring = "386";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is garbage unix
+ * -H1 -T0xd0 -R4 is unix coff
+ * -H2 -T4128 -R4096 is plan9 format
+ * -H3 -Tx -Rx is MS-DOS .COM
+ * -H4 -Tx -Rx is fake MS-DOS .EXE
+ */
+
+static int
+isobjfile(char *f)
+{
+ int n, v;
+ Biobuf *b;
+ char buf1[5], buf2[SARMAG];
+
+ b = Bopen(f, OREAD);
+ if(b == nil)
+ return 0;
+ n = Bread(b, buf1, 5);
+ if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
+ v = 1; /* good enough for our purposes */
+ else{
+ Bseek(b, 0, 0);
+ n = Bread(b, buf2, SARMAG);
+ v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
+ }
+ Bterm(b);
+ return v;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = "8.out";
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o': /* output to (next arg) */
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'x': /* produce export table */
+ doexp = 1;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SEXPORT);
+ break;
+ case 'u': /* produce dynamically loadable module */
+ dlm = 1;
+ debug['l']++;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SIMPORT);
+ break;
+ } ARGEND
+ USED(argc);
+ if(*argv == 0) {
+ diag("usage: 8l [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 1;
+ if(debug['B'])
+ HEADTYPE = 2;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case 0: /* this is garbage */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* is unix coff */
+ HEADR = 0xd0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xd0;
+ if(INITDAT == -1)
+ INITDAT = 0x400000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+32;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* MS-DOS .COM */
+ HEADR = 0;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0100;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 4: /* fake MS-DOS .EXE */
+ HEADR = 0x200;
+ if(INITTEXT == -1)
+ INITTEXT = 0x0100;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ HEADR += (INITTEXT & 0xFFFF);
+ if(debug['v'])
+ Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
+ }
+ maxop = i;
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ }
+
+ zprg.link = P;
+ zprg.pcond = P;
+ zprg.back = 2;
+ zprg.as = AGOK;
+ zprg.from.type = D_NONE;
+ zprg.from.index = D_NONE;
+ zprg.from.scale = 1;
+ zprg.to = zprg.from;
+
+ pcstr = "%.6lux ";
+ nuxiinit();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ edatap = P;
+ pc = 0;
+ dtype = 4;
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s", outfile);
+ errorexit();
+ }
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ errorexit();
+ if(doexp || dlm){
+ EXPTAB = "_exporttab";
+ zerosig(EXPTAB);
+ zerosig("etext");
+ zerosig("edata");
+ zerosig("end");
+ if(dlm){
+ import();
+ HEADTYPE = 2;
+ INITTEXT = INITDAT = 0;
+ INITRND = 8;
+ INITENTRY = EXPTAB;
+ }
+ export();
+ }
+ patch();
+ follow();
+ dodata();
+ dostkoff();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ span();
+ doinit();
+ asmb();
+ undef();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int c, t, i;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ t = p[0];
+
+ c = 1;
+ if(t & T_INDEX) {
+ a->index = p[c];
+ a->scale = p[c+1];
+ c += 2;
+ } else {
+ a->index = D_NONE;
+ a->scale = 0;
+ }
+ a->offset = 0;
+ if(t & T_OFFSET) {
+ a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ c += 4;
+ }
+ a->sym = S;
+ if(t & T_SYM) {
+ a->sym = h[p[c]];
+ c++;
+ }
+ a->type = D_NONE;
+ if(t & T_FCONST) {
+ a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+ a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
+ c += 8;
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ for(i=0; i<NSNAME; i++)
+ a->scon[i] = p[c+i];
+ c += NSNAME;
+ a->type = D_SCONST;
+ }
+ if(t & T_TYPE) {
+ a->type = p[c];
+ c++;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+
+ t = a->type;
+ if(t != D_AUTO && t != D_PARAM)
+ return c;
+ l = a->offset;
+ for(u=curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ long ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ int v, o, r, skip;
+ Sym *h[NSYM], *s, *di;
+ ulong sig;
+ static int files;
+ static char **filen;
+ char **nfilen;
+
+ if((files&15) == 0){
+ nfilen = malloc((files+16)*sizeof(char*));
+ memmove(nfilen, filen, files*sizeof(char*));
+ free(filen);
+ filen = nfilen;
+ }
+ filen[files++] = strdup(pn);
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0] | (bloc[1] << 8);
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .8 file\n");
+ errorexit();
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME) {
+ sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[2]; /* type */
+ o = bloc[3]; /* sym */
+ bloc += 4;
+ c -= 4;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['S'] && r == 0)
+ sig = 1729;
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
+ s->sig = sig;
+ s->file = files-1;
+ }
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+ p->back = 2;
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("%s: redefinition: %s in %s",
+ pn, s->name, TNAME);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ goto loop;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->from.scale = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_ADDR;
+ p->to.index = D_EXTERN;
+ goto data;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ goto data;
+
+ case ADATA:
+ data:
+ if(edatap == P)
+ datap = p;
+ else
+ edatap->link = p;
+ edatap = p;
+ p->link = P;
+ goto loop;
+
+ case AGOK:
+ diag("%s: GOK opcode in %s", pn, TNAME);
+ pc++;
+ goto loop;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ curtext = p;
+ s = p->from.sym;
+ if(s == S) {
+ diag("%s: no TEXT symbol: %P", pn, p);
+ errorexit();
+ }
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
+ diag("%s: redefinition: %s\n%P", pn, s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->pcond = p;
+ etextp = p;
+ goto loop;
+
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_EXTERN;
+ t->from.sym = s;
+ t->from.scale = 4;
+ t->to = p->from;
+ if(edatap == P)
+ datap = t;
+ else
+ edatap->link = t;
+ edatap = t;
+ t->link = P;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_EXTERN;
+ t->from.sym = s;
+ t->from.scale = 8;
+ t->to = p->from;
+ if(edatap == P)
+ datap = t;
+ else
+ edatap->link = t;
+ edatap = t;
+ t->link = P;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ goto loop;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int l, c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ hash[h] = s;
+ nsymbol++;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+Prog*
+copyp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = q->link;
+ q->link = p;
+ p->line = q->line;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+
+ if(p->from.scale & NOPROF) { /* dont profile */
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ fnuxi4[i] = c;
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", fnuxi4[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+int
+find2(long l, int c)
+{
+ short *p;
+ int i;
+
+ p = (short*)&l;
+ for(i=0; i<4; i+=2) {
+ if(((*p >> 8) & 0xff) == c)
+ return i;
+ if((*p++ & 0xff) == c)
+ return i+1;
+ }
+ return 0;
+}
+
+long
+ieeedtof(Ieee *e)
+{
+ int exp;
+ long v;
+
+ if(e->h == 0)
+ return 0;
+ exp = (e->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (e->h & 0xfffffL) << 3;
+ v |= (e->l >> 29) & 0x7L;
+ if((e->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= e->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
+
+void
+undefsym(Sym *s)
+{
+ int n;
+
+ n = imports;
+ if(s->value != 0)
+ diag("value != 0 on SXREF");
+ if(n >= 1<<Rindex)
+ diag("import index %d out of range", n);
+ s->value = n<<Roffset;
+ s->type = SUNDEF;
+ imports++;
+}
+
+void
+zerosig(char *sp)
+{
+ Sym *s;
+
+ s = lookup(sp, 0);
+ s->sig = 0;
+}
+
+void
+readundefs(char *f, int t)
+{
+ int i, n;
+ Sym *s;
+ Biobuf *b;
+ char *l, buf[256], *fields[64];
+
+ if(f == nil)
+ return;
+ b = Bopen(f, OREAD);
+ if(b == nil){
+ diag("could not open %s: %r", f);
+ errorexit();
+ }
+ while((l = Brdline(b, '\n')) != nil){
+ n = Blinelen(b);
+ if(n >= sizeof(buf)){
+ diag("%s: line too long", f);
+ errorexit();
+ }
+ memmove(buf, l, n);
+ buf[n-1] = '\0';
+ n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
+ if(n == nelem(fields)){
+ diag("%s: bad format", f);
+ errorexit();
+ }
+ for(i = 0; i < n; i++){
+ s = lookup(fields[i], 0);
+ s->type = SXREF;
+ s->subtype = t;
+ if(t == SIMPORT)
+ nimports++;
+ else
+ nexports++;
+ }
+ }
+ Bterm(b);
+}
diff --git a/utils/8l/optab.c b/utils/8l/optab.c
new file mode 100644
index 00000000..361125f7
--- /dev/null
+++ b/utils/8l/optab.c
@@ -0,0 +1,654 @@
+#include "l.h"
+
+uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar ytext[] =
+{
+ Ymb, Yi32, Zpseudo,1,
+ 0
+};
+uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,1,
+ Ynone, Yml, Zpseudo,1,
+ Ynone, Yrf, Zpseudo,1,
+ Yml, Ynone, Zpseudo,1,
+ Yrf, Ynone, Zpseudo,1,
+ 0
+};
+uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yincl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zm_r, 1,
+ 0
+};
+uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+uchar yml_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ 0
+};
+uchar ybyte[] =
+{
+ Yi32, Ynone, Zbyte, 1,
+ 0
+};
+uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 1,
+ 0
+};
+uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+uchar ycall[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ Ynone, Ybr, Zcall, 1,
+ 0
+};
+uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ Ynone, Ybr, Zjmp, 1,
+ 0
+};
+
+uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, Px, 0x37 },
+ { AAAD, ynone, Px, 0xd5,0x0a },
+ { AAAM, ynone, Px, 0xd4,0x0a },
+ { AAAS, ynone, Px, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, Px, 0x63 },
+ { ABOUNDL, yrl_m, Px, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTL, yml_rl, Pm, 0xa3 },
+ { ABTW, yml_rl, Pq, 0xa3 },
+ { ABTCL, yml_rl, Pm, 0xbb },
+ { ABTCW, yml_rl, Pq, 0xbb },
+ { ABTRL, yml_rl, Pm, 0xb3 },
+ { ABTRW, yml_rl, Pq, 0xb3 },
+ { ABTSL, yml_rl, Pm, 0xab },
+ { ABTSW, yml_rl, Pq, 0xab },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ADAA, ynone, Px, 0x27 },
+ { ADAS, ynone, Px, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0x48,0xff,(01) },
+ { ADECW, yincl, Pe, 0x48,0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AENTER }, /* botch */
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0x40,0xff,(00) },
+ { AINCW, yincl, Pe, 0x40,0xff,(00) },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, Px, 0xce },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZ, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALEAVEL, ynone, Px, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Px, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px,0,0 },
+ { ANOTB, yscond, Px, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { APOPAL, ynone, Px, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, Px, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, Px, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APUSHAL, ynone, Px, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, Px, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ASAHF, ynone, Px, 0x9e },
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACWD, ynone, Pe, 0x99 },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASYSCALL, ynone, Px, 0xcd,100 },
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yml_ml, Px, 0x87,0x87 },
+ { AXCHGW, yml_ml, Pe, 0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+ { AEND },
+ 0
+};
diff --git a/utils/8l/pass.c b/utils/8l/pass.c
new file mode 100644
index 00000000..9f54d614
--- /dev/null
+++ b/utils/8l/pass.c
@@ -0,0 +1,763 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i;
+ Sym *s;
+ Prog *p;
+ long t, u;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ t = p->from.offset + p->width;
+ if(t > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+ /* allocate small guys */
+ datsize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA)
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t == 0) {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ t = rnd(t, 4);;
+ s->value = t;
+ if(t > MINSIZ)
+ continue;
+ s->value = datsize;
+ datsize += t;
+ s->type = SDATA1;
+ }
+
+ /* allocate the rest of the data */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SDATA) {
+ if(s->type == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ t = s->value;
+ s->value = datsize;
+ datsize += t;
+ }
+
+ if(debug['j']) {
+ /*
+ * pad data with bss that fits up to next
+ * 8k boundary, then push data to 8k
+ */
+ u = rnd(datsize, 8192);
+ u -= datsize;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ if(t > u)
+ continue;
+ u -= t;
+ s->value = datsize;
+ s->type = SDATA;
+ datsize += t;
+ }
+ datsize += u;
+ }
+
+ /* now the bss */
+ bsssize = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ t = s->value;
+ s->value = bsssize + datsize;
+ bsssize += t;
+ }
+ xdefine("edata", SBSS, datsize);
+ xdefine("end", SBSS, bsssize + datsize);
+}
+
+Prog*
+brchain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->as != AJMP)
+ return p;
+ p = p->pcond;
+ }
+ return P;
+}
+
+void
+follow(void)
+{
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+ lastp->link = P;
+ firstp = firstp->link;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == P)
+ return;
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == AJMP)
+ if((q = p->pcond) != P) {
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /* copy up to 4 instructions to avoid branch */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == P)
+ break;
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+
+ case APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPW:
+ case APOPFW:
+ goto brk;
+ }
+ if(q->pcond == P || q->pcond->mark)
+ continue;
+ if(a == ACALL || a == ALOOP)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(p);
+ p = p->link;
+ q->mark = 1;
+ lastp->link = q;
+ lastp = q;
+ if(q->as != a || q->pcond == P || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(q->link);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ brk:;
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark = 1;
+ lastp->link = p;
+ lastp = p;
+ a = p->as;
+ if(a == AJMP || a == ARET || a == AIRETL)
+ return;
+ if(p->pcond != P)
+ if(a != ACALL) {
+ q = brchain(p->link);
+ if(q != P && q->mark)
+ if(a != ALOOP) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(p->link);
+ q = brchain(p->pcond);
+ if(q->mark) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ diag("unknown relation: %s in %s", anames[a], TNAME);
+ return a;
+}
+
+void
+doinit(void)
+{
+ Sym *s;
+ Prog *p;
+ int x;
+
+ for(p = datap; p != P; p = p->link) {
+ x = p->to.type;
+ if(x != D_EXTERN && x != D_STATIC)
+ continue;
+ s = p->to.sym;
+ if(s->type == 0 || s->type == SXREF)
+ diag("undefined %s initializer of %s",
+ s->name, p->from.sym->name);
+ p->to.offset += s->value;
+ p->to.type = D_CONST;
+ if(s->type == SDATA || s->type == SBSS)
+ p->to.offset += INITDAT;
+ }
+}
+
+void
+patch(void)
+{
+ long c;
+ Prog *p, *q;
+ Sym *s;
+ long vexit;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->as == ACALL || p->as == ARET) {
+ s = p->to.sym;
+ if(s) {
+ if(debug['c'])
+ Bprint(&bso, "%s calls %s\n", TNAME, s->name);
+ switch(s->type) {
+ default:
+ diag("undefined: %s in %s", s->name, TNAME);
+ s->type = STEXT;
+ s->value = vexit;
+ break; /* or fall through to set offset? */
+ case STEXT:
+ p->to.offset = s->value;
+ break;
+ case SUNDEF:
+ p->pcond = UP;
+ p->to.offset = 0;
+ break;
+ }
+ p->to.type = D_BRANCH;
+ }
+ }
+ if(p->to.type != D_BRANCH || p->pcond == UP)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range in %s\n%P", TNAME, p);
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P && p->pcond != UP) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ long dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != P; q = q->pcond) {
+ if(q->as != AJMP)
+ break;
+ c++;
+ if(c >= 5000)
+ return P;
+ }
+ return q;
+}
+
+void
+dostkoff(void)
+{
+ Prog *p, *q;
+ long autoffset, deltasp;
+ int a, f, curframe, curbecome, maxbecome;
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == (D_INDIR+D_SP))
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ curtext = p;
+ break;
+
+ case ARET:
+ /* special form of RET is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+ break;
+ }
+ }
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+ case ACALL:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ f = maxbecome - curtext->from.sym->frame;
+ if(f <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += f;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, f);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ autoffset = 0;
+ deltasp = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+ if(autoffset) {
+ p = appendp(p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ }
+ deltasp = autoffset;
+ }
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+ if(p->from.type == D_CONST)
+ goto become;
+
+ if(autoffset) {
+ q = p;
+ p = appendp(p);
+ p->as = ARET;
+
+ q->as = AADJSP;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ }
+ continue;
+
+ become:
+ q = p;
+ p = appendp(p);
+ p->as = AJMP;
+ p->to = q->to;
+ p->pcond = q->pcond;
+
+ q->as = AADJSP;
+ q->from = zprg.from;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ q->to = zprg.to;
+ continue;
+ }
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+void
+import(void)
+{
+ int i;
+ Sym *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
+ if(s->value != 0)
+ diag("value != 0 on SXREF");
+ undefsym(s);
+ Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
+ if(debug['S'])
+ s->sig = 0;
+ }
+}
+
+void
+ckoff(Sym *s, long v)
+{
+ if(v < 0 || v >= 1<<Roffset)
+ diag("relocation offset %ld for %s out of range", v, s->name);
+}
+
+static Prog*
+newdata(Sym *s, int o, int w, int t)
+{
+ Prog *p;
+
+ p = prg();
+ if(edatap == P)
+ datap = p;
+ else
+ edatap->link = p;
+ edatap = p;
+ p->as = ADATA;
+ p->width = w;
+ p->from.scale = w;
+ p->from.type = t;
+ p->from.sym = s;
+ p->from.offset = o;
+ p->to.type = D_CONST;
+ return p;
+}
+
+void
+export(void)
+{
+ int i, j, n, off, nb, sv, ne;
+ Sym *s, *et, *str, **esyms;
+ Prog *p;
+ char buf[NSNAME], *t;
+
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ n++;
+ esyms = malloc(n*sizeof(Sym*));
+ ne = n;
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ esyms[n++] = s;
+ for(i = 0; i < ne-1; i++)
+ for(j = i+1; j < ne; j++)
+ if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
+ s = esyms[i];
+ esyms[i] = esyms[j];
+ esyms[j] = s;
+ }
+
+ nb = 0;
+ off = 0;
+ et = lookup(EXPTAB, 0);
+ if(et->type != 0 && et->type != SXREF)
+ diag("%s already defined", EXPTAB);
+ et->type = SDATA;
+ str = lookup(".string", 0);
+ if(str->type == 0)
+ str->type = SDATA;
+ sv = str->value;
+ for(i = 0; i < ne; i++){
+ s = esyms[i];
+ if(debug['S'])
+ s->sig = 0;
+ /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
+
+ /* signature */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.offset = s->sig;
+
+ /* address */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.type = D_ADDR;
+ p->to.index = D_EXTERN;
+ p->to.sym = s;
+
+ /* string */
+ t = s->name;
+ n = strlen(t)+1;
+ for(;;){
+ buf[nb++] = *t;
+ sv++;
+ if(nb >= NSNAME){
+ p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
+ p->to.type = D_SCONST;
+ memmove(p->to.scon, buf, NSNAME);
+ nb = 0;
+ }
+ if(*t++ == 0)
+ break;
+ }
+
+ /* name */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.type = D_ADDR;
+ p->to.index = D_STATIC;
+ p->to.sym = str;
+ p->to.offset = sv-n;
+ }
+
+ if(nb > 0){
+ p = newdata(str, sv-nb, nb, D_STATIC);
+ p->to.type = D_SCONST;
+ memmove(p->to.scon, buf, nb);
+ }
+
+ for(i = 0; i < 3; i++){
+ newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ }
+ et->value = off;
+ if(sv == 0)
+ sv = 1;
+ str->value = sv;
+ exports = ne;
+ free(esyms);
+}
diff --git a/utils/8l/span.c b/utils/8l/span.c
new file mode 100644
index 00000000..ef135474
--- /dev/null
+++ b/utils/8l/span.c
@@ -0,0 +1,1387 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ long v, c, idat;
+ int m, n, again;
+
+ xdefine("etext", STEXT, 0L);
+ idat = INITDAT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+ n = 0;
+
+start:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->to.type == D_BRANCH)
+ if(p->back)
+ p->pc = c;
+ asmins(p);
+ p->pc = c;
+ m = andptr-and;
+ p->mark = m;
+ c += m;
+ }
+
+loop:
+ n++;
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span %d\n", cputime(), n);
+ Bflush(&bso);
+ if(n > 50) {
+ print("span must be looping\n");
+ errorexit();
+ }
+ again = 0;
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->to.type == D_BRANCH) {
+ if(p->back)
+ p->pc = c;
+ asmins(p);
+ m = andptr-and;
+ if(m != p->mark) {
+ p->mark = m;
+ again++;
+ }
+ }
+ p->pc = c;
+ c += p->mark;
+ }
+ if(again) {
+ textsize = c;
+ goto loop;
+ }
+ if(INITRND) {
+ INITDAT = rnd(c, INITRND);
+ if(INITDAT != idat) {
+ idat = INITDAT;
+ goto start;
+ }
+ }
+ xdefine("etext", STEXT, c);
+ if(debug['v'])
+ Bprint(&bso, "etext = %lux\n", c);
+ Bflush(&bso);
+ for(p = textp; p != P; p = p->pcond)
+ p->from.sym->value = p->pc;
+ textsize = c - INITTEXT;
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+ if(s->type == STEXT && s->value == 0)
+ s->value = v;
+}
+
+void
+putsymb(char *s, int t, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ lput(v);
+ if(ver)
+ t += 'a' - 'A';
+ cput(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ cput(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ cput(s[i]);
+ cput(s[i+1]);
+ }
+ cput(0);
+ cput(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ cput(s[i]);
+ cput(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, s);
+ }
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->pcond) {
+ s = p->from.sym;
+ if(s->type != STEXT)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ putsymb(s->name, 'T', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+4, 0);
+
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ cput(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ cput(0); /* 0 vv +lc */
+ cput(s>>24);
+ cput(s>>16);
+ cput(s>>8);
+ cput(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ cput(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ cput(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ cput(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+int
+oclass(Adr *a)
+{
+ long v;
+
+ if(a->type >= D_INDIR || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ return Yi32;
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+ case D_CL:
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_ADDR:
+ if(a->sym == S) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ }
+ return Yi32;
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+void
+asmidx(Adr *a, int base)
+{
+ int i;
+
+ switch(a->index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[a->index] << 3;
+ break;
+ }
+ switch(a->scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *andptr++ = i;
+ return;
+bad:
+ diag("asmidx: bad address %D", a);
+ *andptr++ = 0;
+ return;
+}
+
+static void
+put4(long v)
+{
+ if(dlm && curp != P && reloca != nil){
+ dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
+ reloca = nil;
+ }
+ andptr[0] = v;
+ andptr[1] = v>>8;
+ andptr[2] = v>>16;
+ andptr[3] = v>>24;
+ andptr += 4;
+}
+
+long
+vaddr(Adr *a)
+{
+ int t;
+ long v;
+ Sym *s;
+
+ t = a->type;
+ v = a->offset;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(s != nil) {
+ if(dlm && curp != P)
+ reloca = a;
+ switch(s->type) {
+ case SUNDEF:
+ ckoff(s, v);
+ case STEXT:
+ case SCONST:
+ v += s->value;
+ break;
+ default:
+ v += INITDAT + s->value;
+ }
+ }
+ }
+ return v;
+}
+
+void
+asmand(Adr *a, int r)
+{
+ long v;
+ int t;
+ Adr aa;
+
+ v = a->offset;
+ t = a->type;
+ if(a->index != D_NONE) {
+ if(t >= D_INDIR) {
+ t -= D_INDIR;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ put4(v);
+ return;
+ }
+ if(v == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, t);
+ put4(v);
+ return;
+ }
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ aa.type = D_NONE+D_INDIR;
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ aa.type = D_SP+D_INDIR;
+ break;
+ }
+ aa.offset = vaddr(a);
+ aa.index = a->index;
+ aa.scale = a->scale;
+ asmand(&aa, r);
+ return;
+ }
+ if(t >= D_AL && t <= D_F0+7) {
+ if(v)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(t >= D_INDIR) {
+ t -= D_INDIR;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ put4(v);
+ return;
+ }
+ if(t == D_SP) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, D_SP);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, D_SP);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a, D_SP);
+ put4(v);
+ return;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(v == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ put4(v);
+ return;
+ }
+ goto bad;
+ }
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ aa.type = D_NONE+D_INDIR;
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ aa.type = D_SP+D_INDIR;
+ break;
+ }
+ aa.index = D_NONE;
+ aa.scale = 1;
+ aa.offset = vaddr(a);
+ asmand(&aa, r);
+ return;
+bad:
+ diag("asmand: bad address %D", a);
+ return;
+}
+
+#define E 0xff
+uchar ymovtab[] =
+{
+/* push */
+ APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
+ APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
+ APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
+ APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
+ APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
+ APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
+
+ APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
+ APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
+ APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
+ APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
+ APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
+ APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
+
+/* pop */
+ APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
+ APOPL, Ynone, Yes, 0, 0x07,E,0,0,
+ APOPL, Ynone, Yss, 0, 0x17,E,0,0,
+ APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
+ APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
+
+ APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
+ APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
+ APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
+ APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
+ APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
+
+/* mov seg */
+ AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
+ AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
+ AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
+ AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
+ AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
+ AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
+
+ AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
+ AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
+ AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
+ AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
+ AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
+ AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
+
+/* mov cr */
+ AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
+ AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
+ AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
+ AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
+
+ AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
+ AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
+ AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
+ AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
+
+/* mov dr */
+ AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
+ AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
+ AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
+
+ AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
+ AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
+ AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
+
+/* mov tr */
+ AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
+ AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
+
+ AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
+ AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
+
+/* lgdt, sgdt, lidt, sidt */
+ AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
+ AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
+ AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
+ AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
+
+/* lldt, sldt */
+ AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
+ AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
+
+/* lmsw, smsw */
+ AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
+ AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
+
+/* ltr, str */
+ AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
+ AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
+
+/* load full pointer */
+ AMOVL, Yml, Ycol, 5, 0,0,0,0,
+ AMOVW, Yml, Ycol, 5, Pe,0,0,0,
+
+/* double shift */
+ ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
+ ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
+
+/* extra imul */
+ AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
+ 0
+};
+
+int
+isax(Adr *a)
+{
+
+ switch(a->type) {
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ return 1;
+ }
+ if(a->index == D_AX)
+ return 1;
+ return 0;
+}
+
+void
+subreg(Prog *p, int from, int to)
+{
+
+ if(debug['Q'])
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from)
+ p->from.type = to;
+ if(p->to.type == from)
+ p->to.type = to;
+
+ if(p->from.index == from)
+ p->from.index = to;
+ if(p->to.index == from)
+ p->to.index = to;
+
+ from += D_INDIR;
+ if(p->from.type == from)
+ p->from.type = to+D_INDIR;
+ if(p->to.type == from)
+ p->to.type = to+D_INDIR;
+
+ if(debug['Q'])
+ print("%P\n", p);
+}
+
+void
+doasm(Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ int z, op, ft, tt;
+ long v;
+
+ o = &optab[p->as];
+ ft = oclass(&p->from) * Ymax;
+ tt = oclass(&p->to) * Ymax;
+ t = o->ytab;
+ if(t == 0) {
+ diag("asmins: noproto %P", p);
+ return;
+ }
+ for(z=0; *t; z+=t[3],t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *andptr++ = Pe;
+ *andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *andptr++ = Pe;
+ break;
+
+ case Pb: /* botch */
+ break;
+ }
+ v = vaddr(&p->from);
+ op = o->op[z];
+ switch(t[2]) {
+ default:
+ diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *andptr++ = op;
+ break;
+
+ case Zm_r:
+ *andptr++ = op;
+ asmand(&p->from, reg[p->to.type]);
+ break;
+
+ case Zaut_r:
+ *andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ asmand(&p->from, reg[p->to.type]);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ break;
+
+ case Zm_o:
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->from.type]);
+ break;
+
+ case Zo_m:
+ *andptr++ = op;
+ asmand(&p->to, o->op[z+1]);
+ break;
+
+ case Zm_ibo:
+ v = vaddr(&p->to);
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ *andptr++ = v;
+ break;
+
+ case Zibo_m:
+ *andptr++ = op;
+ asmand(&p->to, o->op[z+1]);
+ *andptr++ = v;
+ break;
+
+ case Z_ib:
+ v = vaddr(&p->to);
+ case Zib_:
+ *andptr++ = op;
+ *andptr++ = v;
+ break;
+
+ case Zib_rp:
+ *andptr++ = op + reg[p->to.type];
+ *andptr++ = v;
+ break;
+
+ case Zil_rp:
+ *andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zib_rr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ *andptr++ = v;
+ break;
+
+ case Z_il:
+ v = vaddr(&p->to);
+ case Zil_:
+ *andptr++ = op;
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zm_ilo:
+ v = vaddr(&p->to);
+ *andptr++ = op;
+ asmand(&p->from, o->op[z+1]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zilo_m:
+ *andptr++ = op;
+ asmand(&p->to, o->op[z+1]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Zil_rr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ if(o->prefix == Pe) {
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ }
+ else
+ put4(v);
+ break;
+
+ case Z_rp:
+ *andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ *andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *andptr++ = op;
+ asmand(&p->to, reg[p->to.type]);
+ break;
+
+ case Zbr:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 2;
+ if(v >= -128 && v <= 127) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 6-2;
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zcall:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 5;
+ if(dlm && curp != P && p->to.sym->type == SUNDEF){
+ /* v = 0 - p->pc - 5; */
+ v = 0;
+ ckoff(p->to.sym, v);
+ v += p->to.sym->value;
+ dynreloc(p->to.sym, p->pc+1, 0);
+ }
+ *andptr++ = op;
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ break;
+
+ case Zjmp:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 2;
+ if(v >= -128 && v <= 127) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 5-2;
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zloop:
+ q = p->pcond;
+ if(q) {
+ v = q->pc - p->pc - 2;
+ if(v < -128 && v > 127)
+ diag("loop too far: %P", p);
+ *andptr++ = op;
+ *andptr++ = v;
+ }
+ break;
+
+ case Zbyte:
+ *andptr++ = v;
+ if(op > 1) {
+ *andptr++ = v>>8;
+ if(op > 2) {
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zmov:
+ goto domov;
+ }
+ return;
+
+domov:
+ for(t=ymovtab; *t; t+=8)
+ if(p->as == t[0])
+ if(ycover[ft+t[1]])
+ if(ycover[tt+t[2]])
+ goto mfound;
+bad:
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->to)) {
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(&p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(&p->from, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->from)) {
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(&p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(&pp);
+ *andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(&p->to, reg[D_BX]);
+ } else {
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(&pp);
+ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(t[3]) {
+ default:
+ diag("asmins: unknown mov %d %P", t[3], p);
+ break;
+
+ case 0: /* lit */
+ for(z=4; t[z]!=E; z++)
+ *andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *andptr++ = t[4];
+ asmand(&p->to, t[5]);
+ break;
+
+ case 2: /* m,r */
+ *andptr++ = t[4];
+ asmand(&p->from, t[5]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->to, t[6]);
+ break;
+
+ case 4: /* m,r - 2op */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->from, t[6]);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[4])
+ *andptr++ = t[4];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *andptr++ = 0x0f;
+ *andptr++ = 0xb5;
+ break;
+ }
+ asmand(&p->from, reg[p->to.type]);
+ break;
+
+ case 6: /* double shift */
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *andptr++ = 0x0f;
+ *andptr++ = t[4];
+ asmand(&p->to, reg[p->from.index]);
+ *andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *andptr++ = 0x0f;
+ *andptr++ = t[5];
+ asmand(&p->to, reg[p->from.index]);
+ break;
+ }
+ break;
+
+ case 7: /* imul rm,r */
+ *andptr++ = t[4];
+ *andptr++ = t[5];
+ asmand(&p->from, reg[p->to.type]);
+ break;
+ }
+}
+
+void
+asmins(Prog *p)
+{
+
+ andptr = and;
+ doasm(p);
+}
+
+enum{
+ ABSD = 0,
+ ABSU = 1,
+ RELD = 2,
+ RELU = 3,
+};
+
+int modemap[4] = { 0, 1, -1, 2, };
+
+typedef struct Reloc Reloc;
+
+struct Reloc
+{
+ int n;
+ int t;
+ uchar *m;
+ ulong *a;
+};
+
+Reloc rels;
+
+static void
+grow(Reloc *r)
+{
+ int t;
+ uchar *m, *nm;
+ ulong *a, *na;
+
+ t = r->t;
+ r->t += 64;
+ m = r->m;
+ a = r->a;
+ r->m = nm = malloc(r->t*sizeof(uchar));
+ r->a = na = malloc(r->t*sizeof(ulong));
+ memmove(nm, m, t*sizeof(uchar));
+ memmove(na, a, t*sizeof(ulong));
+ free(m);
+ free(a);
+}
+
+void
+dynreloc(Sym *s, ulong v, int abs)
+{
+ int i, k, n;
+ uchar *m;
+ ulong *a;
+ Reloc *r;
+
+ if(s->type == SUNDEF)
+ k = abs ? ABSU : RELU;
+ else
+ k = abs ? ABSD : RELD;
+ /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
+ k = modemap[k];
+ r = &rels;
+ n = r->n;
+ if(n >= r->t)
+ grow(r);
+ m = r->m;
+ a = r->a;
+ for(i = n; i > 0; i--){
+ if(v < a[i-1]){ /* happens occasionally for data */
+ m[i] = m[i-1];
+ a[i] = a[i-1];
+ }
+ else
+ break;
+ }
+ m[i] = k;
+ a[i] = v;
+ r->n++;
+}
+
+static int
+sput(char *s)
+{
+ char *p;
+
+ p = s;
+ while(*s)
+ cput(*s++);
+ cput(0);
+ return s-p+1;
+}
+
+void
+asmdyn()
+{
+ int i, n, t, c;
+ Sym *s;
+ ulong la, ra, *a;
+ vlong off;
+ uchar *m;
+ Reloc *r;
+
+ cflush();
+ off = seek(cout, 0, 1);
+ lput(0);
+ t = 0;
+ lput(imports);
+ t += 4;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SUNDEF){
+ lput(s->sig);
+ t += 4;
+ t += sput(s->name);
+ }
+
+ la = 0;
+ r = &rels;
+ n = r->n;
+ m = r->m;
+ a = r->a;
+ lput(n);
+ t += 4;
+ for(i = 0; i < n; i++){
+ ra = *a-la;
+ if(*a < la)
+ diag("bad relocation order");
+ if(ra < 256)
+ c = 0;
+ else if(ra < 65536)
+ c = 1;
+ else
+ c = 2;
+ cput((c<<6)|*m++);
+ t++;
+ if(c == 0){
+ cput(ra);
+ t++;
+ }
+ else if(c == 1){
+ wputb(ra);
+ t += 2;
+ }
+ else{
+ lput(ra);
+ t += 4;
+ }
+ la = *a++;
+ }
+
+ cflush();
+ seek(cout, off, 0);
+ lput(t);
+
+ if(debug['v']){
+ Bprint(&bso, "import table entries = %d\n", imports);
+ Bprint(&bso, "export table entries = %d\n", exports);
+ }
+}
diff --git a/utils/NOTICE b/utils/NOTICE
new file mode 100644
index 00000000..23704de9
--- /dev/null
+++ b/utils/NOTICE
@@ -0,0 +1,34 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+ Portions Copyright © 1997-1999 Vita Nuova Limited
+ Portions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com)
+ Portions Copyright © 2004,2006 Bruce Ellis
+ Portions Copyright © 2006,2006 C H Forsyth (forsyth@terzarima.net)
+ Revisions Copyright © 2000-2006 Lucent Technologies Inc. and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/utils/acid/386 b/utils/acid/386
new file mode 100644
index 00000000..53f4ce22
--- /dev/null
+++ b/utils/acid/386
@@ -0,0 +1,146 @@
+// 386 support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'b';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/386/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+ Labspoff = 4; // adjustment to Label's sp
+ Labpcoff = 0; // adjustment to Label's pc
+}
+
+defn linkreg(addr)
+{
+ return 0;
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, 0, 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, 0, 1);
+}
+
+defn kstk() // kernel stack
+{
+ _stk(*PC-Labpcoff, *SP-Labspoff, 0, 0);
+}
+
+defn lkstk() // kernel stack and locals
+{
+ _stk(*PC-Labpcoff, *SP-Labspoff, 0, 1);
+}
+defn gpr() // print general(hah hah!) purpose registers
+{
+ print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n");
+ print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n");
+ print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n");
+ print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n");
+
+ cause = *TRAP;
+ print("TRAP\t", cause, " ", reason(cause), "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*TRAP), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+aggr Ureg
+{
+ 'U' 0 di;
+ 'U' 4 si;
+ 'U' 8 bp;
+ 'U' 12 nsp;
+ 'U' 16 bx;
+ 'U' 20 dx;
+ 'U' 24 cx;
+ 'U' 28 ax;
+ 'U' 32 gs;
+ 'U' 36 fs;
+ 'U' 40 es;
+ 'U' 44 ds;
+ 'U' 48 trap;
+ 'U' 52 ecode;
+ 'U' 56 pc;
+ 'U' 60 cs;
+ 'U' 64 flags;
+ {
+ 'U' 68 usp;
+ 'U' 68 sp;
+ };
+ 'U' 72 ss;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" di ", addr.di, "\n");
+ print(" si ", addr.si, "\n");
+ print(" bp ", addr.bp, "\n");
+ print(" nsp ", addr.nsp, "\n");
+ print(" bx ", addr.bx, "\n");
+ print(" dx ", addr.dx, "\n");
+ print(" cx ", addr.cx, "\n");
+ print(" ax ", addr.ax, "\n");
+ print(" gs ", addr.gs, "\n");
+ print(" fs ", addr.fs, "\n");
+ print(" es ", addr.es, "\n");
+ print(" ds ", addr.ds, "\n");
+ print(" trap ", addr.trap, "\n");
+ print(" ecode ", addr.ecode, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" cs ", addr.cs, "\n");
+ print(" flags ", addr.flags, "\n");
+ print(" sp ", addr.sp, "\n");
+ print("}\n");
+ print(" ss ", addr.ss, "\n");
+};
+
+print("/sys/lib/acid/386");
diff --git a/utils/acid/B.sh b/utils/acid/B.sh
new file mode 100644
index 00000000..15570c7d
--- /dev/null
+++ b/utils/acid/B.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+line=`/bin/echo $1 | /bin/sed 's/-//'`
+if [ "x$EDITOR" = "x" ] ; then
+ vi +$line $2
+else
+ $EDITOR +$line $2
+fi
diff --git a/utils/acid/acid.h b/utils/acid/acid.h
new file mode 100644
index 00000000..68c8913d
--- /dev/null
+++ b/utils/acid/acid.h
@@ -0,0 +1,317 @@
+/* acid.h */
+enum
+{
+ Eof = -1,
+ Strsize = 4096,
+ Hashsize = 128,
+ Maxarg = 512,
+ NFD = 100,
+ Maxproc = 50,
+ Maxval = 10,
+ Mempergc = 1024*1024,
+};
+
+#pragma varargck type "L" void
+
+typedef struct Node Node;
+typedef struct String String;
+typedef struct Lsym Lsym;
+typedef struct List List;
+typedef struct Store Store;
+typedef struct Gc Gc;
+typedef struct Strc Strc;
+typedef struct Rplace Rplace;
+typedef struct Ptab Ptab;
+typedef struct Value Value;
+typedef struct Type Type;
+typedef struct Frtype Frtype;
+
+Extern int kernel;
+Extern int remote;
+Extern int rdebug;
+Extern int remfd;
+Extern int protodebug;
+Extern int text;
+Extern int silent;
+Extern Fhdr fhdr;
+Extern int line;
+Extern Biobuf* bout;
+Extern Biobuf* io[32];
+Extern int iop;
+Extern char symbol[Strsize];
+Extern int interactive;
+Extern Node* code;
+Extern int na;
+Extern int wtflag;
+Extern Map* cormap;
+Extern Map* symmap;
+Extern Lsym* hash[Hashsize];
+Extern long dogc;
+Extern Rplace* ret;
+Extern char* filename;
+Extern char* aout;
+Extern int gotint;
+Extern long flen;
+Extern Gc* gcl;
+Extern int stacked;
+Extern jmp_buf err;
+Extern Node* prnt;
+Extern Node* fomt;
+Extern List* tracelist;
+Extern int initialising;
+Extern int quiet;
+extern void (*expop[])(Node*, Node*);
+#define expr(n, r) (r)->nstore.comt=0; (*expop[(n)->op])(n, r);
+
+enum
+{
+ TINT,
+ TFLOAT,
+ TSTRING,
+ TLIST,
+ TCODE,
+};
+
+struct Type
+{
+ Type* next;
+ int offset;
+ char fmt;
+ char depth;
+ Lsym* type;
+ Lsym* tag;
+ Lsym* base;
+};
+
+struct Frtype
+{
+ Lsym* var;
+ Type* type;
+ Frtype* next;
+};
+
+struct Ptab
+{
+ int pid;
+ int ctl;
+};
+Extern Ptab ptab[Maxproc];
+
+struct Rplace
+{
+ jmp_buf rlab;
+ Node* stak;
+ Node* val;
+ Lsym* local;
+ Lsym** tail;
+};
+
+struct Gc
+{
+ char gcmark;
+ Gc* gclink;
+};
+
+struct Store
+{
+ char fmt;
+ Type* comt;
+ union {
+ vlong sival;
+ double sfval;
+ String* sstring;
+ List* sl;
+ Node* scc;
+ } u0;
+};
+
+struct List
+{
+ Gc lgc;
+ List* next;
+ char type;
+ Store lstore;
+};
+
+struct Value
+{
+ char set;
+ char type;
+ Store vstore;
+ Value* pop;
+ Lsym* scope;
+ Rplace* ret;
+};
+
+struct Lsym
+{
+ char* name;
+ int lexval;
+ Lsym* hash;
+ Value* v;
+ Type* lt;
+ Node* proc;
+ Frtype* local;
+ void (*builtin)(Node*, Node*);
+};
+
+struct Node
+{
+ Gc ngc;
+ char op;
+ char type;
+ Node* left;
+ Node* right;
+ Lsym* sym;
+ Store nstore;
+};
+#define ZN (Node*)0
+
+struct String
+{
+ Gc sgc;
+ char *string;
+ int len;
+};
+
+List* addlist(List*, List*);
+List* al(int);
+Node* an(int, Node*, Node*);
+void append(Node*, Node*, Node*);
+int bool(Node*);
+void build(Node*);
+void call(char*, Node*, Node*, Node*, Node*);
+void checkqid(int, int);
+void cmd(void);
+Node* con(int);
+List* construct(Node*);
+void ctrace(int);
+void decl(Node*);
+void defcomplex(Node*, Node*);
+void deinstall(int);
+void delete(List*, int n, Node*);
+void detach(void);
+void dostop(int);
+Lsym* enter(char*, int);
+void error(char*, ...);
+void execute(Node*);
+void fatal(char*, ...);
+ulong findframe(ulong);
+void flatten(Node**, Node*);
+void gc(void);
+char* getstatus(int);
+void* gmalloc(long);
+void indir(Map*, ulong, char, Node*);
+void install(int);
+void installbuiltin(void);
+void kinit(void);
+int Lfmt(Fmt*);
+int listcmp(List*, List*);
+int listlen(List*);
+List* listvar(char*, long);
+void loadmodule(char*);
+void loadvars(void);
+Lsym* look(char*);
+void ltag(char*);
+void setup_os_notify(void);
+void marklist(List*);
+Lsym* mkvar(char*);
+void msg(int, char*);
+void notes(int);
+int nproc(char**);
+void nthelem(List*, int, Node*);
+int numsym(char);
+void odot(Node*, Node*);
+int opentty(char*, int);
+void closetty(int);
+void pcode(Node*, int);
+void pexpr(Node*);
+int popio(void);
+void pstr(String*);
+void pushfile(char*);
+void pushstr(Node*);
+ulong raddr(char*);
+void readtext(char*);
+int remcondset(char, ulong);
+int remcondstartstop(int);
+int remget(struct segment*, ulong, long, char*, int);
+int remoteio(int, char*, char*, int);
+int remote_read(int, char*, int);
+int remote_write(int, char*, int);
+int remput(struct segment*, ulong, long, char*, int);
+void restartio(void);
+vlong rget(Map*, char*);
+String *runenode(Rune*);
+char* runcmd(char*);
+int scmp(String*, String*);
+void setdbg_opt(char, int);
+int sendremote(int, char*);
+void sproc(int);
+String* stradd(String*, String*);
+String* strnode(char*);
+String* strnodlen(char*, int);
+char* mysystem(void);
+void trlist(Map*, ulong, ulong, Symbol*);
+void unwind(void);
+void userinit(void);
+void varreg(void);
+void varsym(void);
+char* waitfor(int);
+void whatis(Lsym*);
+void windir(Map*, Node*, Node*, Node*);
+void yyerror(char*, ...);
+int yylex(void);
+int yyparse(void);
+
+enum
+{
+ ONAME,
+ OCONST,
+ OMUL,
+ ODIV,
+ OMOD,
+ OADD,
+ OSUB,
+ ORSH,
+ OLSH,
+ OLT,
+ OGT,
+ OLEQ,
+ OGEQ,
+ OEQ,
+ ONEQ,
+ OLAND,
+ OXOR,
+ OLOR,
+ OCAND,
+ OCOR,
+ OASGN,
+ OINDM,
+ OEDEC,
+ OEINC,
+ OPINC,
+ OPDEC,
+ ONOT,
+ OIF,
+ ODO,
+ OLIST,
+ OCALL,
+ OCTRUCT,
+ OWHILE,
+ OELSE,
+ OHEAD,
+ OTAIL,
+ OAPPEND,
+ ORET,
+ OINDEX,
+ OINDC,
+ ODOT,
+ OLOCAL,
+ OFRAME,
+ OCOMPLEX,
+ ODELETE,
+ OCAST,
+ OFMT,
+ OEVAL,
+ OWHAT,
+};
diff --git a/utils/acid/arm b/utils/acid/arm
new file mode 100644
index 00000000..79f6eb14
--- /dev/null
+++ b/utils/acid/arm
@@ -0,0 +1 @@
+please remove this file
diff --git a/utils/acid/builtin.c b/utils/acid/builtin.c
new file mode 100644
index 00000000..2afc447b
--- /dev/null
+++ b/utils/acid/builtin.c
@@ -0,0 +1,1285 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#include "regexp.h"
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+void cvtatof(Node*, Node*);
+void cvtatoi(Node*, Node*);
+void cvtitoa(Node*, Node*);
+void bprint(Node*, Node*);
+void funcbound(Node*, Node*);
+void printto(Node*, Node*);
+void getfile(Node*, Node*);
+void fmt(Node*, Node*);
+void pcfile(Node*, Node*);
+void pcline(Node*, Node*);
+void setproc(Node*, Node*);
+void strace(Node*, Node*);
+void follow(Node*, Node*);
+void reason(Node*, Node*);
+void newproc(Node*, Node*);
+void startstop(Node*, Node*);
+void match(Node*, Node*);
+void status(Node*, Node*);
+void dokill(Node*,Node*);
+void waitstop(Node*, Node*);
+void stop(Node*, Node*);
+void start(Node*, Node*);
+void filepc(Node*, Node*);
+void doerror(Node*, Node*);
+void rc(Node*, Node*);
+void doaccess(Node*, Node*);
+void map(Node*, Node*);
+void readfile(Node*, Node*);
+void interpret(Node*, Node*);
+void include(Node*, Node*);
+void regexp(Node*, Node*);
+void _bpcondset(Node*, Node*);
+void _bpconddel(Node*, Node*);
+void setdebug(Node*, Node*);
+
+typedef struct Btab Btab;
+struct Btab
+{
+ char *name;
+ void (*fn)(Node*, Node*);
+} tab[] =
+{
+ "atof", cvtatof,
+ "atoi", cvtatoi,
+ "error", doerror,
+ "file", getfile,
+ "readfile", readfile,
+ "access", doaccess,
+ "filepc", filepc,
+ "fnbound", funcbound,
+ "fmt", fmt,
+ "follow", follow,
+ "itoa", cvtitoa,
+ "kill", dokill,
+ "match", match,
+ "newproc", newproc,
+ "pcfile", pcfile,
+ "pcline", pcline,
+ "print", bprint,
+ "printto", printto,
+ "rc", rc,
+ "reason", reason,
+ "setproc", setproc,
+ "sh", rc,
+ "start", start,
+ "startstop", startstop,
+ "status", status,
+ "stop", stop,
+ "strace", strace,
+ "waitstop", waitstop,
+ "map", map,
+ "interpret", interpret,
+ "include", include,
+ "regexp", regexp,
+ "debug", setdebug,
+ "_bpcondset", _bpcondset,
+ "_bpconddel", _bpconddel,
+ 0
+};
+
+void
+mkprint(Lsym *s)
+{
+ prnt = gmalloc(sizeof(Node));
+ prnt->op = OCALL;
+ prnt->left = gmalloc(sizeof(Node));
+ prnt->left->sym = s;
+}
+
+void
+installbuiltin(void)
+{
+ Btab *b;
+ Lsym *s;
+
+ b = tab;
+ while(b->name) {
+ s = look(b->name);
+ if(s == 0)
+ s = enter(b->name, Tid);
+
+ s->builtin = b->fn;
+ if(b->fn == bprint)
+ mkprint(s);
+ b++;
+ }
+}
+
+void
+match(Node *r, Node *args)
+{
+ int i;
+ List *f;
+ Node *av[Maxarg];
+ Node resi, resl;
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("match(obj, list): arg count");
+
+ expr(av[1], &resl);
+ if(resl.type != TLIST)
+ error("match(obj, list): need list");
+ expr(av[0], &resi);
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+ r->nstore.u0.sival = -1;
+
+ i = 0;
+ for(f = resl.nstore.u0.sl; f; f = f->next) {
+ if(resi.type == f->type) {
+ switch(resi.type) {
+ case TINT:
+ if(resi.nstore.u0.sival == f->lstore.u0.sival) {
+ r->nstore.u0.sival = i;
+ return;
+ }
+ break;
+ case TFLOAT:
+ if(resi.nstore.u0.sfval == f->lstore.u0.sfval) {
+ r->nstore.u0.sival = i;
+ return;
+ }
+ break;
+ case TSTRING:
+ if(scmp(resi.nstore.u0.sstring, f->lstore.u0.sstring)) {
+ r->nstore.u0.sival = i;
+ return;
+ }
+ break;
+ case TLIST:
+ error("match(obj, list): not defined for list");
+ }
+ }
+ i++;
+ }
+}
+
+void
+newproc(Node *r, Node *args)
+{
+ int i;
+ Node res;
+ char *p, *e;
+ char *argv[Maxarg], buf[Strsize];
+
+ i = 1;
+ argv[0] = aout;
+
+ if(args) {
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("newproc(): arg not string");
+ if(res.nstore.u0.sstring->len >= sizeof(buf))
+ error("newproc(): too many arguments");
+ memmove(buf, res.nstore.u0.sstring->string, res.nstore.u0.sstring->len);
+ buf[res.nstore.u0.sstring->len] = '\0';
+ p = buf;
+ e = buf+res.nstore.u0.sstring->len;
+ for(;;) {
+ while(p < e && (*p == '\t' || *p == ' '))
+ *p++ = '\0';
+ if(p >= e)
+ break;
+ argv[i++] = p;
+ if(i >= Maxarg)
+ error("newproc: too many arguments");
+ while(p < e && *p != '\t' && *p != ' ')
+ p++;
+ }
+ }
+ argv[i] = 0;
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+ r->nstore.u0.sival = nproc(argv);
+}
+void
+startstop(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("startstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("startstop(pid): arg type");
+ if(rdebug) {
+ Lsym *s;
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.u0.sival = remcondstartstop(res.nstore.u0.sival);
+ r->nstore.fmt = 'D';
+
+ s = look("_breakid");
+ if(s)
+ s->v->vstore.u0.sival = (int)r->nstore.u0.sival;
+ } else
+ msg(res.nstore.u0.sival, "startstop");
+ notes(res.nstore.u0.sival);
+ dostop(res.nstore.u0.sival);
+}
+
+void
+waitstop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("waitstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("waitstop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.nstore.u0.sival, "waitstop");
+ notes(res.nstore.u0.sival);
+ dostop(res.nstore.u0.sival);
+}
+
+void
+start(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("start(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("start(pid): arg type");
+
+ msg(res.nstore.u0.sival, "start");
+}
+
+void
+stop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("stop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("stop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.nstore.u0.sival, "stop");
+ notes(res.nstore.u0.sival);
+ dostop(res.nstore.u0.sival);
+}
+
+void
+dokill(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("kill(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("kill(pid): arg type");
+
+ msg(res.nstore.u0.sival, "kill");
+ deinstall(res.nstore.u0.sival);
+}
+
+void
+status(Node *r, Node *args)
+{
+ Node res;
+ char *p;
+
+ USED(r);
+ if(args == 0)
+ error("status(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("status(pid): arg type");
+
+ p = getstatus(res.nstore.u0.sival);
+ r->nstore.u0.sstring = strnode(p);
+ r->op = OCONST;
+ r->nstore.fmt = 's';
+ r->type = TSTRING;
+}
+
+void
+reason(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("reason(cause): no cause");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("reason(cause): arg type");
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.fmt = 's';
+ r->nstore.u0.sstring = strnode((*machdata->excep)(cormap, rget));
+}
+
+void
+follow(Node *r, Node *args)
+{
+ int n, i;
+ Node res;
+ ulong f[10];
+ List **tail, *l;
+
+ if(args == 0)
+ error("follow(addr): no addr");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("follow(addr): arg type");
+
+ n = (*machdata->foll)(cormap, res.nstore.u0.sival, rget, f);
+ if (n < 0)
+ error("follow(addr): %r");
+ tail = &r->nstore.u0.sl;
+ for(i = 0; i < n; i++) {
+ l = al(TINT);
+ l->lstore.u0.sival = f[i];
+ l->lstore.fmt = 'X';
+ *tail = l;
+ tail = &l->next;
+ }
+}
+
+void
+funcbound(Node *r, Node *args)
+{
+ int n;
+ Node res;
+ ulong bounds[2];
+ List *l;
+
+ if(args == 0)
+ error("fnbound(addr): no addr");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("fnbound(addr): arg type");
+
+ n = fnbound(res.nstore.u0.sival, bounds);
+ if (n != 0) {
+ r->nstore.u0.sl = al(TINT);
+ l = r->nstore.u0.sl;
+ l->lstore.u0.sival = bounds[0];
+ l->lstore.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = bounds[1];
+ l->lstore.fmt = 'X';
+ }
+}
+
+void
+setproc(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("setproc(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("setproc(pid): arg type");
+
+ sproc(res.nstore.u0.sival);
+}
+
+void
+filepc(Node *r, Node *args)
+{
+ Node res;
+ char *p, c;
+
+ if(args == 0)
+ error("filepc(filename:line): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("filepc(filename:line): arg type");
+
+ p = strchr(res.nstore.u0.sstring->string, ':');
+ if(p == 0)
+ error("filepc(filename:line): bad arg format");
+
+ c = *p;
+ *p++ = '\0';
+ r->nstore.u0.sival = file2pc(res.nstore.u0.sstring->string, atoi(p));
+ p[-1] = c;
+ if(r->nstore.u0.sival == -1)
+ error("filepc(filename:line): can't find address");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+}
+
+void
+interpret(Node *r, Node *args)
+{
+ Node res;
+ int isave;
+
+ if(args == 0)
+ error("interpret(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("interpret(string): arg type");
+
+ pushstr(&res);
+
+ isave = interactive;
+ interactive = 0;
+ r->nstore.u0.sival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+}
+
+void
+include(Node *r, Node *args)
+{
+ Node res;
+ int isave;
+
+ if(args == 0)
+ error("include(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("include(string): arg type");
+
+ pushfile(res.nstore.u0.sstring->string);
+
+ isave = interactive;
+ interactive = 0;
+ r->nstore.u0.sival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+}
+
+void
+rc(Node *r, Node *args)
+{
+ Node res;
+
+ char *p, *q;
+
+ USED(r);
+ if(args == 0)
+ error("error(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("error(string): arg type");
+
+ p = runcmd(res.nstore.u0.sstring->string);
+ q = strrchr(p, ':');
+ if (q)
+ p = q+1;
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(p);
+ r->nstore.fmt = 's';
+}
+
+void
+doerror(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("error(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("error(string): arg type");
+
+ error(res.nstore.u0.sstring->string);
+}
+
+void
+doaccess(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("access(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("access(filename): arg type");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.u0.sival = 0;
+ if(access(res.nstore.u0.sstring->string, OREAD) == 0)
+ r->nstore.u0.sival = 1;
+}
+
+void
+readfile(Node *r, Node *args)
+{
+ Node res;
+ int n, fd;
+ char *buf;
+ Dir *db;
+
+ if(args == 0)
+ error("readfile(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("readfile(filename): arg type");
+
+ fd = open(res.nstore.u0.sstring->string, OREAD);
+ if(fd < 0)
+ return;
+
+ db = dirfstat(fd);
+ if(db == nil || db->length == 0)
+ n = 8192;
+ else
+ n = db->length;
+ free(db);
+
+ buf = gmalloc(n);
+ n = read(fd, buf, n);
+
+ if(n > 0) {
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnodlen(buf, n);
+ r->nstore.fmt = 's';
+ }
+ free(buf);
+ close(fd);
+}
+
+void
+getfile(Node *r, Node *args)
+{
+ int n;
+ char *p;
+ Node res;
+ String *s;
+ Biobuf *bp;
+ List **l, *new;
+
+ if(args == 0)
+ error("file(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("file(filename): arg type");
+
+ r->op = OCONST;
+ r->type = TLIST;
+ r->nstore.u0.sl = 0;
+
+ p = res.nstore.u0.sstring->string;
+ bp = Bopen(p, OREAD);
+ if(bp == 0)
+ return;
+
+ l = &r->nstore.u0.sl;
+ for(;;) {
+ p = Brdline(bp, '\n');
+ n = BLINELEN(bp);
+ if(p == 0) {
+ if(n == 0)
+ break;
+ s = strnodlen(0, n);
+ Bread(bp, s->string, n);
+ }
+ else
+ s = strnodlen(p, n-1);
+
+ new = al(TSTRING);
+ new->lstore.u0.sstring = s;
+ new->lstore.fmt = 's';
+ *l = new;
+ l = &new->next;
+ }
+ Bterm(bp);
+}
+
+void
+cvtatof(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("atof(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("atof(string): arg type");
+
+ r->op = OCONST;
+ r->type = TFLOAT;
+ r->nstore.u0.sfval = atof(res.nstore.u0.sstring->string);
+ r->nstore.fmt = 'f';
+}
+
+void
+cvtatoi(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("atoi(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("atoi(string): arg type");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.u0.sival = strtoul(res.nstore.u0.sstring->string, 0, 0);
+ r->nstore.fmt = 'D';
+}
+
+void
+cvtitoa(Node *r, Node *args)
+{
+ Node res;
+ char buf[128];
+
+ if(args == 0)
+ error("itoa(integer): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("itoa(integer): arg type");
+
+ sprint(buf, "%d", (int)res.nstore.u0.sival);
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(buf);
+ r->nstore.fmt = 's';
+}
+
+List*
+mapent(Map *m)
+{
+ int i;
+ List *l, *n, **t, *h;
+
+ h = 0;
+ t = &h;
+ for(i = 0; i < m->nsegs; i++) {
+ if(m->seg[i].inuse == 0)
+ continue;
+ l = al(TSTRING);
+ n = al(TLIST);
+ n->lstore.u0.sl = l;
+ *t = n;
+ t = &n->next;
+ l->lstore.u0.sstring = strnode(m->seg[i].name);
+ l->lstore.fmt = 's';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = m->seg[i].b;
+ l->lstore.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = m->seg[i].e;
+ l->lstore.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = m->seg[i].f;
+ l->lstore.fmt = 'X';
+ }
+ return h;
+}
+
+void
+map(Node *r, Node *args)
+{
+ int i;
+ Map *m;
+ List *l;
+ char *ent;
+ Node *av[Maxarg], res;
+
+ na = 0;
+ flatten(av, args);
+
+ if(na != 0) {
+ expr(av[0], &res);
+ if(res.type != TLIST)
+ error("map(list): map needs a list");
+ if(listlen(res.nstore.u0.sl) != 4)
+ error("map(list): list must have 4 entries");
+
+ l = res.nstore.u0.sl;
+ if(l->type != TSTRING)
+ error("map name must be a string");
+ ent = l->lstore.u0.sstring->string;
+ m = symmap;
+ i = findseg(m, ent);
+ if(i < 0) {
+ m = cormap;
+ i = findseg(m, ent);
+ }
+ if(i < 0)
+ error("%s is not a map entry", ent);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].b = l->lstore.u0.sival;
+ if (strcmp(ent, "text") == 0)
+ textseg(l->lstore.u0.sival, &fhdr);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].e = l->lstore.u0.sival;
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].f = l->lstore.u0.sival;
+ }
+
+ r->type = TLIST;
+ r->nstore.u0.sl = 0;
+ if(symmap)
+ r->nstore.u0.sl = mapent(symmap);
+ if(cormap) {
+ if(r->nstore.u0.sl == 0)
+ r->nstore.u0.sl = mapent(cormap);
+ else {
+ for(l = r->nstore.u0.sl; l->next; l = l->next)
+ ;
+ l->next = mapent(cormap);
+ }
+ }
+}
+
+void
+flatten(Node **av, Node *n)
+{
+ if(n == 0)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ flatten(av, n->left);
+ flatten(av, n->right);
+ break;
+ default:
+ av[na++] = n;
+ if(na >= Maxarg)
+ error("too many function arguments");
+ break;
+ }
+}
+
+void
+strace(Node *r, Node *args)
+{
+ Node *av[Maxarg], *n, res;
+ ulong pc, sp;
+
+ na = 0;
+ flatten(av, args);
+ if(na != 3)
+ error("strace(pc, sp, link): arg count");
+
+ n = av[0];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): pc bad type");
+ pc = res.nstore.u0.sival;
+
+ n = av[1];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): sp bad type");
+ sp = res.nstore.u0.sival;
+
+ n = av[2];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): link bad type");
+
+ tracelist = 0;
+ if ((*machdata->ctrace)(cormap, pc, sp, res.nstore.u0.sival, trlist) <= 0)
+ error("no stack frame");
+ r->type = TLIST;
+ r->nstore.u0.sl = tracelist;
+}
+
+void
+regerror(char *msg)
+{
+ error(msg);
+}
+
+void
+regexp(Node *r, Node *args)
+{
+ Node res;
+ Reprog *rp;
+ Node *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("regexp(pattern, string): arg count");
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): pattern must be string");
+ rp = regcomp(res.nstore.u0.sstring->string);
+ if(rp == 0)
+ return;
+
+ expr(av[1], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): bad string");
+
+ r->nstore.fmt = 'D';
+ r->type = TINT;
+ r->nstore.u0.sival = regexec(rp, res.nstore.u0.sstring->string, 0, 0);
+ free(rp);
+}
+
+char vfmt[] = "aBbcCdDfFgGiIoOqQrRsuUVxXYZ";
+
+void
+fmt(Node *r, Node *args)
+{
+ Node res;
+ Node *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("fmt(obj, fmt): arg count");
+ expr(av[1], &res);
+ if(res.type != TINT || strchr(vfmt, res.nstore.u0.sival) == 0)
+ error("fmt(obj, fmt): bad format '%c'", (char)res.nstore.u0.sival);
+ expr(av[0], r);
+ r->nstore.fmt = res.nstore.u0.sival;
+}
+
+void
+patom(char type, Store *res)
+{
+ int i;
+ char buf[512];
+ extern char *typenames[];
+
+ switch(res->fmt) {
+ case 'c':
+ Bprint(bout, "%c", (int)res->u0.sival);
+ break;
+ case 'C':
+ if(res->u0.sival < ' ' || res->u0.sival >= 0x7f)
+ Bprint(bout, "%3d", (int)res->u0.sival&0xff);
+ else
+ Bprint(bout, "%3c", (int)res->u0.sival);
+ break;
+ case 'r':
+ Bprint(bout, "%C", (int)res->u0.sival);
+ break;
+ case 'B':
+ memset(buf, '0', 34);
+ buf[1] = 'b';
+ for(i = 0; i < 32; i++) {
+ if(res->u0.sival & (1<<i))
+ buf[33-i] = '1';
+ }
+ buf[35] = '\0';
+ Bprint(bout, "%s", buf);
+ break;
+ case 'b':
+ Bprint(bout, "%3d", (int)res->u0.sival&0xff);
+ break;
+ case 'X':
+ Bprint(bout, "%.8lux", (int)res->u0.sival);
+ break;
+ case 'x':
+ Bprint(bout, "%.4lux", (int)res->u0.sival&0xffff);
+ break;
+ case 'Y':
+ Bprint(bout, "%.16llux", res->u0.sival);
+ break;
+ case 'D':
+ Bprint(bout, "%d", (int)res->u0.sival);
+ break;
+ case 'd':
+ Bprint(bout, "%d", (ushort)res->u0.sival);
+ break;
+ case 'u':
+ Bprint(bout, "%ud", (int)res->u0.sival&0xffff);
+ break;
+ case 'U':
+ Bprint(bout, "%ud", (ulong)res->u0.sival);
+ break;
+ case 'Z':
+ Bprint(bout, "%llud", res->u0.sival);
+ break;
+ case 'V':
+ Bprint(bout, "%lld", res->u0.sival);
+ break;
+ case 'o':
+ Bprint(bout, "0%.11uo", (int)res->u0.sival&0xffff);
+ break;
+ case 'O':
+ Bprint(bout, "0%.6uo", (int)res->u0.sival);
+ break;
+ case 'q':
+ Bprint(bout, "0%.11o", (short)(res->u0.sival&0xffff));
+ break;
+ case 'Q':
+ Bprint(bout, "0%.6o", (int)res->u0.sival);
+ break;
+ case 'f':
+ case 'F':
+ if(type != TFLOAT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bprint(bout, "%g", res->u0.sfval);
+ break;
+ case 's':
+ case 'g':
+ case 'G':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bwrite(bout, res->u0.sstring->string, res->u0.sstring->len);
+ break;
+ case 'R':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bprint(bout, "%S", res->u0.sstring->string);
+ break;
+ case 'a':
+ case 'A':
+ symoff(buf, sizeof(buf), res->u0.sival, CANY);
+ Bprint(bout, "%s", buf);
+ break;
+ case 'I':
+ case 'i':
+ if(type != TINT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else {
+ if ((*machdata->das)(symmap, res->u0.sival, res->fmt, buf, sizeof(buf)) < 0)
+ Bprint(bout, "no instruction: %r");
+ else
+ Bprint(bout, "%s", buf);
+ }
+ break;
+ }
+}
+
+void
+blprint(List *l)
+{
+ Bprint(bout, "{");
+ while(l) {
+ switch(l->type) {
+ default:
+ patom(l->type, &l->lstore);
+ break;
+ case TSTRING:
+ Bputc(bout, '"');
+ patom(l->type, &l->lstore);
+ Bputc(bout, '"');
+ break;
+ case TLIST:
+ blprint(l->lstore.u0.sl);
+ break;
+ case TCODE:
+ pcode(l->lstore.u0.scc, 0);
+ break;
+ }
+ l = l->next;
+ if(l)
+ Bprint(bout, ", ");
+ }
+ Bprint(bout, "}");
+}
+
+int
+comx(Node res)
+{
+ Lsym *sl;
+ Node *n, xx;
+
+ if(res.nstore.fmt != 'a' && res.nstore.fmt != 'A')
+ return 0;
+
+ if(res.nstore.comt == 0 || res.nstore.comt->base == 0)
+ return 0;
+
+ sl = res.nstore.comt->base;
+ if(sl->proc) {
+ res.left = ZN;
+ res.right = ZN;
+ n = an(ONAME, ZN, ZN);
+ n->sym = sl;
+ n = an(OCALL, n, &res);
+ n->left->sym = sl;
+ expr(n, &xx);
+ return 1;
+ }
+ print("(%s)", sl->name);
+ return 0;
+}
+
+void
+bprint(Node *r, Node *args)
+{
+ int i, nas;
+ Node res, *av[Maxarg];
+
+ USED(r);
+ na = 0;
+ flatten(av, args);
+ nas = na;
+ for(i = 0; i < nas; i++) {
+ expr(av[i], &res);
+ switch(res.type) {
+ default:
+ if(comx(res))
+ break;
+ patom(res.type, &res.nstore);
+ break;
+ case TCODE:
+ pcode(res.nstore.u0.scc, 0);
+ break;
+ case TLIST:
+ blprint(res.nstore.u0.sl);
+ break;
+ }
+ }
+ if(ret == 0)
+ Bputc(bout, '\n');
+}
+
+void
+printto(Node *r, Node *args)
+{
+ int fd;
+ Biobuf *b;
+ int i, nas;
+ Node res, *av[Maxarg];
+
+ USED(r);
+ na = 0;
+ flatten(av, args);
+ nas = na;
+
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("printto(string, ...): need string");
+
+ fd = create(res.nstore.u0.sstring->string, OWRITE, 0666);
+ if(fd < 0)
+ fd = open(res.nstore.u0.sstring->string, OWRITE);
+ if(fd < 0)
+ error("printto: open %s: %r", res.nstore.u0.sstring->string);
+
+ b = gmalloc(sizeof(Biobuf));
+ Binit(b, fd, OWRITE);
+
+ Bflush(bout);
+ io[iop++] = bout;
+ bout = b;
+
+ for(i = 1; i < nas; i++) {
+ expr(av[i], &res);
+ switch(res.type) {
+ default:
+ if(comx(res))
+ break;
+ patom(res.type, &res.nstore);
+ break;
+ case TLIST:
+ blprint(res.nstore.u0.sl);
+ break;
+ }
+ }
+ if(ret == 0)
+ Bputc(bout, '\n');
+
+ Bterm(b);
+ close(fd);
+ free(b);
+ bout = io[--iop];
+}
+
+void
+pcfile(Node *r, Node *args)
+{
+ Node res;
+ char *p, buf[128];
+
+ if(args == 0)
+ error("pcfile(addr): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("pcfile(addr): arg type");
+
+ r->type = TSTRING;
+ r->nstore.fmt = 's';
+ if(fileline(buf, sizeof(buf), res.nstore.u0.sival) == 0) {
+ r->nstore.u0.sstring = strnode("?file?");
+ return;
+ }
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcfile(addr): funny file %s", buf);
+ *p = '\0';
+ r->nstore.u0.sstring = strnode(buf);
+}
+
+void
+pcline(Node *r, Node *args)
+{
+ Node res;
+ char *p, buf[128];
+
+ if(args == 0)
+ error("pcline(addr): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("pcline(addr): arg type");
+
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+ if(fileline(buf, sizeof(buf), res.nstore.u0.sival) == 0) {
+ r->nstore.u0.sival = 0;
+ return;
+ }
+
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcline(addr): funny file %s", buf);
+ r->nstore.u0.sival = atoi(p+1);
+}
+
+void
+_bpcondset(Node *r, Node *args)
+{
+ Node id, p, addr, conds;
+ Node *av[Maxarg];
+ List *l;
+ char *op;
+ List *val;
+ ulong pid;
+
+ USED(r);
+
+ if(!rdebug)
+ error("_bpcondset(id, pid, addr, conds): only available with remote debugger\n");
+
+ if(args == 0)
+ error("_bpcondset(id, pid, addr, conds): not enough args");
+ na = 0;
+ flatten(av, args);
+ if(na != 4)
+ error("_bpcondset(id, pid, addr, conds): %s args",
+ na > 4 ? "too many" : "too few");
+ expr(av[0], &id);
+ expr(av[1], &p);
+ expr(av[2], &addr);
+ expr(av[3], &conds);
+ if(id.type != TINT)
+ error("_bpcondset(id, pid, addr, conds): id: integer expected");
+ if(p.type != TINT)
+ error("_bpcondset(pid, addr, conds): pid: integer expected");
+ if(addr.type != TINT)
+ error("_bpcondset(pid, addr, conds): addr: integer expected");
+ if(conds.type != TLIST)
+ error("_bpcondset(pid, addr, conds): conds: list expected");
+ l = conds.nstore.u0.sl;
+ remcondset('n', (ulong)id.nstore.u0.sival);
+ pid = (ulong)p.nstore.u0.sival;
+ if (pid != 0)
+ remcondset('k', pid);
+ while(l != nil) {
+ if(l->type != TLIST || listlen(l->lstore.u0.sl) != 2)
+ error("_bpcondset(addr, list): list elements are {\"op\", val} pairs");
+ if(l->lstore.u0.sl->type != TSTRING)
+ error("_bpcondset(addr, list): list elements are {string, val} pairs");
+ op = l->lstore.u0.sl->lstore.u0.sstring->string;
+ val = l->lstore.u0.sl->next;
+ if(val->type != TINT)
+ error("_bpcondset(addr, list): list elements are {string, int} pairs");
+ remcondset(op[0], (ulong)val->lstore.u0.sival);
+ l = l->next;
+ }
+ remcondset('b', (ulong)addr.nstore.u0.sival);
+}
+
+void
+_bpconddel(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(!rdebug)
+ error("_bpconddel(id): only available with remote debugger\n");
+
+ expr(args, &res);
+ if(res.type != TINT)
+ error("_bpconddel(id): arg type");
+
+ remcondset('d', (ulong)res.nstore.u0.sival);
+}
+
+void
+setdebug(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ expr(args, &res);
+ if (res.type != TINT)
+ error("debug(type): bad type");
+ setdbg_opt((char)res.nstore.u0.sival, 1);
+}
+
+
+void
+setdbg_opt(char c, int prflag)
+{
+ switch(c) {
+ case 'p':
+ if (protodebug) {
+ protodebug = 0;
+ if (prflag)
+ print("Serial protocol debug is OFF\n");
+ } else {
+ protodebug = 1;
+ if (prflag)
+ print("Serial protocol debug is ON\n");
+ }
+ break;
+ default:
+ print("Invalid debug flag(%c), supported values: p\n", c);
+ break;
+ }
+}
diff --git a/utils/acid/dbg.y b/utils/acid/dbg.y
new file mode 100644
index 00000000..66c1b11d
--- /dev/null
+++ b/utils/acid/dbg.y
@@ -0,0 +1,402 @@
+%{
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+%}
+
+%union
+{
+ Node *node;
+ Lsym *sym;
+ ulong ival;
+ float fval;
+ String *string;
+}
+
+%type <node> expr monexpr term stmnt name args zexpr slist
+%type <node> member members mname castexpr idlist
+%type <sym> zname
+
+%left ';'
+%right '='
+%left Tfmt
+%left Toror
+%left Tandand
+%left '|'
+%left '^'
+%left '&'
+%left Teq Tneq
+%left '<' '>' Tleq Tgeq
+%left Tlsh Trsh
+%left '+' '-'
+%left '*' '/' '%'
+%right Tdec Tinc Tindir '.' '[' '('
+
+%token <sym> Tid
+%token <ival> Tconst Tfmt
+%token <fval> Tfconst
+%token <string> Tstring
+%token Tif Tdo Tthen Telse Twhile Tloop Thead Ttail Tappend Tfn Tret Tlocal
+%token Tcomplex Twhat Tdelete Teval
+
+%%
+
+prog :
+ | prog bigstmnt
+ ;
+
+bigstmnt : stmnt
+ {
+ execute($1);
+ gc();
+ if(interactive)
+ Bprint(bout, "acid: ");
+ }
+ | Tfn Tid '(' args ')' zsemi '{' slist '}'
+ {
+ if($2->builtin)
+ print("warning: %s() is a builtin; definition ignored\n", $2->name);
+ else
+ $2->proc = an(OLIST, $4, $8);
+ }
+ | Tcomplex name '{' members '}' ';'
+ {
+ defcomplex($2, $4);
+ }
+ ;
+
+zsemi :
+ | ';' zsemi
+
+members : member
+ | members member
+ {
+ $$ = an(OLIST, $1, $2);
+ }
+ ;
+
+mname : Tid
+ {
+ $$ = an(ONAME, ZN, ZN);
+ $$->sym = $1;
+ }
+ ;
+
+member : Tconst Tconst mname ';'
+ {
+ $3->nstore.u0.sival = $2;
+ $3->nstore.fmt = $1;
+ $$ = $3;
+ }
+ | Tconst mname Tconst mname ';'
+ {
+ $4->nstore.u0.sival = $3;
+ $4->nstore.fmt = $1;
+ $4->right = $2;
+ $$ = $4;
+ }
+ | mname Tconst mname ';'
+ {
+ $3->nstore.u0.sival = $2;
+ $3->left = $1;
+ $$ = $3;
+ }
+ | '{' members '}' ';'
+ {
+ $$ = an(OCTRUCT, $2, ZN);
+ }
+ ;
+
+zname :
+ { $$ = 0; }
+ | Tid
+ ;
+
+slist : stmnt
+ | slist stmnt
+ {
+ $$ = an(OLIST, $1, $2);
+ }
+ ;
+
+stmnt : zexpr ';'
+ | '{' slist '}'
+ {
+ $$ = $2;
+ }
+ | Tif expr Tthen stmnt
+ {
+ $$ = an(OIF, $2, $4);
+ }
+ | Tif expr Tthen stmnt Telse stmnt
+ {
+ $$ = an(OIF, $2, an(OELSE, $4, $6));
+ }
+ | Tloop expr ',' expr Tdo stmnt
+ {
+ $$ = an(ODO, an(OLIST, $2, $4), $6);
+ }
+ | Twhile expr Tdo stmnt
+ {
+ $$ = an(OWHILE, $2, $4);
+ }
+ | Tret expr ';'
+ {
+ $$ = an(ORET, $2, ZN);
+ }
+ | Tlocal idlist
+ {
+ $$ = an(OLOCAL, $2, ZN);
+ }
+ | Tcomplex Tid name ';'
+ {
+ $$ = an(OCOMPLEX, $3, ZN);
+ $$->sym = $2;
+ }
+ ;
+
+idlist : Tid
+ {
+ $$ = an(ONAME, ZN, ZN);
+ $$->sym = $1;
+ }
+ | idlist ',' Tid
+ {
+ $$ = an(ONAME, $1, ZN);
+ $$->sym = $3;
+ }
+ ;
+
+zexpr :
+ { $$ = 0; }
+ | expr
+ ;
+
+expr : castexpr
+ | expr '*' expr
+ {
+ $$ = an(OMUL, $1, $3);
+ }
+ | expr '/' expr
+ {
+ $$ = an(ODIV, $1, $3);
+ }
+ | expr '%' expr
+ {
+ $$ = an(OMOD, $1, $3);
+ }
+ | expr '+' expr
+ {
+ $$ = an(OADD, $1, $3);
+ }
+ | expr '-' expr
+ {
+ $$ = an(OSUB, $1, $3);
+ }
+ | expr Trsh expr
+ {
+ $$ = an(ORSH, $1, $3);
+ }
+ | expr Tlsh expr
+ {
+ $$ = an(OLSH, $1, $3);
+ }
+ | expr '<' expr
+ {
+ $$ = an(OLT, $1, $3);
+ }
+ | expr '>' expr
+ {
+ $$ = an(OGT, $1, $3);
+ }
+ | expr Tleq expr
+ {
+ $$ = an(OLEQ, $1, $3);
+ }
+ | expr Tgeq expr
+ {
+ $$ = an(OGEQ, $1, $3);
+ }
+ | expr Teq expr
+ {
+ $$ = an(OEQ, $1, $3);
+ }
+ | expr Tneq expr
+ {
+ $$ = an(ONEQ, $1, $3);
+ }
+ | expr '&' expr
+ {
+ $$ = an(OLAND, $1, $3);
+ }
+ | expr '^' expr
+ {
+ $$ = an(OXOR, $1, $3);
+ }
+ | expr '|' expr
+ {
+ $$ = an(OLOR, $1, $3);
+ }
+ | expr Tandand expr
+ {
+ $$ = an(OCAND, $1, $3);
+ }
+ | expr Toror expr
+ {
+ $$ = an(OCOR, $1, $3);
+ }
+ | expr '=' expr
+ {
+ $$ = an(OASGN, $1, $3);
+ }
+ | expr Tfmt
+ {
+ $$ = an(OFMT, $1, con($2));
+ }
+ ;
+
+castexpr : monexpr
+ | '(' Tid ')' monexpr
+ {
+ $$ = an(OCAST, $4, ZN);
+ $$->sym = $2;
+ }
+ ;
+
+monexpr : term
+ | '*' monexpr
+ {
+ $$ = an(OINDM, $2, ZN);
+ }
+ | '@' monexpr
+ {
+ $$ = an(OINDC, $2, ZN);
+ }
+ | '+' monexpr
+ {
+ $$ = con(0);
+ $$ = an(OADD, $2, $$);
+ }
+ | '-' monexpr
+ {
+ $$ = con(0);
+ $$ = an(OSUB, $$, $2);
+ }
+ | Tdec monexpr
+ {
+ $$ = an(OEDEC, $2, ZN);
+ }
+ | Tinc monexpr
+ {
+ $$ = an(OEINC, $2, ZN);
+ }
+ | Thead monexpr
+ {
+ $$ = an(OHEAD, $2, ZN);
+ }
+ | Ttail monexpr
+ {
+ $$ = an(OTAIL, $2, ZN);
+ }
+ | Tappend monexpr ',' monexpr
+ {
+ $$ = an(OAPPEND, $2, $4);
+ }
+ | Tdelete monexpr ',' monexpr
+ {
+ $$ = an(ODELETE, $2, $4);
+ }
+ | '!' monexpr
+ {
+ $$ = an(ONOT, $2, ZN);
+ }
+ | '~' monexpr
+ {
+ $$ = an(OXOR, $2, con(-1));
+ }
+ | Teval monexpr
+ {
+ $$ = an(OEVAL, $2, ZN);
+ }
+ ;
+
+term : '(' expr ')'
+ {
+ $$ = $2;
+ }
+ | '{' args '}'
+ {
+ $$ = an(OCTRUCT, $2, ZN);
+ }
+ | term '[' expr ']'
+ {
+ $$ = an(OINDEX, $1, $3);
+ }
+ | term Tdec
+ {
+ $$ = an(OPDEC, $1, ZN);
+ }
+ | term '.' Tid
+ {
+ $$ = an(ODOT, $1, ZN);
+ $$->sym = $3;
+ }
+ | term Tindir Tid
+ {
+ $$ = an(ODOT, an(OINDM, $1, ZN), ZN);
+ $$->sym = $3;
+ }
+ | term Tinc
+ {
+ $$ = an(OPINC, $1, ZN);
+ }
+ | name '(' args ')'
+ {
+ $$ = an(OCALL, $1, $3);
+ }
+ | name
+ | Tconst
+ {
+ $$ = con($1);
+ }
+ | Tfconst
+ {
+ $$ = an(OCONST, ZN, ZN);
+ $$->type = TFLOAT;
+ $$->nstore.fmt = 'f';
+ $$->nstore.u0.sfval = $1;
+ }
+ | Tstring
+ {
+ $$ = an(OCONST, ZN, ZN);
+ $$->type = TSTRING;
+ $$->nstore.u0.sstring = $1;
+ $$->nstore.fmt = 's';
+ }
+ | Twhat zname
+ {
+ $$ = an(OWHAT, ZN, ZN);
+ $$->sym = $2;
+ }
+ ;
+
+name : Tid
+ {
+ $$ = an(ONAME, ZN, ZN);
+ $$->sym = $1;
+ }
+ | Tid ':' name
+ {
+ $$ = an(OFRAME, $3, ZN);
+ $$->sym = $1;
+ }
+ ;
+
+args : zexpr
+ | args ',' zexpr
+ {
+ $$ = an(OLIST, $1, $3);
+ }
+ ;
diff --git a/utils/acid/dot.c b/utils/acid/dot.c
new file mode 100644
index 00000000..89bcb2c8
--- /dev/null
+++ b/utils/acid/dot.c
@@ -0,0 +1,152 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+Type*
+srch(Type *t, char *s)
+{
+ Type *f;
+
+ f = 0;
+ while(t) {
+ if(strcmp(t->tag->name, s) == 0) {
+ if(f == 0 || t->depth < f->depth)
+ f = t;
+ }
+ t = t->next;
+ }
+ return f;
+}
+
+void
+odot(Node *n, Node *r)
+{
+ char *s;
+ Type *t;
+ Node res;
+ ulong addr;
+
+ s = n->sym->name;
+ if(s == 0)
+ fatal("dodot: no tag");
+
+ expr(n->left, &res);
+ if(res.nstore.comt == 0)
+ error("no type specified for (expr).%s", s);
+
+ if(res.type != TINT)
+ error("pointer must be integer for (expr).%s", s);
+
+ t = srch(res.nstore.comt, s);
+ if(t == 0)
+ error("no tag for (expr).%s", s);
+
+ /* Propagate types */
+ if(t->type)
+ r->nstore.comt = t->type->lt;
+
+ addr = res.nstore.u0.sival+t->offset;
+ if(t->fmt == 'a') {
+ r->op = OCONST;
+ r->nstore.fmt = 'a';
+ r->type = TINT;
+ r->nstore.u0.sival = addr;
+ }
+ else
+ indir(cormap, addr, t->fmt, r);
+
+}
+
+static Type **tail;
+static Lsym *base;
+
+void
+buildtype(Node *m, int d)
+{
+ Type *t;
+
+ if(m == ZN)
+ return;
+
+ switch(m->op) {
+ case OLIST:
+ buildtype(m->left, d);
+ buildtype(m->right, d);
+ break;
+
+ case OCTRUCT:
+ buildtype(m->left, d+1);
+ break;
+ default:
+ t = gmalloc(sizeof(Type));
+ t->next = 0;
+ t->depth = d;
+ t->tag = m->sym;
+ t->base = base;
+ t->offset = m->nstore.u0.sival;
+ if(m->left) {
+ t->type = m->left->sym;
+ t->fmt = 'a';
+ }
+ else {
+ t->type = 0;
+ if(m->right)
+ t->type = m->right->sym;
+ t->fmt = m->nstore.fmt;
+ }
+
+ *tail = t;
+ tail = &t->next;
+ }
+}
+
+void
+defcomplex(Node *tn, Node *m)
+{
+ tail = &tn->sym->lt;
+ base = tn->sym;
+ buildtype(m, 0);
+}
+
+void
+decl(Node *n)
+{
+ Node *l;
+ Value *v;
+ Frtype *f;
+ Lsym *type;
+
+ type = n->sym;
+ if(type->lt == 0)
+ error("%s is not a complex type", type->name);
+
+ l = n->left;
+ if(l->op == ONAME) {
+ v = l->sym->v;
+ v->vstore.comt = type->lt;
+ v->vstore.fmt = 'a';
+ return;
+ }
+
+ /*
+ * Frame declaration
+ */
+ for(f = l->sym->local; f; f = f->next) {
+ if(f->var == l->left->sym) {
+ f->type = n->sym->lt;
+ return;
+ }
+ }
+ f = gmalloc(sizeof(Frtype));
+ if(f == 0)
+ fatal("out of memory");
+
+ f->type = type->lt;
+
+ f->var = l->left->sym;
+ f->next = l->sym->local;
+ l->sym->local = f;
+}
diff --git a/utils/acid/exec.c b/utils/acid/exec.c
new file mode 100644
index 00000000..d110673b
--- /dev/null
+++ b/utils/acid/exec.c
@@ -0,0 +1,490 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+void
+error(char *fmt, ...)
+{
+ int i;
+ char buf[2048];
+ va_list arg;
+
+ /* Unstack io channels */
+ if(iop != 0) {
+ for(i = 1; i < iop; i++)
+ Bterm(io[i]);
+ bout = io[0];
+ iop = 0;
+ }
+
+ ret = 0;
+ gotint = 0;
+ Bflush(bout);
+ if(silent)
+ silent = 0;
+ else {
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%L: (error) %s\n", buf);
+ }
+ while(popio())
+ ;
+ interactive = 1;
+ longjmp(err, 1);
+}
+
+void
+unwind(void)
+{
+ int i;
+ Lsym *s;
+ Value *v;
+
+ for(i = 0; i < Hashsize; i++) {
+ for(s = hash[i]; s; s = s->hash) {
+ while(s->v->pop) {
+ v = s->v->pop;
+ free(s->v);
+ s->v = v;
+ }
+ }
+ }
+}
+
+void
+execute(Node *n)
+{
+ Value *v;
+ Lsym *sl;
+ Node *l, *r;
+ int i, s, e;
+ Node res, xx;
+ static int stmnt;
+
+ if(gotint)
+ error("interrupted");
+
+ if(n == 0)
+ return;
+
+ if(stmnt++ > 5000) {
+ Bflush(bout);
+ stmnt = 0;
+ }
+
+ l = n->left;
+ r = n->right;
+ res.right = 0;
+ res.left = 0;
+ res.sym = 0;
+
+ switch(n->op) {
+ default:
+ expr(n, &res);
+ if(ret || (res.type == TLIST && res.nstore.u0.sl == 0))
+ break;
+ prnt->right = &res;
+ xx.right = 0;
+ xx.left = 0;
+ xx.sym = 0;
+ expr(prnt, &xx);
+ break;
+ case OASGN:
+ case OCALL:
+ expr(n, &res);
+ break;
+ case OCOMPLEX:
+ decl(n);
+ break;
+ case OLOCAL:
+ for(n = n->left; n; n = n->left) {
+ if(ret == 0)
+ error("local not in function");
+ sl = n->sym;
+ if(sl->v->ret == ret)
+ error("%s declared twice", sl->name);
+ v = gmalloc(sizeof(Value));
+ v->ret = ret;
+ v->pop = sl->v;
+ sl->v = v;
+ v->scope = 0;
+ *(ret->tail) = sl;
+ ret->tail = &v->scope;
+ v->set = 0;
+ }
+ break;
+ case ORET:
+ if(ret == 0)
+ error("return not in function");
+ expr(n->left, ret->val);
+ longjmp(ret->rlab, 1);
+ case OLIST:
+ execute(n->left);
+ execute(n->right);
+ break;
+ case OIF:
+ expr(l, &res);
+ if(r && r->op == OELSE) {
+ if(bool(&res))
+ execute(r->left);
+ else
+ execute(r->right);
+ }
+ else if(bool(&res))
+ execute(r);
+ break;
+ case OWHILE:
+ for(;;) {
+ expr(l, &res);
+ if(!bool(&res))
+ break;
+ execute(r);
+ }
+ break;
+ case ODO:
+ expr(l->left, &res);
+ if(res.type != TINT)
+ error("loop must have integer start");
+ s = res.nstore.u0.sival;
+ expr(l->right, &res);
+ if(res.type != TINT)
+ error("loop must have integer end");
+ e = res.nstore.u0.sival;
+ for(i = s; i <= e; i++)
+ execute(r);
+ break;
+ }
+}
+
+int
+bool(Node *n)
+{
+ int true = 0;
+
+ if(n->op != OCONST)
+ fatal("bool: not const");
+
+ switch(n->type) {
+ case TINT:
+ if(n->nstore.u0.sival != 0)
+ true = 1;
+ break;
+ case TFLOAT:
+ if(n->nstore.u0.sfval != 0.0)
+ true = 1;
+ break;
+ case TSTRING:
+ if(n->nstore.u0.sstring->len)
+ true = 1;
+ break;
+ case TLIST:
+ if(n->nstore.u0.sl)
+ true = 1;
+ break;
+ }
+ return true;
+}
+
+void
+convflt(Node *r, char *flt)
+{
+ char c;
+
+ c = flt[0];
+ if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
+ r->type = TSTRING;
+ r->nstore.fmt = 's';
+ r->nstore.u0.sstring = strnode(flt);
+ }
+ else {
+ r->type = TFLOAT;
+ r->nstore.u0.sfval = atof(flt);
+ }
+}
+
+void
+indir(Map *m, ulong addr, char fmt, Node *r)
+{
+ int i;
+ long ival;
+ vlong vval;
+ int ret;
+ uchar cval;
+ ushort sval;
+ char buf[512], reg[12];
+
+ r->op = OCONST;
+ r->nstore.fmt = fmt;
+ switch(fmt) {
+ default:
+ error("bad pointer format '%c' for *", fmt);
+ case 'c':
+ case 'C':
+ case 'b':
+ r->type = TINT;
+ ret = get1(m, addr, &cval, 1);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = cval;
+ break;
+ case 'x':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'q':
+ case 'r':
+ r->type = TINT;
+ ret = get2(m, addr, &sval);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = sval;
+ break;
+ case 'a':
+ case 'A':
+ case 'B':
+ case 'X':
+ case 'D':
+ case 'U':
+ case 'O':
+ case 'Q':
+ r->type = TINT;
+ ret = get4(m, addr, &ival);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = ival;
+ break;
+ case 'V':
+ case 'Y':
+ case 'Z':
+ r->type = TINT;
+ ret = get8(m, addr, &vval);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = vval;
+ break;
+ case 's':
+ r->type = TSTRING;
+ for(i = 0; i < sizeof(buf)-1; i++) {
+ ret = get1(m, addr, (uchar*)&buf[i], 1);
+ if (ret < 0)
+ error("indir: %r");
+ addr++;
+ if(buf[i] == '\0')
+ break;
+ }
+ buf[i] = 0;
+ if(i == 0)
+ strcpy(buf, "(null)");
+ r->nstore.u0.sstring = strnode(buf);
+ break;
+ case 'R':
+ r->type = TSTRING;
+ for(i = 0; i < sizeof(buf)-2; i += 2) {
+ ret = get1(m, addr, (uchar*)&buf[i], 2);
+ if (ret < 0)
+ error("indir: %r");
+ addr += 2;
+ if(buf[i] == 0 && buf[i+1] == 0)
+ break;
+ }
+ buf[i++] = 0;
+ buf[i] = 0;
+ r->nstore.u0.sstring = runenode((Rune*)buf);
+ break;
+ case 'i':
+ case 'I':
+ if ((*machdata->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
+ error("indir: %r");
+ r->type = TSTRING;
+ r->nstore.fmt = 's';
+ r->nstore.u0.sstring = strnode(buf);
+ break;
+ case 'f':
+ ret = get1(m, addr, (uchar*)buf, mach->szfloat);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->sftos(buf, sizeof(buf), (void*) buf);
+ convflt(r, buf);
+ break;
+ case 'g':
+ ret = get1(m, addr, (uchar*)buf, mach->szfloat);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->sftos(buf, sizeof(buf), (void*) buf);
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(buf);
+ break;
+ case 'F':
+ ret = get1(m, addr, (uchar*)buf, mach->szdouble);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->dftos(buf, sizeof(buf), (void*) buf);
+ convflt(r, buf);
+ break;
+ case '3': /* little endian ieee 80 with hole in bytes 8&9 */
+ ret = get1(m, addr, (uchar*)reg, 10);
+ if (ret < 0)
+ error("indir: %r");
+ memmove(reg+10, reg+8, 2); /* open hole */
+ memset(reg+8, 0, 2); /* fill it */
+ leieee80ftos(buf, sizeof(buf), reg);
+ convflt(r, buf);
+ break;
+ case '8': /* big-endian ieee 80 */
+ ret = get1(m, addr, (uchar*)reg, 10);
+ if (ret < 0)
+ error("indir: %r");
+ beieee80ftos(buf, sizeof(buf), reg);
+ convflt(r, buf);
+ break;
+ case 'G':
+ ret = get1(m, addr, (uchar*)buf, mach->szdouble);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->dftos(buf, sizeof(buf), (void*) buf);
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(buf);
+ break;
+ }
+}
+
+void
+windir(Map *m, Node *addr, Node *rval, Node *r)
+{
+ uchar cval;
+ ushort sval;
+ Node res, aes;
+ int ret;
+
+ if(m == 0)
+ error("no map for */@=");
+
+ expr(rval, &res);
+ expr(addr, &aes);
+
+ if(aes.type != TINT)
+ error("bad type lhs of @/*");
+
+ if(m != cormap && wtflag == 0)
+ error("not in write mode");
+
+ r->type = res.type;
+ r->nstore.fmt = res.nstore.fmt;
+ r->nstore = res.nstore;
+
+ switch(res.nstore.fmt) {
+ default:
+ error("bad pointer format '%c' for */@=", res.nstore.fmt);
+ case 'c':
+ case 'C':
+ case 'b':
+ cval = res.nstore.u0.sival;
+ ret = put1(m, aes.nstore.u0.sival, &cval, 1);
+ break;
+ case 'r':
+ case 'x':
+ case 'd':
+ case 'u':
+ case 'o':
+ sval = res.nstore.u0.sival;
+ ret = put2(m, aes.nstore.u0.sival, sval);
+ r->nstore.u0.sival = sval;
+ break;
+ case 'a':
+ case 'A':
+ case 'B':
+ case 'X':
+ case 'D':
+ case 'U':
+ case 'O':
+ ret = put4(m, aes.nstore.u0.sival, res.nstore.u0.sival);
+ break;
+ case 'V':
+ case 'Y':
+ case 'Z':
+ ret = put8(m, aes.nstore.u0.sival, res.nstore.u0.sival);
+ break;
+ case 's':
+ case 'R':
+ ret = put1(m, aes.nstore.u0.sival, (uchar*)res.nstore.u0.sstring->string, res.nstore.u0.sstring->len);
+ break;
+ }
+ if (ret < 0)
+ error("windir: %r");
+}
+
+void
+call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
+{
+ int np, i;
+ Rplace rlab;
+ Node *n, res;
+ Value *v, *f;
+ Lsym *s, *next;
+ Node *avp[Maxarg], *ava[Maxarg];
+
+ rlab.local = 0;
+
+ na = 0;
+ flatten(avp, parameters);
+ np = na;
+ na = 0;
+ flatten(ava, local);
+ if(np != na) {
+ if(np < na)
+ error("%s: too few arguments", fn);
+ error("%s: too many arguments", fn);
+ }
+
+ rlab.tail = &rlab.local;
+
+ ret = &rlab;
+ for(i = 0; i < np; i++) {
+ n = ava[i];
+ switch(n->op) {
+ default:
+ error("%s: %d formal not a name", fn, i);
+ case ONAME:
+ expr(avp[i], &res);
+ s = n->sym;
+ break;
+ case OINDM:
+ res.nstore.u0.scc = avp[i];
+ res.type = TCODE;
+ res.nstore.comt = 0;
+ if(n->left->op != ONAME)
+ error("%s: %d formal not a name", fn, i);
+ s = n->left->sym;
+ break;
+ }
+ if(s->v->ret == ret)
+ error("%s already declared at this scope", s->name);
+
+ v = gmalloc(sizeof(Value));
+ v->ret = ret;
+ v->pop = s->v;
+ s->v = v;
+ v->scope = 0;
+ *(rlab.tail) = s;
+ rlab.tail = &v->scope;
+
+ v->vstore = res.nstore;
+ v->type = res.type;
+ v->set = 1;
+ }
+
+ ret->val = retexp;
+ if(setjmp(rlab.rlab) == 0)
+ execute(body);
+
+ for(s = rlab.local; s; s = next) {
+ f = s->v;
+ next = f->scope;
+ s->v = f->pop;
+ free(f);
+ }
+}
diff --git a/utils/acid/expr.c b/utils/acid/expr.c
new file mode 100644
index 00000000..da413742
--- /dev/null
+++ b/utils/acid/expr.c
@@ -0,0 +1,1032 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+static int fsize[] =
+{
+ 0,0,0,0,0,0,0,0, /* 0-7 */
+ 0,0,0,0,0,0,0,0, /* 8-15 */
+ 0,0,0,0,0,0,0,0, /* 16-23 */
+ 0,0,0,0,0,0,0,0, /* 24-31 */
+ 0,0,0,0,0,0,0,0, /* 32-39 */
+ 0,0,0,0,0,0,0,0, /* 40-47 */
+ 0,0,0,0,0,0,0,0, /* 48-55 */
+ 0,0,0,0,0,0,0,0, /* 56-63 */
+ 0, /* 64 */
+ 4, /* 65 ['A'] 4, */
+ 4, /* 66 ['B'] 4, */
+ 1, /* 67 ['C'] 1, */
+ 4, /* 68 ['D'] 4, */
+ 0, /* 69 */
+ 8, /* 70 ['F'] 8, */
+ 8, /* 71 ['G'] 8, */
+ 0,0,0,0,0,0,0, /* 72-78 */
+ 4, /* 79 ['O'] 4, */
+ 0, /* 80 */
+ 4, /* 81 ['Q'] 4, */
+ 4, /* 82 ['R'] 4, */
+ 4, /* 83 ['S'] 4, */
+ 0, /* 84 */
+ 4, /* 85 ['U'] 4, */
+ 8, /* 86 ['V'] 8, */
+ 0, /* 87 */
+ 4, /* 88 ['X'] 4, */
+ 8, /* 89 ['Y'] 8, */
+ 8, /* 90 ['Z'] 8, */
+ 0,0,0,0,0,0, /* 91-96 */
+ 4, /* 97 ['a'] 4, */
+ 1, /* 98 ['b'] 1, */
+ 1, /* 99 ['c'] 1, */
+ 2, /* 100 ['d'] 2, */
+ 0, /* 101 */
+ 4, /* 102 ['f'] 4, */
+ 4, /* 103 ['g'] 4, */
+ 0,0,0,0,0,0,0, /* 104-110 */
+ 2, /* 111 ['o'] 2, */
+ 0, /* 112 */
+ 2, /* 113 ['q'] 2, */
+ 2, /* 114 ['r'] 2, */
+ 4, /* 115 ['s'] 4, */
+ 0, /* 116 */
+ 2, /* 117 ['u'] 2, */
+ 0,0, /* 118-119 */
+ 2, /* 120 ['x'] 2, */
+};
+
+int
+fmtsize(Value *v)
+{
+ int ret;
+
+ switch(v->vstore.fmt) {
+ default:
+ return fsize[v->vstore.fmt];
+ case 'i':
+ case 'I':
+ if(v->type != TINT || machdata == 0)
+ error("no size for i fmt pointer ++/--");
+ ret = (*machdata->instsize)(cormap, v->vstore.u0.sival);
+ if(ret < 0) {
+ ret = (*machdata->instsize)(symmap, v->vstore.u0.sival);
+ if(ret < 0)
+ error("%r");
+ }
+ return ret;
+ }
+}
+
+void
+chklval(Node *lp)
+{
+ if(lp->op != ONAME)
+ error("need l-value");
+}
+
+void
+olist(Node *n, Node *res)
+{
+ expr(n->left, res);
+ expr(n->right, res);
+}
+
+void
+oeval(Node *n, Node *res)
+{
+ expr(n->left, res);
+ if(res->type != TCODE)
+ error("bad type for eval");
+ expr(res->nstore.u0.scc, res);
+}
+
+void
+ocast(Node *n, Node *res)
+{
+ if(n->sym->lt == 0)
+ error("%s is not a complex type", n->sym->name);
+
+ expr(n->left, res);
+ res->nstore.comt = n->sym->lt;
+ res->nstore.fmt = 'a';
+}
+
+void
+oindm(Node *n, Node *res)
+{
+ Map *m;
+ Node l;
+
+ m = cormap;
+ if(m == 0)
+ m = symmap;
+ expr(n->left, &l);
+ if(l.type != TINT)
+ error("bad type for *");
+ if(m == 0)
+ error("no map for *");
+ indir(m, l.nstore.u0.sival, l.nstore.fmt, res);
+ res->nstore.comt = l.nstore.comt;
+}
+
+void
+oindc(Node *n, Node *res)
+{
+ Map *m;
+ Node l;
+
+ m = symmap;
+ if(m == 0)
+ m = cormap;
+ expr(n->left, &l);
+ if(l.type != TINT)
+ error("bad type for @");
+ if(m == 0)
+ error("no map for @");
+ indir(m, l.nstore.u0.sival, l.nstore.fmt, res);
+ res->nstore.comt = l.nstore.comt;
+}
+
+void
+oframe(Node *n, Node *res)
+{
+ char *p;
+ Node *lp;
+ long ival;
+ Frtype *f;
+
+ p = n->sym->name;
+ while(*p && *p == '$')
+ p++;
+ lp = n->left;
+ if(localaddr(cormap, p, lp->sym->name, &ival, rget) < 0)
+ error("colon: %r");
+
+ res->nstore.u0.sival = ival;
+ res->op = OCONST;
+ res->nstore.fmt = 'X';
+ res->type = TINT;
+
+ /* Try and set comt */
+ for(f = n->sym->local; f; f = f->next) {
+ if(f->var == lp->sym) {
+ res->nstore.comt = f->type;
+ res->nstore.fmt = 'a';
+ break;
+ }
+ }
+}
+
+void
+oindex(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+
+ if(r.type != TINT)
+ error("bad type for []");
+
+ switch(l.type) {
+ default:
+ error("lhs[] has bad type");
+ case TINT:
+ indir(cormap, l.nstore.u0.sival+(r.nstore.u0.sival*fsize[l.nstore.fmt]), l.nstore.fmt, res);
+ res->nstore.comt = l.nstore.comt;
+ res->nstore.fmt = l.nstore.fmt;
+ break;
+ case TLIST:
+ nthelem(l.nstore.u0.sl, r.nstore.u0.sival, res);
+ break;
+ case TSTRING:
+ res->nstore.u0.sival = 0;
+ if(r.nstore.u0.sival >= 0 && r.nstore.u0.sival < l.nstore.u0.sstring->len) {
+ int xx8; /* to get around bug in vc */
+ xx8 = r.nstore.u0.sival;
+ res->nstore.u0.sival = l.nstore.u0.sstring->string[xx8];
+ }
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.fmt = 'c';
+ break;
+ }
+}
+
+void
+oappend(Node *n, Node *res)
+{
+ Node r, l;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ if(l.type != TLIST)
+ error("must append to list");
+ append(res, &l, &r);
+}
+
+void
+odelete(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ if(l.type != TLIST)
+ error("must delete from list");
+ if(r.type != TINT)
+ error("delete index must be integer");
+
+ delete(l.nstore.u0.sl, r.nstore.u0.sival, res);
+}
+
+void
+ohead(Node *n, Node *res)
+{
+ Node l;
+
+ expr(n->left, &l);
+ if(l.type != TLIST)
+ error("head needs list");
+ res->op = OCONST;
+ if(l.nstore.u0.sl) {
+ res->type = l.nstore.u0.sl->type;
+ res->nstore = l.nstore.u0.sl->lstore;
+ }
+ else {
+ res->type = TLIST;
+ res->nstore.u0.sl = 0;
+ }
+}
+
+void
+otail(Node *n, Node *res)
+{
+ Node l;
+
+ expr(n->left, &l);
+ if(l.type != TLIST)
+ error("tail needs list");
+ res->op = OCONST;
+ res->type = TLIST;
+ if(l.nstore.u0.sl)
+ res->nstore.u0.sl = l.nstore.u0.sl->next;
+ else
+ res->nstore.u0.sl = 0;
+}
+
+void
+oconst(Node *n, Node *res)
+{
+ res->op = OCONST;
+ res->type = n->type;
+ res->nstore = n->nstore;
+ res->nstore.comt = n->nstore.comt;
+}
+
+void
+oname(Node *n, Node *res)
+{
+ Value *v;
+
+ v = n->sym->v;
+ if(v->set == 0)
+ error("%s used but not set", n->sym->name);
+ res->op = OCONST;
+ res->type = v->type;
+ res->nstore = v->vstore;
+ res->nstore.comt = v->vstore.comt;
+}
+
+void
+octruct(Node *n, Node *res)
+{
+ res->op = OCONST;
+ res->type = TLIST;
+ res->nstore.u0.sl = construct(n->left);
+}
+
+void
+oasgn(Node *n, Node *res)
+{
+ Node *lp, r;
+ Value *v;
+
+ lp = n->left;
+ switch(lp->op) {
+ case OINDM:
+ windir(cormap, lp->left, n->right, res);
+ break;
+ case OINDC:
+ windir(symmap, lp->left, n->right, res);
+ break;
+ default:
+ chklval(lp);
+ v = lp->sym->v;
+ expr(n->right, &r);
+ v->set = 1;
+ v->type = r.type;
+ v->vstore = r.nstore;
+ res->op = OCONST;
+ res->type = v->type;
+ res->nstore = v->vstore;
+ res->nstore.comt = v->vstore.comt;
+ }
+}
+
+void
+oadd(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TFLOAT;
+ switch(l.type) {
+ default:
+ error("bad lhs type +");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->type = TINT;
+ res->nstore.u0.sival = l.nstore.u0.sival+r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sival+r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type +");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval+r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval+r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type +");
+ }
+ break;
+ case TSTRING:
+ if(r.type == TSTRING) {
+ res->type = TSTRING;
+ res->nstore.fmt = 's';
+ res->nstore.u0.sstring = stradd(l.nstore.u0.sstring, r.nstore.u0.sstring);
+ break;
+ }
+ error("bad rhs for +");
+ case TLIST:
+ res->type = TLIST;
+ switch(r.type) {
+ case TLIST:
+ res->nstore.u0.sl = addlist(l.nstore.u0.sl, r.nstore.u0.sl);
+ break;
+ default:
+ r.left = 0;
+ r.right = 0;
+ res->nstore.u0.sl = addlist(l.nstore.u0.sl, construct(&r));
+ break;
+ }
+ }
+}
+
+void
+osub(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TFLOAT;
+ switch(l.type) {
+ default:
+ error("bad lhs type -");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->type = TINT;
+ res->nstore.u0.sival = l.nstore.u0.sival-r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sival-r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type -");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval-r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval-r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type -");
+ }
+ break;
+ }
+}
+
+void
+omul(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TFLOAT;
+ switch(l.type) {
+ default:
+ error("bad lhs type *");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->type = TINT;
+ res->nstore.u0.sival = l.nstore.u0.sival*r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sival*r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type *");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval*r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval*r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type *");
+ }
+ break;
+ }
+}
+
+void
+odiv(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TFLOAT;
+ switch(l.type) {
+ default:
+ error("bad lhs type /");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->type = TINT;
+ if(r.nstore.u0.sival == 0)
+ error("zero divide");
+ res->nstore.u0.sival = l.nstore.u0.sival/r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ if(r.nstore.u0.sfval == 0)
+ error("zero divide");
+ res->nstore.u0.sfval = l.nstore.u0.sival/r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type /");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval/r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval/r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type /");
+ }
+ break;
+ }
+}
+
+void
+omod(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type %");
+ res->nstore.u0.sival = l.nstore.u0.sival%r.nstore.u0.sival;
+}
+
+void
+olsh(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type <<");
+ res->nstore.u0.sival = l.nstore.u0.sival<<r.nstore.u0.sival;
+}
+
+void
+orsh(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type >>");
+ res->nstore.u0.sival = l.nstore.u0.sival>>r.nstore.u0.sival;
+}
+
+void
+olt(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad lhs type <");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival < r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival < r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type <");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval < r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval < r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type <");
+ }
+ break;
+ }
+}
+
+void
+ogt(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad lhs type >");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival > r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival > r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type >");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval > r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval > r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type >");
+ }
+ break;
+ }
+}
+
+void
+oleq(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad expr type <=");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival <= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival <= r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad expr type <=");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval <= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval <= r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad expr type <=");
+ }
+ break;
+ }
+}
+
+void
+ogeq(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad lhs type >=");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival >= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival >= r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type >=");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval >= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval >= r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type >=");
+ }
+ break;
+ }
+}
+
+void
+oeq(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ switch(l.type) {
+ default:
+ break;
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival == r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival == r.nstore.u0.sfval;
+ break;
+ default:
+ break;
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval == r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval == r.nstore.u0.sfval;
+ break;
+ default:
+ break;
+ }
+ break;
+ case TSTRING:
+ if(r.type == TSTRING) {
+ res->nstore.u0.sival = scmp(r.nstore.u0.sstring, l.nstore.u0.sstring);
+ break;
+ }
+ break;
+ case TLIST:
+ if(r.type == TLIST) {
+ res->nstore.u0.sival = listcmp(l.nstore.u0.sl, r.nstore.u0.sl);
+ break;
+ }
+ break;
+ }
+ if(n->op == ONEQ)
+ res->nstore.u0.sival = !res->nstore.u0.sival;
+}
+
+
+void
+oland(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type &");
+ res->nstore.u0.sival = l.nstore.u0.sival&r.nstore.u0.sival;
+}
+
+void
+oxor(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type ^");
+ res->nstore.u0.sival = l.nstore.u0.sival^r.nstore.u0.sival;
+}
+
+void
+olor(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type |");
+ res->nstore.u0.sival = l.nstore.u0.sival|r.nstore.u0.sival;
+}
+
+void
+ocand(Node *n, Node *res)
+{
+ Node l, r;
+
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ expr(n->left, &l);
+ if(bool(&l) == 0)
+ return;
+ expr(n->right, &r);
+ if(bool(&r) == 0)
+ return;
+ res->nstore.u0.sival = 1;
+}
+
+void
+onot(Node *n, Node *res)
+{
+ Node l;
+
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ expr(n->left, &l);
+ if(bool(&l) == 0)
+ res->nstore.u0.sival = 1;
+}
+
+void
+ocor(Node *n, Node *res)
+{
+ Node l, r;
+
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ expr(n->left, &l);
+ if(bool(&l)) {
+ res->nstore.u0.sival = 1;
+ return;
+ }
+ expr(n->right, &r);
+ if(bool(&r)) {
+ res->nstore.u0.sival = 1;
+ return;
+ }
+}
+
+void
+oeinc(Node *n, Node *res)
+{
+ Value *v;
+
+ chklval(n->left);
+ v = n->left->sym->v;
+ res->op = OCONST;
+ res->type = v->type;
+ switch(v->type) {
+ case TINT:
+ if(n->op == OEDEC)
+ v->vstore.u0.sival -= fmtsize(v);
+ else
+ v->vstore.u0.sival += fmtsize(v);
+ break;
+ case TFLOAT:
+ if(n->op == OEDEC)
+ v->vstore.u0.sfval--;
+ else
+ v->vstore.u0.sfval++;
+ break;
+ default:
+ error("bad type for pre --/++");
+ }
+ res->nstore = v->vstore;
+}
+
+void
+opinc(Node *n, Node *res)
+{
+ Value *v;
+
+ chklval(n->left);
+ v = n->left->sym->v;
+ res->op = OCONST;
+ res->type = v->type;
+ res->nstore = v->vstore;
+ switch(v->type) {
+ case TINT:
+ if(n->op == OPDEC)
+ v->vstore.u0.sival -= fmtsize(v);
+ else
+ v->vstore.u0.sival += fmtsize(v);
+ break;
+ case TFLOAT:
+ if(n->op == OPDEC)
+ v->vstore.u0.sfval--;
+ else
+ v->vstore.u0.sfval++;
+ break;
+ default:
+ error("bad type for post --/++");
+ }
+}
+
+void
+ocall(Node *n, Node *res)
+{
+ Lsym *s;
+ Rplace *rsav;
+
+ res->op = OCONST; /* Default return value */
+ res->type = TLIST;
+ res->nstore.u0.sl = 0;
+
+ chklval(n->left);
+ s = n->left->sym;
+
+ if(s->builtin) {
+ (*s->builtin)(res, n->right);
+ return;
+ }
+ if(s->proc == 0)
+ error("no function %s", s->name);
+
+ rsav = ret;
+ call(s->name, n->right, s->proc->left, s->proc->right, res);
+ ret = rsav;
+}
+
+void
+ofmt(Node *n, Node *res)
+{
+ expr(n->left, res);
+ res->nstore.fmt = n->right->nstore.u0.sival;
+}
+
+void
+owhat(Node *n, Node *res)
+{
+ res->op = OCONST; /* Default return value */
+ res->type = TLIST;
+ res->nstore.u0.sl = 0;
+ whatis(n->sym);
+}
+
+void (*expop[])(Node*, Node*) =
+{
+ oname, /* [ONAME] oname, */
+ oconst, /* [OCONST] oconst, */
+ omul, /* [OMUL] omul, */
+ odiv, /* [ODIV] odiv, */
+ omod, /* [OMOD] omod, */
+ oadd, /* [OADD] oadd, */
+ osub, /* [OSUB] osub, */
+ orsh, /* [ORSH] orsh, */
+ olsh, /* [OLSH] olsh, */
+ olt, /* [OLT] olt, */
+ ogt, /* [OGT] ogt, */
+ oleq, /* [OLEQ] oleq, */
+ ogeq, /* [OGEQ] ogeq, */
+ oeq, /* [OEQ] oeq, */
+ oeq, /* [ONEQ] oeq, */
+ oland, /* [OLAND] oland, */
+ oxor, /* [OXOR] oxor, */
+ olor, /* [OLOR] olor, */
+ ocand, /* [OCAND] ocand, */
+ ocor, /* [OCOR] ocor, */
+ oasgn, /* [OASGN] oasgn, */
+ oindm, /* [OINDM] oindm, */
+ oeinc, /* [OEDEC] oeinc, */
+ oeinc, /* [OEINC] oeinc, */
+ opinc, /* [OPINC] opinc, */
+ opinc, /* [OPDEC] opinc, */
+ onot, /* [ONOT] onot, */
+ 0, /* [OIF] 0, */
+ 0, /* [ODO] 0, */
+ olist, /* [OLIST] olist, */
+ ocall, /* [OCALL] ocall, */
+ octruct, /* [OCTRUCT] octruct, */
+ 0, /* [OWHILE] 0, */
+ 0, /* [OELSE] 0, */
+ ohead, /* [OHEAD] ohead, */
+ otail, /* [OTAIL] otail, */
+ oappend, /* [OAPPEND] oappend, */
+ 0, /* [ORET] 0, */
+ oindex, /* [OINDEX] oindex, */
+ oindc, /* [OINDC] oindc, */
+ odot, /* [ODOT] odot, */
+ 0, /* [OLOCAL] 0, */
+ oframe, /* [OFRAME] oframe, */
+ 0, /* [OCOMPLEX] 0, */
+ odelete, /* [ODELETE] odelete, */
+ ocast, /* [OCAST] ocast, */
+ ofmt, /* [OFMT] ofmt, */
+ oeval, /* [OEVAL] oeval, */
+ owhat, /* [OWHAT] owhat, */
+};
diff --git a/utils/acid/lex.c b/utils/acid/lex.c
new file mode 100644
index 00000000..364bcae9
--- /dev/null
+++ b/utils/acid/lex.c
@@ -0,0 +1,636 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+struct keywd
+{
+ char *name;
+ int terminal;
+}
+keywds[] =
+{
+ "do", Tdo,
+ "if", Tif,
+ "then", Tthen,
+ "else", Telse,
+ "while", Twhile,
+ "loop", Tloop,
+ "head", Thead,
+ "tail", Ttail,
+ "append", Tappend,
+ "defn", Tfn,
+ "return", Tret,
+ "local", Tlocal,
+ "aggr", Tcomplex,
+ "union", Tcomplex,
+ "adt", Tcomplex,
+ "complex", Tcomplex,
+ "delete", Tdelete,
+ "whatis", Twhat,
+ "eval", Teval,
+ 0, 0
+};
+
+char cmap[256] =
+{
+ 0,0,0,0,0,0,0,0, /* 0-7 */
+ 0,0,0,0,0,0,0,0, /* 8-15 */
+ 0,0,0,0,0,0,0,0, /* 16-23 */
+ 0,0,0,0,0,0,0,0, /* 24-31 */
+ 0,0, /* 32-33 */
+ '"'+1, /* 34 ['"'] '"'+1, */
+ 0,0,0,0,0, /* 35-39 */
+ 0,0,0,0,0,0,0,0, /* 40-47 */
+ '\0'+1, /* 48 ['0'] '\0'+1, */
+ 0,0,0,0,0,0,0, /* 49-55 */
+ 0,0,0,0,0,0,0,0, /* 56-63 */
+ 0,0,0,0,0,0,0,0, /* 64-71 */
+ 0,0,0,0,0,0,0,0, /* 72-79 */
+ 0,0,0,0,0,0,0,0, /* 80-87 */
+ 0,0,0,0, /* 88-91 */
+ '\\'+1, /* 92 ['\\'] '\\'+1, */
+ 0,0,0,0, /* 93-96 */
+ '\a'+1, /* 97 ['a'] '\a'+1, */
+ '\b'+1, /* 98 ['b'] '\b'+1, */
+ 0,0,0, /* 99-101 */
+ '\f'+1, /* 102 ['f'] '\f'+1, */
+ 0,0,0,0,0,0,0, /* 103-109 */
+ '\n'+1, /* 110 ['n'] '\n'+1, */
+ 0,0,0, /* 111-113 */
+ '\r'+1, /* 114 ['r'] '\r'+1, */
+ 0, /* 115 */
+ '\t'+1, /* 116 ['t'] '\t'+1, */
+ 0, /* 117 */
+ '\v'+1, /* 118 ['v'] '\v'+1, */
+};
+
+void
+kinit(void)
+{
+ int i;
+
+ for(i = 0; keywds[i].name; i++)
+ enter(keywds[i].name, keywds[i].terminal);
+}
+
+typedef struct IOstack IOstack;
+struct IOstack
+{
+ char *name;
+ int line;
+ char *text;
+ char *ip;
+ Biobuf *fin;
+ IOstack *prev;
+};
+IOstack *lexio;
+
+void
+pushfile(char *file)
+{
+ Biobuf *b;
+ IOstack *io;
+ char buf[512];
+ extern char *acidlib;
+
+ if(file){
+ b = Bopen(file, OREAD);
+ if(b == nil && strchr(file, '/') == 0){
+ snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, file);
+ b = Bopen(buf, OREAD);
+ }
+ }
+ else{
+ b = gmalloc(sizeof(Biobuf));
+ if (Binit(b, 0, OREAD) == Beof) {
+ free(b);
+ b = 0;
+ }
+ file = "<stdin>";
+ }
+
+ if(b == 0)
+ error("pushfile: %s: %r", file);
+
+ io = gmalloc(sizeof(IOstack));
+ if(io == 0)
+ fatal("no memory");
+ io->name = strdup(file);
+ if(io->name == 0)
+ fatal("no memory");
+ io->line = line;
+ line = 1;
+ io->text = 0;
+ io->fin = b;
+ io->prev = lexio;
+ lexio = io;
+}
+
+void
+pushstr(Node *s)
+{
+ IOstack *io;
+
+ io = gmalloc(sizeof(IOstack));
+ if(io == 0)
+ fatal("no memory");
+ io->line = line;
+ line = 1;
+ io->name = strdup("<string>");
+ if(io->name == 0)
+ fatal("no memory");
+ io->line = line;
+ line = 1;
+ io->text = strdup(s->nstore.u0.sstring->string);
+ if(io->text == 0)
+ fatal("no memory");
+ io->ip = io->text;
+ io->fin = 0;
+ io->prev = lexio;
+ lexio = io;
+}
+
+void
+restartio(void)
+{
+ Bflush(lexio->fin);
+ Binit(lexio->fin, 0, OREAD);
+}
+
+int
+popio(void)
+{
+ IOstack *s;
+
+ if(lexio == 0)
+ return 0;
+
+ if(lexio->prev == 0){
+ if(lexio->fin)
+ restartio();
+ return 0;
+ }
+
+ if(lexio->fin)
+ Bterm(lexio->fin);
+ else
+ free(lexio->text);
+ free(lexio->name);
+ line = lexio->line;
+ s = lexio;
+ lexio = s->prev;
+ free(s);
+ return 1;
+}
+
+int
+Lfmt(Fmt *f)
+{
+ int i;
+ char buf[1024];
+ IOstack *e;
+
+ e = lexio;
+ if(e) {
+ i = sprint(buf, "%s:%d", e->name, line);
+ while(e->prev) {
+ e = e->prev;
+ if(initialising && e->prev == 0)
+ break;
+ i += sprint(buf+i, " [%s:%d]", e->name, e->line);
+ }
+ } else
+ sprint(buf, "no file:0");
+ return fmtstrcpy(f, buf);
+}
+
+void
+unlexc(int s)
+{
+ if(s == '\n')
+ line--;
+
+ if(lexio->fin)
+ Bungetc(lexio->fin);
+ else
+ lexio->ip--;
+}
+
+int
+lexc(void)
+{
+ int c;
+
+ if(lexio->fin) {
+ c = Bgetc(lexio->fin);
+ if(gotint)
+ error("interrupt");
+ return c;
+ }
+
+ c = *lexio->ip++;
+ if(c == 0)
+ return -1;
+ return c;
+}
+
+int
+escchar(char c)
+{
+ int n;
+ char buf[Strsize];
+
+ if(c >= '0' && c <= '9') {
+ n = 1;
+ buf[0] = c;
+ for(;;) {
+ c = lexc();
+ if(c == Eof)
+ error("%d: <eof> in escape sequence", line);
+ if(strchr("0123456789xX", c) == 0) {
+ unlexc(c);
+ break;
+ }
+ buf[n++] = c;
+ }
+ buf[n] = '\0';
+ return strtol(buf, 0, 0);
+ }
+
+ n = cmap[c];
+ if(n == 0)
+ return c;
+ return n-1;
+}
+
+void
+eatstring(void)
+{
+ int esc, c, cnt;
+ char buf[Strsize];
+
+ esc = 0;
+ for(cnt = 0;;) {
+ c = lexc();
+ switch(c) {
+ case Eof:
+ error("%d: <eof> in string constant", line);
+
+ case '\r':
+ case '\n':
+ error("newline in string constant");
+ goto done;
+
+ case '\\':
+ if(esc)
+ goto Default;
+ esc = 1;
+ break;
+
+ case '"':
+ if(esc == 0)
+ goto done;
+
+ /* Fall through */
+ default:
+ Default:
+ if(esc) {
+ c = escchar(c);
+ esc = 0;
+ }
+ buf[cnt++] = c;
+ break;
+ }
+ if(cnt >= Strsize)
+ error("string token too long");
+ }
+done:
+ buf[cnt] = '\0';
+ yylval.string = strnode(buf);
+}
+
+void
+eatnl(void)
+{
+ int c;
+
+ line++;
+ for(;;) {
+ c = lexc();
+ if(c == Eof)
+ error("eof in comment");
+ if(c == '\n')
+ return;
+ }
+}
+
+int
+yylex(void)
+{
+ int c;
+ extern char vfmt[];
+
+loop:
+ Bflush(bout);
+ c = lexc();
+ switch(c) {
+ case Eof:
+ if(gotint) {
+ gotint = 0;
+ stacked = 0;
+ Bprint(bout, "\nacid: ");
+ goto loop;
+ }
+ return Eof;
+
+ case '"':
+ eatstring();
+ return Tstring;
+
+ case ' ':
+ case '\r':
+ case '\t':
+ goto loop;
+
+ case '\n':
+ line++;
+ if(interactive == 0)
+ goto loop;
+ if(stacked) {
+ print("\t");
+ goto loop;
+ }
+ return ';';
+
+ case '.':
+ c = lexc();
+ unlexc(c);
+ if(isdigit(c))
+ return numsym('.');
+
+ return '.';
+
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case ';':
+ case ':':
+ case ',':
+ case '~':
+ case '?':
+ case '*':
+ case '@':
+ case '^':
+ case '%':
+ return c;
+ case '{':
+ stacked++;
+ return c;
+ case '}':
+ stacked--;
+ return c;
+
+ case '\\':
+ c = lexc();
+ if(strchr(vfmt, c) == 0) {
+ unlexc(c);
+ return '\\';
+ }
+ yylval.ival = c;
+ return Tfmt;
+
+ case '!':
+ c = lexc();
+ if(c == '=')
+ return Tneq;
+ unlexc(c);
+ return '!';
+
+ case '+':
+ c = lexc();
+ if(c == '+')
+ return Tinc;
+ unlexc(c);
+ return '+';
+
+ case '/':
+ c = lexc();
+ if(c == '/') {
+ eatnl();
+ goto loop;
+ }
+ unlexc(c);
+ return '/';
+
+ case '\'':
+ c = lexc();
+ if(c == '\\')
+ yylval.ival = escchar(lexc());
+ else
+ yylval.ival = c;
+ c = lexc();
+ if(c != '\'') {
+ error("missing '");
+ unlexc(c);
+ }
+ return Tconst;
+
+ case '&':
+ c = lexc();
+ if(c == '&')
+ return Tandand;
+ unlexc(c);
+ return '&';
+
+ case '=':
+ c = lexc();
+ if(c == '=')
+ return Teq;
+ unlexc(c);
+ return '=';
+
+ case '|':
+ c = lexc();
+ if(c == '|')
+ return Toror;
+ unlexc(c);
+ return '|';
+
+ case '<':
+ c = lexc();
+ if(c == '=')
+ return Tleq;
+ if(c == '<')
+ return Tlsh;
+ unlexc(c);
+ return '<';
+
+ case '>':
+ c = lexc();
+ if(c == '=')
+ return Tgeq;
+ if(c == '>')
+ return Trsh;
+ unlexc(c);
+ return '>';
+
+ case '-':
+ c = lexc();
+
+ if(c == '>')
+ return Tindir;
+
+ if(c == '-')
+ return Tdec;
+ unlexc(c);
+ return '-';
+
+ default:
+ return numsym(c);
+ }
+}
+
+int
+numsym(char first)
+{
+ int c, isbin, isfloat, ishex;
+ char *sel, *p;
+ Lsym *s;
+
+ symbol[0] = first;
+ p = symbol;
+
+ ishex = 0;
+ isbin = 0;
+ isfloat = 0;
+ if(first == '.')
+ isfloat = 1;
+
+ if(isdigit(*p++) || isfloat) {
+ for(;;) {
+ c = lexc();
+ if(c < 0)
+ error("%d: <eof> eating symbols", line);
+
+ if(c == '\r')
+ continue;
+ if(c == '\n')
+ line++;
+ sel = "01234567890.xb";
+ if(ishex)
+ sel = "01234567890abcdefABCDEF";
+ else if(isbin)
+ sel = "01";
+ else if(isfloat)
+ sel = "01234567890eE-+";
+
+ if(strchr(sel, c) == 0) {
+ unlexc(c);
+ break;
+ }
+ if(c == '.')
+ isfloat = 1;
+ if(!isbin && c == 'x')
+ ishex = 1;
+ if(!ishex && c == 'b')
+ isbin = 1;
+ *p++ = c;
+ }
+ *p = '\0';
+ if(isfloat) {
+ yylval.fval = atof(symbol);
+ return Tfconst;
+ }
+
+ if(isbin)
+ yylval.ival = strtoul(symbol+2, 0, 2);
+ else
+ yylval.ival = strtoul(symbol, 0, 0);
+ return Tconst;
+ }
+
+ for(;;) {
+ c = lexc();
+ if(c < 0)
+ error("%d <eof> eating symbols", line);
+ if(c == '\n')
+ line++;
+ if(c != '_' && c != '$' && c <= '~' && !isalnum(c)) { /* checking against ~ lets UTF names through */
+ unlexc(c);
+ break;
+ }
+ *p++ = c;
+ }
+
+ *p = '\0';
+
+ s = look(symbol);
+ if(s == 0)
+ s = enter(symbol, Tid);
+
+ yylval.sym = s;
+ return s->lexval;
+}
+
+Lsym*
+enter(char *name, int t)
+{
+ Lsym *s;
+ ulong h;
+ char *p;
+ Value *v;
+
+ h = 0;
+ for(p = name; *p; p++)
+ h = h*3 + *p;
+ h %= Hashsize;
+
+ s = gmalloc(sizeof(Lsym));
+ s->name = strdup(name);
+
+ s->hash = hash[h];
+ hash[h] = s;
+ s->lexval = t;
+
+ v = gmalloc(sizeof(Value));
+ s->v = v;
+
+ v->vstore.fmt = 'X';
+ v->type = TINT;
+
+ return s;
+}
+
+Lsym*
+look(char *name)
+{
+ Lsym *s;
+ ulong h;
+ char *p;
+
+ h = 0;
+ for(p = name; *p; p++)
+ h = h*3 + *p;
+ h %= Hashsize;
+
+ for(s = hash[h]; s; s = s->hash)
+ if(strcmp(name, s->name) == 0)
+ return s;
+ return 0;
+}
+
+Lsym*
+mkvar(char *s)
+{
+ Lsym *l;
+
+ l = look(s);
+ if(l == 0)
+ l = enter(s, Tid);
+ return l;
+}
diff --git a/utils/acid/list.c b/utils/acid/list.c
new file mode 100644
index 00000000..ced2f4d8
--- /dev/null
+++ b/utils/acid/list.c
@@ -0,0 +1,276 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+static List **tail;
+
+List*
+construct(Node *l)
+{
+ List *lh, **save;
+
+ save = tail;
+ lh = 0;
+ tail = &lh;
+ build(l);
+ tail = save;
+
+ return lh;
+}
+
+int
+listlen(List *l)
+{
+ int len;
+
+ len = 0;
+ while(l) {
+ len++;
+ l = l->next;
+ }
+ return len;
+}
+
+void
+build(Node *n)
+{
+ List *l;
+ Node res;
+
+ if(n == 0)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ build(n->left);
+ build(n->right);
+ return;
+ default:
+ expr(n, &res);
+ l = al(res.type);
+ l->lstore = res.nstore;
+ *tail = l;
+ tail = &l->next;
+ }
+}
+
+List*
+addlist(List *l, List *r)
+{
+ List *f;
+
+ if(l == 0)
+ return r;
+
+ for(f = l; f->next; f = f->next)
+ ;
+ f->next = r;
+
+ return l;
+}
+
+void
+append(Node *r, Node *list, Node *val)
+{
+ List *l, *f;
+
+ l = al(val->type);
+ l->lstore = val->nstore;
+ l->next = 0;
+
+ r->op = OCONST;
+ r->type = TLIST;
+
+ if(list->nstore.u0.sl == 0) {
+ list->nstore.u0.sl = l;
+ r->nstore.u0.sl = l;
+ return;
+ }
+ for(f = list->nstore.u0.sl; f->next; f = f->next)
+ ;
+ f->next = l;
+ r->nstore.u0.sl = list->nstore.u0.sl;
+}
+
+int
+listcmp(List *l, List *r)
+{
+ if(l == r)
+ return 1;
+
+ while(l) {
+ if(r == 0)
+ return 0;
+ if(l->type != r->type)
+ return 0;
+ switch(l->type) {
+ case TINT:
+ if(l->lstore.u0.sival != r->lstore.u0.sival)
+ return 0;
+ break;
+ case TFLOAT:
+ if(l->lstore.u0.sfval != r->lstore.u0.sfval)
+ return 0;
+ break;
+ case TSTRING:
+ if(scmp(l->lstore.u0.sstring, r->lstore.u0.sstring) == 0)
+ return 0;
+ break;
+ case TLIST:
+ if(listcmp(l->lstore.u0.sl, r->lstore.u0.sl) == 0)
+ return 0;
+ break;
+ }
+ l = l->next;
+ r = r->next;
+ }
+ if(l != r)
+ return 0;
+ return 1;
+}
+
+void
+nthelem(List *l, int n, Node *res)
+{
+ if(n < 0)
+ error("negative index in []");
+
+ while(l && n--)
+ l = l->next;
+
+ res->op = OCONST;
+ if(l == 0) {
+ res->type = TLIST;
+ res->nstore.u0.sl = 0;
+ return;
+ }
+ res->type = l->type;
+ res->nstore = l->lstore;
+}
+
+void
+delete(List *l, int n, Node *res)
+{
+ List **tl;
+
+ if(n < 0)
+ error("negative index in delete");
+
+ res->op = OCONST;
+ res->type = TLIST;
+ res->nstore.u0.sl = l;
+
+ for(tl = &res->nstore.u0.sl; l && n--; l = l->next)
+ tl = &l->next;
+
+ if(l == 0)
+ error("element beyond end of list");
+ *tl = l->next;
+}
+
+List*
+listvar(char *s, long v)
+{
+ List *l, *tl;
+
+ tl = al(TLIST);
+
+ l = al(TSTRING);
+ tl->lstore.u0.sl = l;
+ l->lstore.fmt = 's';
+ l->lstore.u0.sstring = strnode(s);
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.fmt = 'X';
+ l->lstore.u0.sival = v;
+
+ return tl;
+}
+
+static List*
+listlocals(Map *map, Symbol *fn, ulong fp)
+{
+ int i;
+ long val;
+ Symbol s;
+ List **tail, *l2;
+
+ l2 = 0;
+ tail = &l2;
+ s = *fn;
+
+ for(i = 0; localsym(&s, i); i++) {
+ if(s.class != CAUTO)
+ continue;
+ if(s.name[0] == '.')
+ continue;
+
+ if(get4(map, fp-s.value, &val) > 0) {
+ *tail = listvar(s.name, val);
+ tail = &(*tail)->next;
+ }
+ }
+ return l2;
+}
+
+static List*
+listparams(Map *map, Symbol *fn, ulong fp)
+{
+ int i;
+ Symbol s;
+ long v;
+ List **tail, *l2;
+
+ l2 = 0;
+ tail = &l2;
+ fp += mach->szaddr; /* skip saved pc */
+ s = *fn;
+ for(i = 0; localsym(&s, i); i++) {
+ if (s.class != CPARAM)
+ continue;
+
+ if(get4(map, fp+s.value, &v) > 0) {
+ *tail = listvar(s.name, v);
+ tail = &(*tail)->next;
+ }
+ }
+ return l2;
+}
+
+void
+trlist(Map *map, ulong pc, ulong sp, Symbol *sym)
+{
+ List *q, *l;
+
+ static List **tail;
+
+ if (tracelist == 0) { /* first time */
+ tracelist = al(TLIST);
+ tail = &tracelist;
+ }
+
+ q = al(TLIST);
+ *tail = q;
+ tail = &q->next;
+
+ l = al(TINT); /* Function address */
+ q->lstore.u0.sl = l;
+ l->lstore.u0.sival = sym->value;
+ l->lstore.fmt = 'X';
+
+ l->next = al(TINT); /* called from address */
+ l = l->next;
+ l->lstore.u0.sival = pc;
+ l->lstore.fmt = 'X';
+
+ l->next = al(TLIST); /* make list of params */
+ l = l->next;
+ l->lstore.u0.sl = listparams(map, sym, sp);
+
+ l->next = al(TLIST); /* make list of locals */
+ l = l->next;
+ l->lstore.u0.sl = listlocals(map, sym, sp);
+}
diff --git a/utils/acid/main.c b/utils/acid/main.c
new file mode 100644
index 00000000..5bd85f13
--- /dev/null
+++ b/utils/acid/main.c
@@ -0,0 +1,616 @@
+/*#include <u.h>*/
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+#define Extern
+#include "acid.h"
+#include "y.tab.h"
+
+char *argv0;
+char *acidlib;
+static Biobuf bioout;
+static char prog[128];
+static char* lm[16];
+static int nlm;
+static char* mtype;
+
+static int attachfiles(char*, int);
+int xfmt(Fmt*);
+extern int gfltconv(Fmt*), _ifmt(Fmt*);
+int isnumeric(char*);
+void die(void);
+
+void
+usage(void)
+{
+ fprint(2, "usage: acid [-l module] [-m machine] [-qrw] [-k] [-d flag] [-R tty] [pid] [file]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Dir *db;
+ Lsym *l;
+ Node *n;
+ char buf[128], *s;
+ int pid, i;
+ char *p;
+ char afile[512];
+
+ argv0 = argv[0];
+ pid = 0;
+ aout = "v.out";
+ quiet = 1;
+ /* turn off all debugging */
+ protodebug = 0;
+
+ mtype = 0;
+ ARGBEGIN{
+ case 'm':
+ mtype = ARGF();
+ break;
+ case 'w':
+ wtflag = 1;
+ break;
+ case 'l':
+ s = ARGF();
+ if(s == 0)
+ usage();
+ lm[nlm++] = s;
+ break;
+ case 'd':
+ p = ARGF();
+ if (p == 0)
+ usage();
+ while (*p) {
+ setdbg_opt(*p, 0); /* don't print set message */
+ p++;
+ }
+ break;
+ case 'k':
+ kernel++;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case 'r':
+ pid = 1;
+ remote++;
+ kernel++;
+ break;
+ case 'R':
+ pid = 1;
+ rdebug++;
+ s = ARGF();
+ if(s == 0)
+ usage();
+ remfd = opentty(s, 0);
+ if(remfd < 0){
+ fprint(2, "acid: can't open %s: %r\n", s);
+ exits("open");
+ }
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0) {
+ if(remote || rdebug)
+ aout = argv[0];
+ else
+ if(isnumeric(argv[0])) {
+ pid = atoi(argv[0]);
+ sprint(prog, "/proc/%d/text", pid);
+ aout = prog;
+ if(argc > 1)
+ aout = argv[1];
+ else if(kernel)
+ aout = mysystem();
+ }
+ else {
+ if(kernel) {
+ print("-k requires a pid");
+ kernel = 0;
+ }
+ aout = argv[0];
+ }
+ } else if(rdebug)
+ aout = "/386/bpc";
+ else if(remote)
+ aout = "/mips/bcarrera";
+
+ fmtinstall('x', xfmt);
+ fmtinstall('L', Lfmt);
+ fmtinstall('f', gfltconv);
+ fmtinstall('F', gfltconv);
+ fmtinstall('g', gfltconv);
+ fmtinstall('G', gfltconv);
+ fmtinstall('e', gfltconv);
+ fmtinstall('E', gfltconv);
+ Binit(&bioout, 1, OWRITE);
+ bout = &bioout;
+
+ kinit();
+ initialising = 1;
+ pushfile(0);
+ loadvars();
+ installbuiltin();
+
+ if(mtype && machbyname(mtype) == 0)
+ print("unknown machine %s", mtype);
+
+ if (attachfiles(aout, pid) < 0)
+ varreg(); /* use default register set on error */
+
+ acidlib = getenv("ACIDLIB");
+ if(acidlib == nil){
+ p = getenv("ROOT");
+ if(p == nil)
+ p = "/usr/inferno";
+ snprint(afile, sizeof(afile)-1, "%s/lib/acid", p);
+ acidlib = strdup(afile);
+ }
+
+ snprint(afile, sizeof(afile)-1, "%s/port", acidlib);
+ loadmodule(afile);
+ for(i = 0; i < nlm; i++) {
+ if((db = dirstat(lm[i])) != nil) {
+ free(db);
+ loadmodule(lm[i]);
+ } else {
+ sprint(buf, "%s/%s", acidlib, lm[i]);
+ loadmodule(buf);
+ }
+ }
+
+ userinit();
+ varsym();
+
+ l = look("acidmap");
+ if(l && l->proc) {
+ n = an(ONAME, ZN, ZN);
+ n->sym = l;
+ n = an(OCALL, n, ZN);
+ execute(n);
+ }
+
+ interactive = 1;
+ initialising = 0;
+ line = 1;
+
+ setup_os_notify();
+
+ for(;;) {
+ if(setjmp(err)) {
+ Binit(&bioout, 1, OWRITE);
+ unwind();
+ }
+ stacked = 0;
+
+ Bprint(bout, "acid: ");
+
+ if(yyparse() != 1)
+ die();
+ restartio();
+
+ unwind();
+ }
+ Bputc(bout, '\n');
+ exits(0);
+}
+
+static int
+attachfiles(char *aout, int pid)
+{
+ interactive = 0;
+ if(setjmp(err))
+ return -1;
+
+ if(aout) { /* executable given */
+ if(wtflag)
+ text = open(aout, ORDWR);
+ else
+ text = open(aout, OREAD);
+
+ if(text < 0)
+ error("%s: can't open %s: %r\n", argv0, aout);
+ readtext(aout);
+ }
+ if(pid) /* pid given */
+ sproc(pid);
+ return 0;
+}
+
+void
+die(void)
+{
+ Lsym *s;
+ List *f;
+
+ Bprint(bout, "\n");
+
+ s = look("proclist");
+ if(!rdebug && s && s->v->type == TLIST) {
+ for(f = s->v->vstore.u0.sl; f; f = f->next)
+ Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->lstore.u0.sival);
+ }
+ exits(0);
+}
+
+void
+userinit(void)
+{
+ Lsym *l;
+ Node *n;
+ char buf[512], *p;
+
+
+ p = getenv("home");
+ if(p == 0)
+ p = getenv("HOME");
+ if(p != 0) {
+ snprint(buf, sizeof(buf)-1, "%s/lib/acid", p);
+ silent = 1;
+ loadmodule(buf);
+ }
+
+ if(rdebug){
+ snprint(buf, sizeof(buf)-1, "%s/rdebug", acidlib);
+ loadmodule(buf);
+ }
+
+ snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, mach->name);
+ loadmodule(buf);
+
+ interactive = 0;
+ if(setjmp(err)) {
+ unwind();
+ return;
+ }
+ l = look("acidinit");
+ if(l && l->proc) {
+ n = an(ONAME, ZN, ZN);
+ n->sym = l;
+ n = an(OCALL, n, ZN);
+ execute(n);
+ }
+}
+
+void
+loadmodule(char *s)
+{
+ interactive = 0;
+ if(setjmp(err)) {
+ unwind();
+ return;
+ }
+ pushfile(s);
+ silent = 0;
+ yyparse();
+ popio();
+ return;
+}
+
+void
+readtext(char *s)
+{
+ Dir *d;
+ Lsym *l;
+ Value *v;
+ Symbol sym;
+ ulong length;
+ extern Machdata mipsmach;
+
+ if(mtype != 0){
+ symmap = newmap(0, 1);
+ if(symmap == 0)
+ print("%s: (error) loadmap: cannot make symbol map\n", argv0);
+ length = 1<<24;
+ d = dirfstat(text);
+ if(d != nil) {
+ length = d->length;
+ free(d);
+ }
+ setmap(symmap, text, 0, length, 0, "binary");
+ free(d);
+ return;
+ }
+
+ machdata = &mipsmach;
+
+ if(!crackhdr(text, &fhdr)) {
+ print("can't decode file header\n");
+ return;
+ }
+
+ symmap = loadmap(0, text, &fhdr);
+ if(symmap == 0)
+ print("%s: (error) loadmap: cannot make symbol map\n", argv0);
+
+ if(syminit(text, &fhdr) < 0) {
+ print("%s: (error) syminit: %r\n", argv0);
+ return;
+ }
+ print("%s:%s\n\n", s, fhdr.name);
+
+ if(mach->sbreg && lookup(0, mach->sbreg, &sym)) {
+ mach->sb = sym.value;
+ l = enter("SB", Tid);
+ l->v->vstore.fmt = 'X';
+ l->v->vstore.u0.sival = mach->sb;
+ l->v->type = TINT;
+ l->v->set = 1;
+ }
+
+ l = mkvar("objtype");
+ v = l->v;
+ v->vstore.fmt = 's';
+ v->set = 1;
+ v->vstore.u0.sstring = strnode(mach->name);
+ v->type = TSTRING;
+
+ l = mkvar("textfile");
+ v = l->v;
+ v->vstore.fmt = 's';
+ v->set = 1;
+ v->vstore.u0.sstring = strnode(s);
+ v->type = TSTRING;
+
+ machbytype(fhdr.type);
+ varreg();
+}
+
+Node*
+an(int op, Node *l, Node *r)
+{
+ Node *n;
+
+ n = gmalloc(sizeof(Node));
+ n->ngc.gclink = gcl;
+ gcl = &n->ngc;
+ n->op = op;
+ n->left = l;
+ n->right = r;
+ return n;
+}
+
+List*
+al(int t)
+{
+ List *l;
+
+ l = gmalloc(sizeof(List));
+ l->type = t;
+ l->lgc.gclink = gcl;
+ gcl = &l->lgc;
+ return l;
+}
+
+Node*
+con(int v)
+{
+ Node *n;
+
+ n = an(OCONST, ZN, ZN);
+ n->nstore.u0.sival = v;
+ n->nstore.fmt = 'X';
+ n->type = TINT;
+ return n;
+}
+
+void
+fatal(char *fmt, ...)
+{
+ char buf[128];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s: %L (fatal problem) %s\n", argv0, buf);
+ exits(buf);
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[128];
+ va_list arg;
+
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, near symbol '%s'", symbol);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%L: %s\n", buf);
+}
+
+void
+marktree(Node *n)
+{
+
+ if(n == 0)
+ return;
+
+ marktree(n->left);
+ marktree(n->right);
+
+ n->ngc.gcmark = 1;
+ if(n->op != OCONST)
+ return;
+
+ switch(n->type) {
+ case TSTRING:
+ n->nstore.u0.sstring->sgc.gcmark = 1;
+ break;
+ case TLIST:
+ marklist(n->nstore.u0.sl);
+ break;
+ case TCODE:
+ marktree(n->nstore.u0.scc);
+ break;
+ }
+}
+
+void
+marklist(List *l)
+{
+ while(l) {
+ l->lgc.gcmark = 1;
+ switch(l->type) {
+ case TSTRING:
+ l->lstore.u0.sstring->sgc.gcmark = 1;
+ break;
+ case TLIST:
+ marklist(l->lstore.u0.sl);
+ break;
+ case TCODE:
+ marktree(l->lstore.u0.scc);
+ break;
+ }
+ l = l->next;
+ }
+}
+
+void
+gc(void)
+{
+ int i;
+ Lsym *f;
+ Value *v;
+ Gc *m, **p, *next;
+
+ if(dogc < Mempergc)
+ return;
+ dogc = 0;
+
+ /* Mark */
+ for(m = gcl; m; m = m->gclink)
+ m->gcmark = 0;
+
+ /* Scan */
+ for(i = 0; i < Hashsize; i++) {
+ for(f = hash[i]; f; f = f->hash) {
+ marktree(f->proc);
+ if(f->lexval != Tid)
+ continue;
+ for(v = f->v; v; v = v->pop) {
+ switch(v->type) {
+ case TSTRING:
+ v->vstore.u0.sstring->sgc.gcmark = 1;
+ break;
+ case TLIST:
+ marklist(v->vstore.u0.sl);
+ break;
+ case TCODE:
+ marktree(v->vstore.u0.scc);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Free */
+ p = &gcl;
+ for(m = gcl; m; m = next) {
+ next = m->gclink;
+ if(m->gcmark == 0) {
+ *p = next;
+ free(m); /* Sleazy reliance on my malloc */
+ }
+ else
+ p = &m->gclink;
+ }
+}
+
+void*
+gmalloc(long l)
+{
+ void *p;
+
+ dogc += l;
+ p = malloc(l);
+ if(p == 0)
+ fatal("out of memory");
+ memset(p, 0, l);
+ return p;
+}
+
+void
+checkqid(int f1, int pid)
+{
+ int fd;
+ Dir *d1, *d2;
+ char buf[128];
+
+ if(kernel || rdebug)
+ return;
+
+ d1 = dirfstat(f1);
+ if(d1 == nil)
+ fatal("checkqid: (qid not checked) dirfstat: %r");
+
+ sprint(buf, "/proc/%d/text", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0 || (d2 = dirfstat(fd)) == nil){
+ fatal("checkqid: (qid not checked) dirstat %s: %r", buf);
+ return; /* not reached */
+ }
+
+ close(fd);
+
+ if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){
+ print("path %llux %llux vers %lud %lud type %d %d\n",
+ d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);
+ print("warning: image does not match text for pid %d\n", pid);
+ }
+ free(d1);
+ free(d2);
+}
+
+char*
+mysystem(void)
+{
+ char *cpu, *p, *q;
+ static char kernel[128];
+
+ cpu = getenv("cputype");
+ if(cpu == 0) {
+ cpu = "mips";
+ print("$cputype not set; assuming %s\n", cpu);
+ }
+ p = getenv("terminal");
+ if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {
+ p = "9power";
+ print("missing or bad $terminal; assuming %s\n", p);
+ }
+ else{
+ p++;
+ q = strchr(p, ' ');
+ if(q)
+ *q = 0;
+ sprint(kernel, "/%s/b%s", cpu, p);
+ }
+ return kernel;
+}
+
+int
+isnumeric(char *s)
+{
+ while(*s) {
+ if(*s < '0' || *s > '9')
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+int
+xfmt(Fmt *f)
+{
+ f->flags ^= FmtSharp;
+ return _ifmt(f);
+}
diff --git a/utils/acid/mips b/utils/acid/mips
new file mode 100644
index 00000000..5c267d1f
--- /dev/null
+++ b/utils/acid/mips
@@ -0,0 +1,217 @@
+// Mips support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'X';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/mips/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n");
+ print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n");
+ print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n");
+ print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n");
+ print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n");
+ print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n");
+ print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n");
+ print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n");
+ print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n");
+ print("R28\t", *R28, " R29\t", *SP, " R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn Fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n");
+ print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n");
+ print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n");
+ print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n");
+ print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n");
+ print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+ print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+ print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+ print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+ print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+ print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+ print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+ print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+ print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+ print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+ print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc, link, cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ link = *R31;
+ print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " ");
+ pfl(link);
+
+ cause = *CAUSE;
+ print("STATUS\t", *STATUS, "\tCAUSE\t", cause, " ", reason(cause), "\n");
+ print("TLBVIR\t", *TLBVIRT, "\tBADVADR\t", *BADVADDR, "\n");
+
+ print("HI\t", *HI, "\tLO\t", *LO, "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l, pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*CAUSE), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+sizeofUreg = 152;
+aggr Ureg
+{
+ 'X' 0 status;
+ 'X' 4 pc;
+ {
+ 'X' 8 sp;
+ 'X' 8 usp;
+ };
+ 'X' 12 cause;
+ 'X' 16 badvaddr;
+ 'X' 20 tlbvirt;
+ 'X' 24 hi;
+ 'X' 28 lo;
+ 'X' 32 r31;
+ 'X' 36 r30;
+ 'X' 40 r28;
+ 'X' 44 r27;
+ 'X' 48 r26;
+ 'X' 52 r25;
+ 'X' 56 r24;
+ 'X' 60 r23;
+ 'X' 64 r22;
+ 'X' 68 r21;
+ 'X' 72 r20;
+ 'X' 76 r19;
+ 'X' 80 r18;
+ 'X' 84 r17;
+ 'X' 88 r16;
+ 'X' 92 r15;
+ 'X' 96 r14;
+ 'X' 100 r13;
+ 'X' 104 r12;
+ 'X' 108 r11;
+ 'X' 112 r10;
+ 'X' 116 r9;
+ 'X' 120 r8;
+ 'X' 124 r7;
+ 'X' 128 r6;
+ 'X' 132 r5;
+ 'X' 136 r4;
+ 'X' 140 r3;
+ 'X' 144 r2;
+ 'X' 148 r1;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" status ", addr.status, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" cause ", addr.cause, "\n");
+ print(" badvaddr ", addr.badvaddr, "\n");
+ print(" tlbvirt ", addr.tlbvirt, "\n");
+ print(" hi ", addr.hi, "\n");
+ print(" lo ", addr.lo, "\n");
+ print(" r31 ", addr.r31, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r1 ", addr.r1, "\n");
+};
+
+defn linkreg(addr)
+{
+ complex Ureg addr;
+ return addr.r31\X;
+}
+
+print("/sys/lib/acid/mips");
diff --git a/utils/acid/mkfile b/utils/acid/mkfile
new file mode 100644
index 00000000..697f7fc7
--- /dev/null
+++ b/utils/acid/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=acid
+
+OFILES= main.$O\
+ y.tab.$O\
+ lex.$O\
+ util.$O\
+ exec.$O\
+ expr.$O\
+ list.$O\
+ builtin.$O\
+ proc.$O\
+ dot.$O\
+ print.$O\
+ os-$TARGMODEL.$O\
+ rdebug.$O\
+
+YFILES=dbg.y
+HFILES=acid.h y.tab.h
+
+LIBS=mach math bio regexp 9
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/acid/os-Nt.c b/utils/acid/os-Nt.c
new file mode 100644
index 00000000..5966d718
--- /dev/null
+++ b/utils/acid/os-Nt.c
@@ -0,0 +1,198 @@
+/*
+ * Windows Nt
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include <signal.h>
+
+#include <windows.h>
+
+#define MAXBUFSIZ 16640 /* 2 STYX messages plus headers */
+#define NT_DEBUG
+int nt_debug = 0;
+
+int
+opentty(char *tty, int baud)
+{
+ HANDLE comport;
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+
+ comport = CreateFile(tty, GENERIC_READ|GENERIC_WRITE,
+ 0, 0, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if (comport == INVALID_HANDLE_VALUE) {
+ werrstr("could not create port %s", tty);
+ return -1;
+ }
+
+ if (SetupComm(comport, MAXBUFSIZ, MAXBUFSIZ) != TRUE) {
+ werrstr("could not set up %s Comm port", tty);
+ CloseHandle(comport);
+ return -1;
+ }
+
+ if (GetCommState(comport, &dcb) != TRUE) {
+ werrstr("could not get %s comstate", tty);
+ CloseHandle(comport);
+ return -1;
+ }
+
+ if (baud == 0) {
+ dcb.BaudRate = 19200;
+ } else {
+ dcb.BaudRate = baud;
+ }
+ dcb.ByteSize = 8;
+ dcb.fParity = 0;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ dcb.fInX = 0;
+ dcb.fOutX = 0;
+ dcb.fAbortOnError = 1;
+
+ if (SetCommState(comport, &dcb) != TRUE) {
+ werrstr("could not set %s comstate", tty);
+ CloseHandle(comport);
+ return -1;
+ }
+
+ timeouts.ReadIntervalTimeout = 2;
+ /* char time in milliseconds, at 19.2K char time is .4 ms */
+ timeouts.ReadTotalTimeoutMultiplier = 0; /* was 100; */
+ timeouts.ReadTotalTimeoutConstant = 200; /* was 500; */
+ timeouts.WriteTotalTimeoutMultiplier = 0; /* was 10; */
+ timeouts.WriteTotalTimeoutConstant = 400; /* was 20; */
+
+ SetCommTimeouts(comport, &timeouts);
+
+ EscapeCommFunction(comport, SETDTR);
+
+ return (int) comport;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ DWORD numread = 0;
+ BOOL rtn;
+
+#ifdef NT_DEBUG
+ if (nt_debug) {
+ print("NT:rread fd %x bytes: %d", fd, bytes);
+ }
+#endif
+ rtn = ReadFile((HANDLE) fd, buf, bytes, &numread, 0);
+#ifdef NT_DEBUG
+ if (nt_debug) {
+ print(" numread: %d rtn: %x\n", numread, rtn);
+ if (numread) {
+ char *cp;
+ int i;
+
+ cp = (char *) buf;
+ for (i=0; i < numread; i++) {
+ print(" %2.2x", *cp++);
+ }
+ print("\n");
+ }
+ }
+#endif
+ if (!rtn)
+ return -1;
+ else
+ return numread;
+}
+
+int
+remote_write(int fd, char *buf, int bytes)
+{
+ DWORD numwrt = 0;
+ BOOL rtn;
+ char *cp;
+ int i;
+
+#ifdef NT_DEBUG
+ if (nt_debug) {
+ print("NT:rwrite fd %x bytes: %d", fd, bytes);
+ print("\n");
+ cp = (char *) buf;
+ for (i=0; i < bytes; i++) {
+ print(" %2.2x", *cp++);
+ }
+ print("\n");
+ }
+#endif
+ while (bytes > 0) {
+ rtn = WriteFile((HANDLE) fd, buf, bytes, &numwrt, 0);
+ if (!rtn) {
+ break;
+ }
+ buf += numwrt;
+ bytes -= numwrt;
+ }
+ return numwrt;
+}
+
+void
+detach(void)
+{
+ /* ??? */
+}
+
+char *
+waitfor(int pid)
+{
+ fprint(2, "wait unimplemented");
+ return 0;
+}
+
+int
+fork(void)
+{
+ fprint(2, "fork unimplemented");
+ return -1;
+}
+
+char *
+runcmd(char *cmd)
+{
+ fprint(2, "runcmd unimplemented");
+ return 0;
+}
+
+void (*notefunc)(int);
+
+os_notify(void (*func)(int))
+{
+ notefunc = func;
+ signal(SIGINT, func);
+ return 0;
+}
+
+void
+catcher(int sig)
+{
+ if (sig == SIGINT) {
+ gotint = 1;
+ signal(SIGINT, notefunc);
+ }
+}
+
+void
+setup_os_notify(void)
+{
+ os_notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+ fprint(2, "nproc not implemented\n");
+ return -1;
+}
diff --git a/utils/acid/os-Plan9.c b/utils/acid/os-Plan9.c
new file mode 100644
index 00000000..1ac60404
--- /dev/null
+++ b/utils/acid/os-Plan9.c
@@ -0,0 +1,157 @@
+/*
+ * Plan9
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+int
+opentty(char *tty, int baud)
+{
+ int fd, cfd;
+ char ctty[100];
+
+ if(tty == 0)
+ tty = "/dev/eia0";
+ sprint(ctty, "%sctl", tty);
+ fd = open(tty, 2);
+ if(fd < 0)
+ return -1;
+ if(baud){
+ cfd = open(ctty, 1);
+ if(cfd < 0)
+ return fd;
+ fprint(cfd, "b%d", baud);
+ close(cfd);
+ }
+ return fd;
+}
+
+void
+detach(void)
+{
+ rfork(RFNAMEG|RFNOTEG|RFREND);
+}
+
+char *
+waitfor(int pid)
+{
+ Waitmsg *w;
+ static char buf[ERRMAX];
+
+ for(;;) {
+ w = wait();
+ if(w == nil)
+ error("wait %r");
+ if(w->pid == pid){
+ strecpy(buf, buf+ERRMAX, w->msg);
+ free(w);
+ return buf;
+ }
+ free(w);
+ }
+ return nil;
+}
+
+char *
+runcmd(char *cmd)
+{
+ char *argv[4];
+ int pid;
+
+ argv[0] = "/bin/rc";
+ argv[1] = "-c";
+ argv[2] = cmd;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ exec("/bin/rc", argv);
+ exits(0);
+ default:
+ return waitfor(pid);
+ }
+ return 0;
+}
+
+void
+catcher(void *junk, char *s)
+{
+ USED(junk);
+
+ if(strstr(s, "interrupt")) {
+ gotint = 1;
+ noted(NCONT);
+ }
+ noted(NDFLT);
+}
+
+void (*notefunc)(void *, char *);
+
+void
+setup_os_notify(void)
+{
+ notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+ char buf[128];
+ int pid, i, fd;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("new: fork %r");
+ case 0:
+ rfork(RFNAMEG|RFNOTEG);
+
+ sprint(buf, "/proc/%d/ctl", getpid());
+ fd = open(buf, ORDWR);
+ if(fd < 0)
+ fatal("new: open %s: %r", buf);
+ write(fd, "hang", 4);
+ close(fd);
+
+ close(0);
+ close(1);
+ close(2);
+ for(i = 3; i < NFD; i++)
+ close(i);
+
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", OWRITE);
+ exec(argv[0], argv);
+ fatal("new: exec %s: %r");
+ default:
+ install(pid);
+ msg(pid, "waitstop");
+ notes(pid);
+ sproc(pid);
+ dostop(pid);
+ break;
+ }
+
+ return pid;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+int
+remote_write(int fd, char *buf, int bytes)
+{
+ return write(fd, buf, bytes);
+}
diff --git a/utils/acid/os-Posix.c b/utils/acid/os-Posix.c
new file mode 100644
index 00000000..58b4b255
--- /dev/null
+++ b/utils/acid/os-Posix.c
@@ -0,0 +1,183 @@
+#include <lib9.h>
+#include <bio.h>
+#include <sys/types.h>
+#include <termios.h>
+#undef getwd
+#undef getwd
+#include <unistd.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include <signal.h>
+
+static void
+setraw(int fd, int baud)
+{
+ struct termios sg;
+
+ switch(baud){
+ case 1200: baud = B1200; break;
+ case 2400: baud = B2400; break;
+ case 4800: baud = B4800; break;
+ case 9600: baud = B9600; break;
+ case 19200: baud = B19200; break;
+ case 38400: baud = B38400; break;
+ default:
+ werrstr("unknown speed %d", baud);
+ return;
+ }
+ if(tcgetattr(fd, &sg) >= 0) {
+ sg.c_iflag = sg.c_oflag = sg.c_lflag = 0;
+ sg.c_cflag &= ~CSIZE;
+ sg.c_cflag |= CS8 | CREAD;
+ sg.c_cflag &= ~(PARENB|PARODD);
+ sg.c_cc[VMIN] = 1;
+ sg.c_cc[VTIME] = 0;
+ if(baud) {
+ cfsetispeed(&sg, baud);
+ cfsetospeed(&sg, baud);
+ }
+ tcsetattr(fd, TCSANOW, &sg);
+ }
+}
+
+int
+opentty(char *tty, int baud)
+{
+ int fd;
+
+ if(baud == 0)
+ baud = 19200;
+ fd = open(tty, 2);
+ if(fd < 0)
+ return -1;
+ setraw(fd, baud);
+ return fd;
+}
+
+void
+detach(void)
+{
+ setpgid(0, 0);
+}
+
+char *
+waitfor(int pid)
+{
+ int n, status;
+ static char buf[32];
+
+ for(;;) {
+ n = wait(&status);
+ if(n < 0)
+ error("wait %r");
+ if(n == pid) {
+ sprint(buf, "%d", status);
+ return buf;
+ }
+ }
+}
+
+char *
+runcmd(char *cmd)
+{
+ char *argv[4];
+ int pid;
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = cmd;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ execv("/bin/sh", argv);
+ exits(0);
+ default:
+ return waitfor(pid);
+ }
+ return 0;
+}
+
+void (*notefunc)(int);
+
+os_notify(void (*func)(int))
+{
+ notefunc = func;
+ signal(SIGINT, func);
+}
+
+void
+catcher(int sig)
+{
+ if(sig==SIGINT) {
+ gotint = 1;
+ signal(SIGINT, notefunc);
+ }
+}
+
+void
+setup_os_notify(void)
+{
+ os_notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+ char buf[128];
+ int pid, i, fd;
+
+ if(rdebug)
+ error("can't newproc in remote mode");
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("new: fork %r");
+ case 0:
+ detach();
+
+ sprint(buf, "/proc/%d/ctl", getpid());
+ fd = open(buf, ORDWR);
+ if(fd < 0)
+ fatal("new: open %s: %r", buf);
+ write(fd, "hang", 4);
+ close(fd);
+
+ close(0);
+ close(1);
+ close(2);
+ for(i = 3; i < NFD; i++)
+ close(i);
+
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", OWRITE);
+ execvp(argv[0], argv);
+ fatal("new: execvp %s: %r");
+ default:
+ install(pid);
+ msg(pid, "waitstop");
+ notes(pid);
+ sproc(pid);
+ dostop(pid);
+ break;
+ }
+
+ return pid;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+int remote_write(int fd, char *buf, int bytes)
+{
+ return write(fd, buf, bytes);
+}
diff --git a/utils/acid/port b/utils/acid/port
new file mode 100644
index 00000000..a348eb9c
--- /dev/null
+++ b/utils/acid/port
@@ -0,0 +1,547 @@
+// portable acid for all architectures
+
+defn pfl(addr)
+{
+ print(pcfile(addr), ":", pcline(addr), "\n");
+}
+
+defn
+notestk(addr)
+{
+ local pc, sp;
+ complex Ureg addr;
+
+ pc = addr.pc\X;
+ sp = addr.sp\X;
+
+ print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ _stk(pc, sp, linkreg(addr), 1);
+}
+
+defn labstk(l) // trace from a label
+{
+ _stk(*(l+4)+Labpcoff, *l+Labspoff, linkreg(0), 0);
+}
+
+defn params(param)
+{
+ while param do {
+ sym = head param;
+ print(sym[0], "=", sym[1]);
+ param = tail param;
+ if param then
+ print (",");
+ }
+}
+
+defn locals(l)
+{
+ local sym;
+
+ while l do {
+ sym = head l;
+ print("\t", sym[0], "=", sym[1], "\n");
+ l = tail l;
+ }
+}
+
+defn _stk(pc, sp, link, dolocals)
+{
+ local stk;
+
+ print("At pc:", pc, ":", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ stk = strace(pc, sp, link);
+
+ while stk do {
+ frame = head stk;
+ print(fmt(frame[0], 'a'), "(");
+ params(frame[2]);
+ print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
+ print("\n\tcalled from ", fmt(frame[1], 'a'), " ");
+ pfl(frame[1]);
+ stk = tail stk;
+ if dolocals then
+ locals(frame[3]);
+ }
+}
+
+defn findsrc(file)
+{
+ local lst, src;
+
+ if file[0] == '/' then {
+ src = file(file);
+ if src != {} then {
+ srcfiles = append srcfiles, file;
+ srctext = append srctext, src;
+ return src;
+ }
+ return {};
+ }
+
+ lst = srcpath;
+ while head lst do {
+ src = file(head lst+file);
+ if src != {} then {
+ srcfiles = append srcfiles, file;
+ srctext = append srctext, src;
+ return src;
+ }
+ lst = tail lst;
+ }
+}
+
+defn line(addr)
+{
+ local src, file;
+
+ file = pcfile(addr);
+ src = match(file, srcfiles);
+
+ if src >= 0 then
+ src = srctext[src];
+ else
+ src = findsrc(file);
+
+ if src == {} then {
+ print("no source for ", file, "\n");
+ return {};
+ }
+ line = pcline(addr)-1;
+ print(file, ":", src[line], "\n");
+}
+
+defn addsrcdir(dir)
+{
+ dir = dir+"/";
+
+ if match(dir, srcpath) >= 0 then {
+ print("already in srcpath\n");
+ return {};
+ }
+
+ srcpath = {dir}+srcpath;
+}
+
+defn source()
+{
+ local l;
+
+ l = srcpath;
+ while l do {
+ print(head l, "\n");
+ l = tail l;
+ }
+ l = srcfiles;
+
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+}
+
+defn Bsrc(addr)
+{
+ local lst;
+
+ lst = srcpath;
+ file = pcfile(addr);
+ if file[0] == '/' && access(file) then {
+ rc("B "+itoa(-pcline(addr))+" "+file);
+ return {};
+ }
+ while head lst do {
+ name = head lst+file;
+ if access(name) then {
+ rc("B "+itoa(-pcline(addr))+" "+name);
+ return {};
+ }
+ lst = tail lst;
+ }
+ print("no source for ", file, "\n");
+}
+
+defn src(addr)
+{
+ local src, file, line, cline, text;
+
+ file = pcfile(addr);
+ src = match(file, srcfiles);
+
+ if src >= 0 then
+ src = srctext[src];
+ else
+ src = findsrc(file);
+
+ if src == {} then {
+ print("no source for ", file, "\n");
+ return {};
+ }
+
+ cline = pcline(addr)-1;
+ print(file, ":", cline, "\n");
+ line = cline-5;
+ loop 0,10 do {
+ if line >= 0 then {
+ if line == cline then
+ print(">");
+ else
+ print(" ");
+ text = src[line];
+ if text == {} then
+ return {};
+ print(line, "\t", text, "\n");
+ }
+ line = line+1;
+ }
+}
+
+defn stopped(pid) // called from acid when a process changes state
+{
+ pstop(pid); // stub so this is easy to replace
+}
+
+defn procs() // print status of processes
+{
+ local c, lst, cpid;
+
+ cpid = pid;
+ lst = proclist;
+ while lst do {
+ np = head lst;
+ setproc(np);
+ if np == cpid then
+ c = '>';
+ else
+ c = ' ';
+ print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n");
+ lst = tail lst;
+ }
+ pid = cpid;
+ if pid != 0 then
+ setproc(pid);
+}
+
+defn asm(addr)
+{
+ local bound;
+
+ bound = fnbound(addr);
+
+ addr = fmt(addr, 'i');
+ loop 1,30 do {
+ print(fmt(addr, 'a'), " ", fmt(addr, 'X'));
+ print("\t", @addr++, "\n");
+ if bound != {} && addr > bound[1] then {
+ lasmaddr = addr;
+ return {};
+ }
+ }
+ lasmaddr = addr;
+}
+
+defn casm()
+{
+ asm(lasmaddr);
+}
+
+defn new()
+{
+ bplist = {};
+ newproc(progargs);
+ // Dont miss the delay slot calls
+ bpset(follow(main)[0]);
+ cont();
+ bpdel(*PC);
+}
+
+defn stmnt() // step one statement
+{
+ local line;
+
+ line = pcline(*PC);
+ while 1 do {
+ step();
+ if line != pcline(*PC) then {
+ src(*PC);
+ return {};
+ }
+ }
+}
+
+defn func() // step until we leave the current function
+{
+ local bound, end, start, pc;
+
+ bound = fnbound(*PC);
+ if bound == {} then {
+ print("cannot locate text symbol\n");
+ return {};
+ }
+
+ pc = *PC;
+ start = bound[0];
+ end = bound[1];
+ while pc >= start && pc < end do {
+ step();
+ pc = *PC;
+ }
+}
+
+defn next()
+{
+ local sp, bound;
+
+ sp = *SP;
+ bound = fnbound(*PC);
+ stmnt();
+ pc = *PC;
+ if pc >= bound[0] && pc < bound[1] then
+ return {};
+
+ while (pc < bound[0] || pc > bound[1]) && sp >= *SP do {
+ step();
+ pc = *PC;
+ }
+ src(*PC);
+}
+
+defn dump(addr, n, fmt)
+{
+ loop 0, n do {
+ print(fmt(addr, 'X'), ": ");
+ addr = mem(addr, fmt);
+ }
+}
+
+defn mem(addr, fmt)
+{
+
+ local i, c, n;
+
+ i = 0;
+ while fmt[i] != 0 do {
+ c = fmt[i];
+ n = 0;
+ while '0' <= fmt[i] && fmt[i] <= '9' do {
+ n = 10*n + fmt[i]-'0';
+ i = i+1;
+ }
+ if n <= 0 then n = 1;
+ addr = fmt(addr, fmt[i]);
+ while n > 0 do {
+ print(*addr++, " ");
+ n = n-1;
+ }
+ i = i+1;
+ }
+ print("\n");
+ return addr;
+}
+
+defn symbols(pattern)
+{
+ local l, s;
+
+ l = symbols;
+ while l do {
+ s = head l;
+ if regexp(pattern, s[0]) then
+ print(s[0], "\t", s[1], "\t", s[2], "\n");
+ l = tail l;
+ }
+}
+
+defn spsrch(len)
+{
+ local addr, a, s, e;
+
+ addr = *SP;
+ s = origin & 0x7fffffff;
+ e = etext & 0x7fffffff;
+ loop 1, len do {
+ a = *addr++;
+ c = a & 0x7fffffff;
+ if c > s && c < e then {
+ print("src(", a, ")\n");
+ pfl(a);
+ }
+ }
+}
+
+defn bppush(val)
+{
+ return {"p", val};
+}
+
+defn bpderef()
+{
+ return {"*", 0};
+}
+
+defn bpmask()
+{
+ return {"&", 0};
+}
+
+defn bpeq()
+{
+ return {"=", 0};
+}
+
+defn bpneq()
+{
+ return {"!", 0};
+}
+
+defn bpand()
+{
+ return {"a", 0};
+}
+
+defn bpor()
+{
+ return {"o", 0};
+}
+
+defn bpcondset(pid, addr, conds)
+{
+ local l;
+ local id;
+ local found;
+
+ if status(pid) != "Stopped" then {
+ print("Waiting...\n");
+ stop(pid);
+ }
+
+ id = 0;
+ found = 0;
+
+ while !found && id <= 255 do {
+ l = bpl;
+ while l && head head l != id do {
+ l = tail l;
+ }
+
+ if !l then
+ found = 1;
+ else
+ id = id + 1;
+ }
+
+ if !found then {
+ print("error: no breakpoints available\n");
+ return -1;
+ }
+
+ bpl = append bpl, {id\d, pid\d, addr\X, conds};
+
+ _bpcondset(id, pid, addr, conds);
+
+ return id;
+}
+
+defn bpconddel(id)
+{
+ local i;
+ local l;
+
+ l = bpl;
+ i = 0;
+ while l do {
+ if id == head head l then {
+ bpl = delete bpl, i;
+ _bpconddel(id);
+ if id == bpid then
+ bpid = -1;
+ return {};
+ }
+ i = i + 1;
+ l = tail l;
+ }
+ print("no breakpoint with id ", id\d, ".\n");
+}
+
+defn bpprint(b)
+{
+ local l;
+
+ print(b[0], "\t", b[1], "\t", fmt(b[2], 'a'), " ", b[2]);
+ print("\t{");
+ l = b[3];
+ while l do {
+ print("\n\t\t\t\t\t", head l);
+ l = tail l;
+ }
+ print(" }\n");
+}
+
+defn bptab()
+{
+ local l;
+
+ l = bpl;
+ print("ID PID ADDR CONDITIONS\n");
+ while l do {
+ bpprint(head l);
+ l = tail l;
+ }
+}
+
+defn cont()
+{
+ local b, c, l, found;
+
+ l = bpl;
+ found = 0;
+ c = curpc();
+ while !found && l do {
+ b = head l;
+ if b[2] == c then {
+ nopstop = 1;
+ step();
+ nopstop = 0;
+ found = 1;
+ } else {
+ l = tail l;
+ }
+ }
+
+ return startstop(pid);
+}
+
+defn bpset(addr) // set a breakpoint
+{
+ return bpcondset(pid, addr, {});
+}
+
+defn bpdel(id)
+{
+ bpconddel(id);
+}
+
+defn bpaddr(id)
+{
+ local i;
+ local l;
+ local b;
+
+ l = bpl;
+ i = 0;
+ while l do {
+ b = head l;
+ if id == b[0] then
+ return b[2];
+ i = i + 1;
+ l = tail l;
+ }
+ print("bpaddr(", id\d, "): no match\n");
+ return {};
+}
+
+progargs="";
+print("/sys/lib/acid/port");
diff --git a/utils/acid/print.c b/utils/acid/print.c
new file mode 100644
index 00000000..8043fcd7
--- /dev/null
+++ b/utils/acid/print.c
@@ -0,0 +1,444 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+static char *binop[] =
+{
+ 0,
+ 0,
+ "*", /* [OMUL] "*", */
+ "/", /* [ODIV] "/", */
+ "%", /* [OMOD] "%", */
+ "+", /* [OADD] "+", */
+ "-", /* [OSUB] "-", */
+ ">>", /* [ORSH] ">>", */
+ "<<", /* [OLSH] "<<", */
+ "<", /* [OLT] "<", */
+ ">", /* [OGT] ">", */
+ "<=", /* [OLEQ] "<=", */
+ ">=", /* [OGEQ] ">=", */
+ "==", /* [OEQ] "==", */
+ "!=", /* [ONEQ] "!=", */
+ "&", /* [OLAND] "&", */
+ "^", /* [OXOR] "^", */
+ "|", /* [OLOR] "|", */
+ "&&", /* [OCAND] "&&", */
+ "||", /* [OCOR] "||", */
+ " = ", /* [OASGN] " = ", */
+};
+
+static char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+char *typenames[] =
+{
+ "integer", /* [TINT] "integer", */
+ "float", /* [TFLOAT] "float", */
+ "string", /* [TSTRING] "string", */
+ "list", /* [TLIST] "list", */
+ "code", /* [TCODE] "code", */
+};
+
+int
+cmp(const void *a, const void *b)
+{
+ return strcmp(*(char**)a, *(char**)b);
+}
+
+void
+fundefs(void)
+{
+ Lsym *l;
+ char **vec;
+ int i, j, n, max, col, f, g, s;
+
+ max = 0;
+ f = 0;
+ g = 100;
+ vec = gmalloc(sizeof(char*)*g);
+ if(vec == 0)
+ fatal("out of memory");
+
+ for(i = 0; i < Hashsize; i++) {
+ for(l = hash[i]; l; l = l->hash) {
+ if(l->proc == 0 && l->builtin == 0)
+ continue;
+ n = strlen(l->name);
+ if(n > max)
+ max = n;
+ if(f >= g) {
+ g *= 2;
+ vec = realloc(vec, sizeof(char*)*g);
+ if(vec == 0)
+ fatal("out of memory");
+ }
+ vec[f++] = l->name;
+ }
+ }
+ qsort(vec, f, sizeof(char*), cmp);
+ max++;
+ col = 60/max;
+ s = (f+col-1)/col;
+
+ for(i = 0; i < s; i++) {
+ for(j = i; j < f; j += s)
+ Bprint(bout, "%-*s", max, vec[j]);
+ Bprint(bout, "\n");
+ }
+}
+
+void
+whatis(Lsym *l)
+{
+ int t;
+ int def;
+ Type *ti;
+
+ if(l == 0) {
+ fundefs();
+ return;
+ }
+
+ def = 0;
+ if(l->v->set) {
+ t = l->v->type;
+ Bprint(bout, "%s variable", typenames[t]);
+ if(t == TINT || t == TFLOAT)
+ Bprint(bout, " format %c", l->v->vstore.fmt);
+ if(l->v->vstore.comt)
+ Bprint(bout, " complex %s",
+ l->v->vstore.comt->base->name);
+ Bputc(bout, '\n');
+ def = 1;
+ }
+ if(l->lt) {
+ Bprint(bout, "complex %s {\n", l->name);
+ for(ti = l->lt; ti; ti = ti->next) {
+ if(ti->type) {
+ if(ti->fmt == 'a') {
+ Bprint(bout, "\t%s %d %s;\n",
+ ti->type->name, ti->offset,
+ ti->tag->name);
+ }
+ else {
+ Bprint(bout, "\t'%c' %s %d %s;\n",
+ ti->fmt, ti->type->name, ti->offset,
+ ti->tag->name);
+ }
+ }
+ else
+ Bprint(bout, "\t'%c' %d %s;\n",
+ ti->fmt, ti->offset, ti->tag->name);
+ }
+ Bprint(bout, "};\n");
+ def = 1;
+ }
+ if(l->proc) {
+ Bprint(bout, "defn %s(", l->name);
+ pexpr(l->proc->left);
+ Bprint(bout, ") {\n");
+ pcode(l->proc->right, 1);
+ Bprint(bout, "}\n");
+ def = 1;
+ }
+ if(l->builtin) {
+ Bprint(bout, "builtin function\n");
+ def = 1;
+ }
+ if(def == 0)
+ Bprint(bout, "%s is undefined\n", l->name);
+}
+
+void
+slist(Node *n, int d)
+{
+ if(n == 0)
+ return;
+ if(n->op == OLIST)
+ Bprint(bout, "%.*s{\n", d-1, tabs);
+ pcode(n, d);
+ if(n->op == OLIST)
+ Bprint(bout, "%.*s}\n", d-1, tabs);
+}
+
+void
+pcode(Node *n, int d)
+{
+ Node *r, *l;
+
+ if(n == 0)
+ return;
+
+ r = n->right;
+ l = n->left;
+
+ switch(n->op) {
+ default:
+ Bprint(bout, "%.*s", d, tabs);
+ pexpr(n);
+ Bprint(bout, ";\n");
+ break;
+ case OLIST:
+ pcode(n->left, d);
+ pcode(n->right, d);
+ break;
+ case OLOCAL:
+ Bprint(bout, "%.*slocal", d, tabs);
+ while(l) {
+ Bprint(bout, " %s", l->sym->name);
+ l = l->left;
+ if(l == 0)
+ Bprint(bout, ";\n");
+ else
+ Bprint(bout, ",");
+ }
+ break;
+ case OCOMPLEX:
+ Bprint(bout, "%.*scomplex %s %s;\n", d, tabs, n->sym->name, l->sym->name);
+ break;
+ case OIF:
+ Bprint(bout, "%.*sif ", d, tabs);
+ pexpr(l);
+ d++;
+ Bprint(bout, " then\n", d, tabs);
+ if(r && r->op == OELSE) {
+ slist(r->left, d);
+ Bprint(bout, "%.*selse\n", d-1, tabs, d, tabs);
+ slist(r->right, d);
+ }
+ else
+ slist(r, d);
+ break;
+ case OWHILE:
+ Bprint(bout, "%.*swhile ", d, tabs);
+ pexpr(l);
+ d++;
+ Bprint(bout, " do\n", d, tabs);
+ slist(r, d);
+ break;
+ case ORET:
+ Bprint(bout, "%.*sreturn ", d, tabs);
+ pexpr(l);
+ Bprint(bout, ";\n");
+ break;
+ case ODO:
+ Bprint(bout, "%.*sloop ", d, tabs);
+ pexpr(l->left);
+ Bprint(bout, ", ");
+ pexpr(l->right);
+ Bprint(bout, " do\n");
+ slist(r, d+1);
+ }
+}
+
+void
+pexpr(Node *n)
+{
+ Node *r, *l;
+
+ if(n == 0)
+ return;
+
+ r = n->right;
+ l = n->left;
+
+ switch(n->op) {
+ case ONAME:
+ Bprint(bout, "%s", n->sym->name);
+ break;
+ case OCONST:
+ switch(n->type) {
+ case TINT:
+ Bprint(bout, "%d", (int)n->nstore.u0.sival);
+ break;
+ case TFLOAT:
+ Bprint(bout, "%g", n->nstore.u0.sfval);
+ break;
+ case TSTRING:
+ pstr(n->nstore.u0.sstring);
+ break;
+ case TLIST:
+ break;
+ }
+ break;
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ case OADD:
+ case OSUB:
+ case ORSH:
+ case OLSH:
+ case OLT:
+ case OGT:
+ case OLEQ:
+ case OGEQ:
+ case OEQ:
+ case ONEQ:
+ case OLAND:
+ case OXOR:
+ case OLOR:
+ case OCAND:
+ case OCOR:
+ Bputc(bout, '(');
+ pexpr(l);
+ Bprint(bout, binop[n->op]);
+ pexpr(r);
+ Bputc(bout, ')');
+ break;
+ case OASGN:
+ pexpr(l);
+ Bprint(bout, binop[n->op]);
+ pexpr(r);
+ break;
+ case OINDM:
+ Bprint(bout, "*");
+ pexpr(l);
+ break;
+ case OEDEC:
+ Bprint(bout, "--");
+ pexpr(l);
+ break;
+ case OEINC:
+ Bprint(bout, "++");
+ pexpr(l);
+ break;
+ case OPINC:
+ pexpr(l);
+ Bprint(bout, "++");
+ break;
+ case OPDEC:
+ pexpr(l);
+ Bprint(bout, "--");
+ break;
+ case ONOT:
+ Bprint(bout, "!");
+ pexpr(l);
+ break;
+ case OLIST:
+ pexpr(l);
+ if(r) {
+ Bprint(bout, ",");
+ pexpr(r);
+ }
+ break;
+ case OCALL:
+ pexpr(l);
+ Bprint(bout, "(");
+ pexpr(r);
+ Bprint(bout, ")");
+ break;
+ case OCTRUCT:
+ Bprint(bout, "{");
+ pexpr(l);
+ Bprint(bout, "}");
+ break;
+ case OHEAD:
+ Bprint(bout, "head ");
+ pexpr(l);
+ break;
+ case OTAIL:
+ Bprint(bout, "tail ");
+ pexpr(l);
+ break;
+ case OAPPEND:
+ Bprint(bout, "append ");
+ pexpr(l);
+ Bprint(bout, ",");
+ pexpr(r);
+ break;
+ case ODELETE:
+ Bprint(bout, "delete ");
+ pexpr(l);
+ Bprint(bout, ",");
+ pexpr(r);
+ break;
+ case ORET:
+ Bprint(bout, "return ");
+ pexpr(l);
+ break;
+ case OINDEX:
+ pexpr(l);
+ Bprint(bout, "[");
+ pexpr(r);
+ Bprint(bout, "]");
+ break;
+ case OINDC:
+ Bprint(bout, "@");
+ pexpr(l);
+ break;
+ case ODOT:
+ pexpr(l);
+ Bprint(bout, ".%s", n->sym->name);
+ break;
+ case OFRAME:
+ Bprint(bout, "%s:%s", n->sym->name, l->sym->name);
+ break;
+ case OCAST:
+ Bprint(bout, "(%s)", n->sym->name);
+ pexpr(l);
+ break;
+ case OFMT:
+ pexpr(l);
+ Bprint(bout, "\\%c", (int)r->nstore.u0.sival);
+ break;
+ case OEVAL:
+ Bprint(bout, "eval ");
+ pexpr(l);
+ break;
+ case OWHAT:
+ Bprint(bout, "whatis", n->sym->name);
+ if(n->sym)
+ Bprint(bout, " %s", n->sym->name);
+ break;
+ }
+}
+
+void
+pstr(String *s)
+{
+ int i, c;
+
+ Bputc(bout, '"');
+ for(i = 0; i < s->len; i++) {
+ c = s->string[i];
+ switch(c) {
+ case '\0':
+ c = '0';
+ break;
+ case '\n':
+ c = 'n';
+ break;
+ case '\r':
+ c = 'r';
+ break;
+ case '\t':
+ c = 't';
+ break;
+ case '\b':
+ c = 'b';
+ break;
+ case '\f':
+ c = 'f';
+ break;
+ case '\a':
+ c = 'a';
+ break;
+ case '\v':
+ c = 'v';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '"':
+ c = '"';
+ break;
+ default:
+ Bputc(bout, c);
+ continue;
+ }
+ Bputc(bout, '\\');
+ Bputc(bout, c);
+ }
+ Bputc(bout, '"');
+}
diff --git a/utils/acid/proc.c b/utils/acid/proc.c
new file mode 100644
index 00000000..f13dbf95
--- /dev/null
+++ b/utils/acid/proc.c
@@ -0,0 +1,274 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+void
+nocore(void)
+{
+ int i;
+
+ if(cormap == 0)
+ return;
+
+ for (i = 0; i < cormap->nsegs; i++)
+ if (cormap->seg[i].mget == 0 && cormap->seg[i].inuse && cormap->seg[i].fd >= 0)
+ close(cormap->seg[i].fd);
+ free(cormap);
+ cormap = 0;
+}
+
+void
+sproc(int pid)
+{
+ Lsym *s;
+ char buf[64];
+ ulong proctab;
+ int fd, i, fcor;
+
+ if(symmap == 0)
+ error("no map");
+
+ if(rdebug) {
+ fcor = -1;
+ proctab = 0;
+ i = remoteio(pid, "proc", buf, sizeof(buf));
+ if(i >= 0) {
+ buf[i] = '\0';
+ proctab = strtoul(buf, 0, 16);
+ } else
+ error("can't access pid %d: %r", pid);
+ s = look("proc");
+ if(s != 0)
+ s->v->vstore.u0.sival = proctab;
+ } else {
+ sprint(buf, "/proc/%d/mem", pid);
+ fcor = open(buf, ORDWR);
+ if(fcor < 0)
+ error("setproc: open %s: %r", buf);
+
+ checkqid(symmap->seg[0].fd, pid);
+
+ if(kernel) {
+ proctab = 0;
+ sprint(buf, "/proc/%d/proc", pid);
+ fd = open(buf, OREAD);
+ if(fd >= 0) {
+ i = read(fd, buf, sizeof(buf));
+ if(i >= 0) {
+ buf[i] = '\0';
+ proctab = strtoul(buf, 0, 0);
+ }
+ close(fd);
+ }
+ s = look("proc");
+ if(s != 0)
+ s->v->vstore.u0.sival = proctab;
+ }
+ }
+
+ s = look("pid");
+ s->v->vstore.u0.sival = pid;
+
+ nocore();
+ if(rdebug) {
+ cormap = attachremt(remfd, &fhdr);
+ for(i = 0; i < cormap->nsegs; i++)
+ setmapio(cormap, i, remget, remput);
+ } else
+ cormap = attachproc(pid, kernel, fcor, &fhdr);
+ if (cormap == 0)
+ error("setproc: cant make coremap");
+ i = findseg(cormap, "text");
+ if (i >= 0)
+ cormap->seg[i].name = "*text";
+ i = findseg(cormap, "data");
+ if (i >= 0)
+ cormap->seg[i].name = "*data";
+ install(pid);
+}
+
+void
+notes(int pid)
+{
+ Lsym *s;
+ Value *v;
+ int i, fd;
+ char buf[128];
+ List *l, **tail;
+
+ s = look("notes");
+ if(s == 0)
+ return;
+ v = s->v;
+
+ if(!rdebug) {
+ sprint(buf, "/proc/%d/note", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0)
+ error("pid=%d: open note: %r", pid);
+ } else
+ fd = -1;
+
+ v->set = 1;
+ v->type = TLIST;
+ v->vstore.u0.sl = 0;
+ tail = &v->vstore.u0.sl;
+ for(;;) {
+ if(rdebug)
+ i = remoteio(pid, "note", buf, sizeof(buf));
+ else
+ i = read(fd, buf, sizeof(buf));
+ if(i <= 0)
+ break;
+ buf[i] = '\0';
+ l = al(TSTRING);
+ l->lstore.u0.sstring = strnode(buf);
+ l->lstore.fmt = 's';
+ *tail = l;
+ tail = &l->next;
+ }
+ if(fd >= 0)
+ close(fd);
+}
+
+void
+dostop(int pid)
+{
+ Lsym *s;
+ Node *np, *p;
+
+ s = look("stopped");
+ if(s && s->proc) {
+ np = an(ONAME, ZN, ZN);
+ np->sym = s;
+ np->nstore.fmt = 'D';
+ np->type = TINT;
+ p = con(pid);
+ p->nstore.fmt = 'D';
+ np = an(OCALL, np, p);
+ execute(np);
+ }
+}
+
+void
+install(int pid)
+{
+ Lsym *s;
+ List *l;
+ char buf[128];
+ int i, fd, new, p;
+
+ new = -1;
+ for(i = 0; i < Maxproc; i++) {
+ p = ptab[i].pid;
+ if(p == pid)
+ return;
+ if(p == 0 && new == -1)
+ new = i;
+ }
+ if(new == -1)
+ error("no free process slots");
+
+ if(!rdebug) {
+ sprint(buf, "/proc/%d/ctl", pid);
+ fd = open(buf, OWRITE);
+ if(fd < 0)
+ error("pid=%d: open ctl: %r", pid);
+ } else
+ fd = -1;
+ ptab[new].pid = pid;
+ ptab[new].ctl = fd;
+
+ s = look("proclist");
+ l = al(TINT);
+ l->lstore.fmt = 'D';
+ l->lstore.u0.sival = pid;
+ l->next = s->v->vstore.u0.sl;
+ s->v->vstore.u0.sl = l;
+ s->v->set = 1;
+}
+
+void
+deinstall(int pid)
+{
+ int i;
+ Lsym *s;
+ List *f, **d;
+
+ for(i = 0; i < Maxproc; i++) {
+ if(ptab[i].pid == pid) {
+ if(ptab[i].ctl >= 0)
+ close(ptab[i].ctl);
+ ptab[i].pid = 0;
+ s = look("proclist");
+ d = &s->v->vstore.u0.sl;
+ for(f = *d; f; f = f->next) {
+ if(f->lstore.u0.sival == pid) {
+ *d = f->next;
+ break;
+ }
+ }
+ s = look("pid");
+ if(s->v->vstore.u0.sival == pid)
+ s->v->vstore.u0.sival = 0;
+ return;
+ }
+ }
+}
+
+void
+msg(int pid, char *msg)
+{
+ int i;
+ int l;
+ int ok;
+ char err[ERRMAX];
+
+ for(i = 0; i < Maxproc; i++) {
+ if(ptab[i].pid == pid) {
+ l = strlen(msg);
+ if(rdebug)
+ ok = sendremote(pid, msg) >= 0;
+ else
+ ok = write(ptab[i].ctl, msg, l) == l;
+ if(!ok) {
+ errstr(err, sizeof err);
+ if(strcmp(err, "process exited") == 0)
+ deinstall(pid);
+ error("msg: pid=%d %s: %s", pid, msg, err);
+ }
+ return;
+ }
+ }
+ error("msg: pid=%d: not found for %s", pid, msg);
+}
+
+char *
+getstatus(int pid)
+{
+ int fd;
+ char *p;
+
+ static char buf[128];
+
+ if(rdebug) {
+ if(remoteio(pid, "status", buf, sizeof(buf)) < 0)
+ error("remote status: pid %d: %r", pid);
+ return buf;
+ }
+ sprint(buf, "/proc/%d/status", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0)
+ error("open %s: %r", buf);
+ read(fd, buf, sizeof(buf));
+ close(fd);
+ p = buf+56+12; /* Do better! */
+ while(*p == ' ')
+ p--;
+ p[1] = '\0';
+ return buf+56; /* ditto */
+}
diff --git a/utils/acid/rdebug.c b/utils/acid/rdebug.c
new file mode 100644
index 00000000..8903711e
--- /dev/null
+++ b/utils/acid/rdebug.c
@@ -0,0 +1,274 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include "../../include/rdbg.h"
+
+/*
+ * remote kernel debugging
+ */
+
+enum {
+ chatty = 0
+};
+
+static long myreadn(int, void*, long);
+static int rproto(int, char*, int);
+
+void
+remotemap(Map *m, int i)
+{
+ setmapio(m, i, remget, remput);
+}
+
+/*
+ * send a /proc control message to remote pid,
+ * and await a reply
+ */
+int
+sendremote(int pid, char *msg)
+{
+ int tag;
+ char dbg[RDBMSGLEN];
+
+ if(protodebug)
+ fprint(2, "sendremote: pid %d: %s\n", pid, msg);
+ if(strcmp(msg, "startstop") == 0)
+ tag = Tstartstop;
+ else if(strcmp(msg, "waitstop") == 0)
+ tag = Twaitstop;
+ else if(strcmp(msg, "start") == 0)
+ tag = Tstart;
+ else if(strcmp(msg, "stop") == 0)
+ tag = Tstop;
+ else if(strcmp(msg, "kill") == 0)
+ tag = Tkill;
+ else {
+ werrstr("invalid sendremote: %s", msg);
+ return -1;
+ }
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = tag;
+ dbg[1] = pid>>24;
+ dbg[2] = pid>>16;
+ dbg[3] = pid>>8;
+ dbg[4] = pid;
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * read a line from /proc/<pid>/<file> into buf
+ */
+int
+remoteio(int pid, char *file, char *buf, int nb)
+{
+ char dbg[RDBMSGLEN];
+ int tag;
+
+ if(protodebug)
+ fprint(2, "remoteio %d: %s\n", pid, file);
+ memset(buf, nb, 0);
+ if(strcmp(file, "proc") == 0)
+ tag = Tproc;
+ else if(strcmp(file, "status") == 0)
+ tag = Tstatus;
+ else if(strcmp(file, "note") == 0)
+ tag = Trnote;
+ else {
+ werrstr("invalid remoteio: %s", file);
+ return -1;
+ }
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = tag;
+ dbg[1] = pid>>24;
+ dbg[2] = pid>>16;
+ dbg[3] = pid>>8;
+ dbg[4] = pid;
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0)
+ return -1;
+ if(nb > sizeof(dbg)-1)
+ nb = sizeof(dbg)-1;
+ memmove(buf, dbg+1, nb);
+ return strlen(buf);
+}
+
+int
+remget(struct segment *s, ulong addr, long off, char *buf, int size)
+{
+ int n, t;
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remget addr %#lux off %#lux\n", addr, off);
+ for (t = 0; t < size; t += n) {
+ n = size;
+ if(n > 9)
+ n = 9;
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = Tmget;
+ dbg[1] = off>>24;
+ dbg[2] = off>>16;
+ dbg[3] = off>>8;
+ dbg[4] = off;
+ dbg[5] = n;
+ if(rproto(s->fd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't read address %#lux: %r", addr);
+ return -1;
+ }
+ memmove(buf, dbg+1, n);
+ buf += n;
+ }
+ return t;
+}
+
+int
+remput(struct segment *s, ulong addr, long off, char *buf, int size)
+{
+ int n, i, t;
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remput addr %#lux off %#lux\n", addr, off);
+ for (t = 0; t < size; t += n) {
+ n = size;
+ if(n > 4)
+ n = 4;
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = Tmput;
+ dbg[1] = off>>24;
+ dbg[2] = off>>16;
+ dbg[3] = off>>8;
+ dbg[4] = off;
+ dbg[5] = n;
+ for(i=0; i<n; i++)
+ dbg[6+i] = *buf++;
+ if(rproto(s->fd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't write address %#lux: %r", addr);
+ return -1;
+ }
+ }
+ return t;
+}
+
+int
+remcondset(char op, ulong val)
+{
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remcondset op %c val: %#lux\n", op, val);
+ memset(dbg, 0, sizeof(dbg));
+
+ dbg[0] = Tcondbreak;
+ dbg[1] = val>>24;
+ dbg[2] = val>>16;
+ dbg[3] = val>>8;
+ dbg[4] = val;
+ dbg[5] = op;
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't set condbreak: %c %#lux: %r", op, val);
+ return -1;
+ }
+ return 0;
+}
+
+int
+remcondstartstop(int pid)
+{
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remcondstartstop pid %d\n", pid);
+ memset(dbg, 0, sizeof(dbg));
+
+ dbg[0] = Tstartstop;
+ dbg[1] = pid>>24;
+ dbg[2] = pid>>16;
+ dbg[3] = pid>>8;
+ dbg[4] = pid;
+
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't send Tstartstop");
+ return -1;
+ }
+
+ return dbg[1];
+}
+
+static int
+rproto(int fd, char *buf, int nb)
+{
+ int tag;
+
+ if (protodebug) {
+ int i;
+ print("rproto remote write fd %d bytes: %d\n", fd, nb);
+ for (i=0; i < nb; i++) {
+ print(" %2.2ux", buf[i]&0xFF);
+ }
+ print("\n");
+ }
+ tag = buf[0];
+ if(remote_write(fd, buf, nb) != nb ||
+ myreadn(fd, buf, nb) != nb){ /* could set alarm */
+ werrstr("remote i/o: %r");
+ return -1;
+ }
+ if(buf[0] == Rerr){
+ buf[nb-1] = 0;
+ werrstr("remote err: %s", buf+1);
+ return -1;
+ }
+ if(buf[0] != tag+1) {
+ werrstr("remote proto err: %.2ux", buf[0]&0xff);
+ return -1;
+ }
+ if(chatty) {
+ int i;
+ fprint(2, "remote [%d]: ", nb);
+ for(i=0; i<nb; i++)
+ fprint(2, " %.2ux", buf[i]&0xff);
+ fprint(2, "\n");
+ }
+ return nb;
+}
+
+/*
+ * this should probably be in lib9 as readn
+ */
+static long
+myreadn(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ if (protodebug) {
+ print("remote read fd %d bytes: %ld", f, n);
+ }
+ a = av;
+ t = 0;
+ while(t < n){
+ m = remote_read(f, a+t, n-t);
+ if(m < 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ if (protodebug) {
+ print(" rtn: %ld\n", m);
+ if (m) {
+ int i;
+
+ for (i=0; i < m; i++)
+ print(" %2.2ux", a[i+t]&0xFF);
+ print("\n");
+ }
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/utils/acid/sparc b/utils/acid/sparc
new file mode 100644
index 00000000..76a1eba3
--- /dev/null
+++ b/utils/acid/sparc
@@ -0,0 +1,218 @@
+// Sparc support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'X';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/sparc/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *R1, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *R1, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n");
+ print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "\n");
+ print("R7\t", *R7, "R8\t", *R8, "R9\t", *R9, "\n");
+ print("R10\t", *R10, "R11\t", *R11, "R12\t", *R12, "\n");
+ print("R13\t", *R13, "R14\t", *R14, "R15\t", *R15, "\n");
+ print("R16\t", *R16, "R17\t", *R17, "R18\t", *R18, "\n");
+ print("R19\t", *R19, "R20\t", *R20, "R21\t", *R21, "\n");
+ print("R22\t", *R22, "R23\t", *R23, "R24\t", *R24, "\n");
+ print("R25\t", *R25, "R26\t", *R26, "R27\t", *R27, "\n");
+ print("R28\t", *R28, "R29\t", *R29, "R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local link;
+ local cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("PSR\t", *PSR, "\n");
+
+ link = *R15;
+ print("SP\t", *R1, "\tLINK\t\t", link, " ", fmt(link, 'a'));
+ pfl(link);
+
+ cause = *TBR;
+ print("Y\t", *Y, "\tCAUSE\t", *Y, cause, " ", reason(cause), "\n");
+}
+
+defn Fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n");
+ print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n");
+ print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n");
+ print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n");
+ print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n");
+ print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+ print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+ print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+ print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+ print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+ print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+ print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+ print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+ print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+ print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+ print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*TBR), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+aggr Ureg
+{
+ 'U' 0 r0;
+ {
+ 'U' 4 sp;
+ 'U' 4 usp;
+ 'U' 4 r1;
+ };
+ 'U' 8 r2;
+ 'U' 12 r3;
+ 'U' 16 r4;
+ 'U' 20 r5;
+ 'U' 24 r6;
+ 'U' 28 r7;
+ 'U' 32 r8;
+ 'U' 36 r9;
+ 'U' 40 r10;
+ 'U' 44 r11;
+ 'U' 48 r12;
+ 'U' 52 r13;
+ 'U' 56 r14;
+ 'U' 60 r15;
+ 'U' 64 r16;
+ 'U' 68 r17;
+ 'U' 72 r18;
+ 'U' 76 r19;
+ 'U' 80 r20;
+ 'U' 84 r21;
+ 'U' 88 r22;
+ 'U' 92 r23;
+ 'U' 96 r24;
+ 'U' 100 r25;
+ 'U' 104 r26;
+ 'U' 108 r27;
+ 'U' 112 r28;
+ 'U' 116 r29;
+ 'U' 120 r30;
+ 'U' 124 r31;
+ 'U' 128 y;
+ 'U' 132 tbr;
+ 'U' 136 psr;
+ 'U' 140 npc;
+ 'U' 144 pc;
+ 'U' 148 pad;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" r0 ", addr.r0, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r29 ", addr.r29, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r31 ", addr.r31, "\n");
+ print(" y ", addr.y, "\n");
+ print(" tbr ", addr.tbr, "\n");
+ print(" psr ", addr.psr, "\n");
+ print(" npc ", addr.npc, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" pad ", addr.pad, "\n");
+};
+
+defn linkreg(addr)
+{
+ complex Ureg addr;
+ return addr.r15\X;
+}
+
+print("/sys/lib/acid/sparc");
diff --git a/utils/acid/util.c b/utils/acid/util.c
new file mode 100644
index 00000000..0de244fd
--- /dev/null
+++ b/utils/acid/util.c
@@ -0,0 +1,295 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+static int syren;
+
+Lsym*
+unique(char *buf, Sym *s)
+{
+ Lsym *l;
+ int i, renamed;
+
+ renamed = 0;
+ strcpy(buf, s->name);
+ for(;;) {
+ l = look(buf);
+ if(l == 0 || (l->lexval == Tid && l->v->set == 0))
+ break;
+
+ if(syren == 0 && !quiet) {
+ print("Symbol renames:\n");
+ syren = 1;
+ }
+ i = strlen(buf)+1;
+ memmove(buf+1, buf, i);
+ buf[0] = '$';
+ renamed++;
+ if(renamed > 5 && !quiet) {
+ print("Too many renames; must be X source!\n");
+ break;
+ }
+ }
+ if(renamed && !quiet)
+ print("\t%s=%s %c/%lux\n", s->name, buf, s->type, s->value);
+ if(l == 0)
+ l = enter(buf, Tid);
+ return l;
+}
+
+void
+varsym(void)
+{
+ int i;
+ Sym *s;
+ long n;
+ Lsym *l;
+ ulong v;
+ char buf[1024];
+ List *list, **tail, *l2, *tl;
+
+ tail = &l2;
+ l2 = 0;
+
+ symbase(&n);
+ for(i = 0; i < n; i++) {
+ s = getsym(i);
+ switch(s->type) {
+ case 'T':
+ case 'L':
+ case 'D':
+ case 'B':
+ case 'b':
+ case 'd':
+ case 'l':
+ case 't':
+ if(s->name[0] == '.')
+ continue;
+
+ v = s->value;
+ tl = al(TLIST);
+ *tail = tl;
+ tail = &tl->next;
+
+ l = unique(buf, s);
+
+ l->v->set = 1;
+ l->v->type = TINT;
+ l->v->vstore.u0.sival = v;
+ if(l->v->vstore.comt == 0)
+ l->v->vstore.fmt = 'X';
+
+ /* Enter as list of { name, type, value } */
+ list = al(TSTRING);
+ tl->lstore.u0.sl = list;
+ list->lstore.u0.sstring = strnode(buf);
+ list->lstore.fmt = 's';
+ list->next = al(TINT);
+ list = list->next;
+ list->lstore.fmt = 'c';
+ list->lstore.u0.sival = s->type;
+ list->next = al(TINT);
+ list = list->next;
+ list->lstore.fmt = 'X';
+ list->lstore.u0.sival = v;
+
+ }
+ }
+ l = mkvar("symbols");
+ l->v->set = 1;
+ l->v->type = TLIST;
+ l->v->vstore.u0.sl = l2;
+ if(l2 == 0)
+ print("no symbol information\n");
+}
+
+void
+varreg(void)
+{
+ Lsym *l;
+ Value *v;
+ Reglist *r;
+ List **tail, *li;
+
+ l = mkvar("registers");
+ v = l->v;
+ v->set = 1;
+ v->type = TLIST;
+ v->vstore.u0.sl = 0;
+ tail = &v->vstore.u0.sl;
+
+ for(r = mach->reglist; r->rname; r++) {
+ l = mkvar(r->rname);
+ v = l->v;
+ v->set = 1;
+ v->vstore.u0.sival = r->roffs;
+ v->vstore.fmt = r->rformat;
+ v->type = TINT;
+
+ li = al(TSTRING);
+ li->lstore.u0.sstring = strnode(r->rname);
+ li->lstore.fmt = 's';
+ *tail = li;
+ tail = &li->next;
+ }
+
+ if(machdata == 0)
+ return;
+
+ l = mkvar("bpinst"); /* Breakpoint text */
+ v = l->v;
+ v->type = TSTRING;
+ v->vstore.fmt = 's';
+ v->set = 1;
+ v->vstore.u0.sstring = gmalloc(sizeof(String));
+ v->vstore.u0.sstring->len = machdata->bpsize;
+ v->vstore.u0.sstring->string = gmalloc(machdata->bpsize);
+ memmove(v->vstore.u0.sstring->string, machdata->bpinst, machdata->bpsize);
+}
+
+void
+loadvars(void)
+{
+ Lsym *l;
+ Value *v;
+
+ l = mkvar("proc");
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'X';
+ v->set = 1;
+ v->vstore.u0.sival = 0;
+
+ l = mkvar("pid"); /* Current process */
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'D';
+ v->set = 1;
+ v->vstore.u0.sival = 0;
+
+ mkvar("notes"); /* Pending notes */
+
+ l = mkvar("proclist"); /* Attached processes */
+ l->v->type = TLIST;
+
+ l = mkvar("rdebug"); /* remote debugging enabled? */
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'D';
+ v->set = 1;
+ v->vstore.u0.sival = rdebug;
+
+ if(rdebug) {
+ l = mkvar("_breakid");
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'D';
+ v->set = 1;
+ v->vstore.u0.sival = -1;
+ }
+}
+
+vlong
+rget(Map *map, char *reg)
+{
+ Lsym *s;
+ long x;
+ vlong v;
+ int ret;
+
+ s = look(reg);
+ if(s == 0)
+ fatal("rget: %s\n", reg);
+
+ if(s->v->vstore.fmt == 'Y')
+ ret = get8(map, (long)s->v->vstore.u0.sival, &v);
+ else {
+ ret = get4(map, (long)s->v->vstore.u0.sival, &x);
+ v = x;
+ }
+ if(ret < 0)
+ error("can't get register %s: %r\n", reg);
+ return v;
+}
+
+String*
+strnodlen(char *name, int len)
+{
+ String *s;
+
+ s = gmalloc(sizeof(String)+len+1);
+ s->string = (char*)s+sizeof(String);
+ s->len = len;
+ if(name != 0)
+ memmove(s->string, name, len);
+ s->string[len] = '\0';
+
+ s->sgc.gclink = gcl;
+ gcl = &s->sgc;
+
+ return s;
+}
+
+String*
+strnode(char *name)
+{
+ return strnodlen(name, strlen(name));
+}
+
+String*
+runenode(Rune *name)
+{
+ int len;
+ Rune *p;
+ String *s;
+
+ p = name;
+ for(len = 0; *p; p++)
+ len++;
+
+ len++;
+ len *= sizeof(Rune);
+ s = gmalloc(sizeof(String)+len);
+ s->string = (char*)s+sizeof(String);
+ s->len = len;
+ memmove(s->string, name, len);
+
+ s->sgc.gclink = gcl;
+ gcl = &s->sgc;
+
+ return s;
+}
+
+String*
+stradd(String *l, String *r)
+{
+ int len;
+ String *s;
+
+ len = l->len+r->len;
+ s = gmalloc(sizeof(String)+len+1);
+ s->sgc.gclink = gcl;
+ gcl = &s->sgc;
+ s->len = len;
+ s->string = (char*)s+sizeof(String);
+ memmove(s->string, l->string, l->len);
+ memmove(s->string+l->len, r->string, r->len);
+ s->string[s->len] = 0;
+ return s;
+}
+
+int
+scmp(String *sr, String *sl)
+{
+ if(sr->len != sl->len)
+ return 0;
+
+ if(memcmp(sr->string, sl->string, sl->len))
+ return 0;
+
+ return 1;
+}
diff --git a/utils/awk/FIXES b/utils/awk/FIXES
new file mode 100644
index 00000000..236323fc
--- /dev/null
+++ b/utils/awk/FIXES
@@ -0,0 +1,703 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+This file lists all bug fixes, changes, etc., made since the AWK book
+was sent to the printers in August, 1987.
+
+Nov 15, 2000:
+ fixed a bug introduced in august 1997 that caused expressions
+ like $f[1] to be syntax errors. thanks to arnold robbins for
+ noticing this and providing a fix.
+
+Oct 30, 2000:
+ fixed some nextfile bugs: not handling all cases. thanks to
+ arnold robbins for pointing this out. new regressions added.
+
+ close() is now a function. it returns whatever the library
+ fclose returns, and -1 for closing a file or pipe that wasn't
+ opened.
+
+Sep 24, 2000:
+ permit \n explicitly in character classes; won't work right
+ if comes in as "[\n]" but ok as /[\n]/, because of multiple
+ processing of \'s. thanks to arnold robbins.
+
+July 5, 2000:
+ minor fiddles in tran.c to keep compilers happy about uschar.
+ thanks to norman wilson.
+
+May 25, 2000:
+ yet another attempt at making 8-bit input work, with another
+ band-aid in b.c (member()), and some (uschar) casts to head
+ off potential errors in subscripts (like isdigit). also
+ changed HAT to NCHARS-2. thanks again to santiago vila.
+
+ changed maketab.c to ignore apparently out of range definitions
+ instead of halting; new freeBSD generates one. thanks to
+ jon snader <jsnader@ix.netcom.com> for pointing out the problem.
+
+May 2, 2000:
+ fixed an 8-bit problem in b.c by making several char*'s into
+ unsigned char*'s. not clear i have them all yet. thanks to
+ Santiago Vila <sanvila@unex.es> for the bug report.
+
+Apr 21, 2000:
+ finally found and fixed a memory leak in function call; it's
+ been there since functions were added ~1983. thanks to
+ jon bentley for the test case that found it.
+
+ added test in envinit to catch environment "variables" with
+ names begining with '='; thanks to Berend Hasselman.
+
+Jul 28, 1999:
+ added test in defn() to catch function foo(foo), which
+ otherwise recurses until core dump. thanks to arnold
+ robbins for noticing this.
+
+Jun 20, 1999:
+ added *bp in gettok in lex.c; appears possible to exit function
+ without terminating the string. thanks to russ cox.
+
+Jun 2, 1999:
+ added function stdinit() to run to initialize files[] array,
+ in case stdin, etc., are not constants; some compilers care.
+
+May 10, 1999:
+ replaced the ERROR ... FATAL, etc., macros with functions
+ based on vprintf, to avoid problems caused by overrunning
+ fixed-size errbuf array. thanks to ralph corderoy for the
+ impetus, and for pointing out a string termination bug in
+ qstring as well.
+
+Apr 21, 1999:
+ fixed bug that caused occasional core dumps with commandline
+ variable with value ending in \. (thanks to nelson beebe for
+ the test case.)
+
+Apr 16, 1999:
+ with code kindly provided by Bruce Lilly, awk now parses
+ /=/ and similar constructs more sensibly in more places.
+ Bruce also provided some helpful test cases.
+
+Apr 5, 1999:
+ changed true/false to True/False in run.c to make it
+ easier to compile with C++. Added some casts on malloc
+ and realloc to be honest about casts; ditto. changed
+ ltype int to long in struct rrow to reduce some 64-bit
+ complaints; other changes scattered throughout for the
+ same purpose. thanks to Nelson Beebe for these portability
+ improvements.
+
+ removed some horrible pointer-int casting in b.c and elsewhere
+ by adding ptoi and itonp to localize the casts, which are
+ all benign. fixed one incipient bug that showed up on sgi
+ in 64-bit mode.
+
+ reset lineno for new source file; include filename in error
+ message. also fixed line number error in continuation lines.
+ (thanks to Nelson Beebe for both of these.)
+
+Mar 24, 1999:
+ Nelson Beebe notes that irix 5.3 yacc dies with a bogus
+ error; use a newer version or switch to bison, since sgi
+ is unlikely to fix it.
+
+Mar 5, 1999:
+ changed isnumber to is_number to avoid the problem caused by
+ versions of ctype.h that include the name isnumber.
+
+ distribution now includes a script for building on a Mac,
+ thanks to Dan Allen.
+
+Feb 20, 1999:
+ fixed memory leaks in run.c (call) and tran.c (setfval).
+ thanks to Stephen Nutt for finding these and providing the fixes.
+
+Jan 13, 1999:
+ replaced srand argument by (unsigned int) in run.c;
+ avoids problem on Mac and potentially on Unix & Windows.
+ thanks to Dan Allen.
+
+ added a few (int) casts to silence useless compiler warnings.
+ e.g., errorflag= in run.c jump().
+
+ added proctab.c to the bundle outout; one less thing
+ to have to compile out of the box.
+
+ added calls to _popen and _pclose to the win95 stub for
+ pipes (thanks to Steve Adams for this helpful suggestion).
+ seems to work, though properties are not well understood
+ by me, and it appears that under some circumstances the
+ pipe output is truncated. Be careful.
+
+Oct 19, 1998:
+ fixed a couple of bugs in getrec: could fail to update $0
+ after a getline var; because inputFS wasn't initialized,
+ could split $0 on every character, a misleading diversion.
+
+ fixed caching bug in makedfa: LRU was actually removing
+ least often used.
+
+ thanks to ross ridge for finding these, and for providing
+ great bug reports.
+
+May 12, 1998:
+ fixed potential bug in readrec: might fail to update record
+ pointer after growing. thanks to dan levy for spotting this
+ and suggesting the fix.
+
+Mar 12, 1998:
+ added -V to print version number and die.
+
+Feb 11, 1998:
+ subtle silent bug in lex.c: if the program ended with a number
+ longer than 1 digit, part of the input would be pushed back and
+ parsed again because token buffer wasn't terminated right.
+ example: awk 'length($0) > 10'. blush. at least i found it
+ myself.
+
+Aug 31, 1997:
+ s/adelete/awkdelete/: SGI uses this in malloc.h.
+ thanks to nelson beebe for pointing this one out.
+
+Aug 21, 1997:
+ fixed some bugs in sub and gsub when replacement includes \\.
+ this is a dark, horrible corner, but at least now i believe that
+ the behavior is the same as gawk and the intended posix standard.
+ thanks to arnold robbins for advice here.
+
+Aug 9, 1997:
+ somewhat regretfully, replaced the ancient lex-based lexical
+ analyzer with one written in C. it's longer, generates less code,
+ and more portable; the old one depended too much on mysterious
+ properties of lex that were not preserved in other environments.
+ in theory these recognize the same language.
+
+ now using strtod to test whether a string is a number, instead of
+ the convoluted original function. should be more portable and
+ reliable if strtod is implemented right.
+
+ removed now-pointless optimization in makefile that tries to avoid
+ recompilation when awkgram.y is changed but symbols are not.
+
+ removed most fixed-size arrays, though a handful remain, some
+ of which are unchecked. you have been warned.
+
+Aug 4, 1997:
+ with some trepidation, replaced the ancient code that managed
+ fields and $0 in fixed-size arrays with arrays that grow on
+ demand. there is still some tension between trying to make this
+ run fast and making it clean; not sure it's right yet.
+
+ the ill-conceived -mr and -mf arguments are now useful only
+ for debugging. previous dynamic string code removed.
+
+ numerous other minor cleanups along the way.
+
+Jul 30, 1997:
+ using code provided by dan levy (to whom profuse thanks), replaced
+ fixed-size arrays and awkward kludges by a fairly uniform mechanism
+ to grow arrays as needed for printf, sub, gsub, etc.
+
+Jul 23, 1997:
+ falling off the end of a function returns "" and 0, not 0.
+ thanks to arnold robbins.
+
+Jun 17, 1997:
+ replaced several fixed-size arrays by dynamically-created ones
+ in run.c; added overflow tests to some previously unchecked cases.
+ getline, toupper, tolower.
+
+ getline code is still broken in that recursive calls may wind
+ up using the same space. [fixed later]
+
+ increased RECSIZE to 8192 to push problems further over the horizon.
+
+ added \r to \n as input line separator for programs, not data.
+ damn CRLFs.
+
+ modified format() to permit explicit printf("%c", 0) to include
+ a null byte in output. thanks to ken stailey for the fix.
+
+ added a "-safe" argument that disables file output (print >,
+ print >>), process creation (cmd|getline, print |, system), and
+ access to the environment (ENVIRON). this is a first approximation
+ to a "safe" version of awk, but don't rely on it too much. thanks
+ to joan feigenbaum and matt blaze for the inspiration long ago.
+
+Jul 8, 1996:
+ fixed long-standing bug in sub, gsub(/a/, "\\\\&"); thanks to
+ ralph corderoy.
+
+Jun 29, 1996:
+ fixed awful bug in new field splitting; didn't get all the places
+ where input was done.
+
+Jun 28, 1996:
+ changed field-splitting to conform to posix definition: fields are
+ split using the value of FS at the time of input; it used to be
+ the value when the field or NF was first referred to, a much less
+ predictable definition. thanks to arnold robbins for encouragement
+ to do the right thing.
+
+May 28, 1996:
+ fixed appalling but apparently unimportant bug in parsing octal
+ numbers in reg exprs.
+
+ explicit hex in reg exprs now limited to 2 chars: \xa, \xaa.
+
+May 27, 1996:
+ cleaned up some declarations so gcc -Wall is now almost silent.
+
+ makefile now includes backup copies of ytab.c and lexyy.c in case
+ one makes before looking; it also avoids recreating lexyy.c unless
+ really needed.
+
+ s/aprintf/awkprint, s/asprintf/awksprintf/ to avoid some name clashes
+ with unwisely-written header files.
+
+ thanks to jeffrey friedl for several of these.
+
+May 26, 1996:
+ an attempt to rationalize the (unsigned) char issue. almost all
+ instances of unsigned char have been removed; the handful of places
+ in b.c where chars are used as table indices have been hand-crafted.
+ added some latin-1 tests to the regression, but i'm not confident;
+ none of my compilers seem to care much. thanks to nelson beebe for
+ pointing out some others that do care.
+
+May 2, 1996:
+ removed all register declarations.
+
+ enhanced split(), as in gawk, etc: split(s, a, "") splits s into
+ a[1]...a[length(s)] with each character a single element.
+
+ made the same changes for field-splitting if FS is "".
+
+ added nextfile, as in gawk: causes immediate advance to next
+ input file. (thanks to arnold robbins for inspiration and code).
+
+ small fixes to regexpr code: can now handle []], [[], and
+ variants; [] is now a syntax error, rather than matching
+ everything; [z-a] is now empty, not z. far from complete
+ or correct, however. (thanks to jeffrey friedl for pointing out
+ some awful behaviors.)
+
+Apr 29, 1996:
+ replaced uchar by uschar everwhere; apparently some compilers
+ usurp this name and this causes conflicts.
+
+ fixed call to time in run.c (bltin); arg is time_t *.
+
+ replaced horrible pointer/long punning in b.c by a legitimate
+ union. should be safer on 64-bit machines and cleaner everywhere.
+ (thanks to nelson beebe for pointing out some of these problems.)
+
+ replaced nested comments by #if 0...#endif in run.c, lib.c.
+
+ removed getsval, setsval, execute macros from run.c and lib.c.
+ machines are 100x faster than they were when these macros were
+ first used.
+
+ revised filenames: awk.g.y => awkgram.y, awk.lx.l => awklex.l,
+ y.tab.[ch] => ytab.[ch], lex.yy.c => lexyy.c, all in the aid of
+ portability to nameless systems.
+
+ "make bundle" now includes yacc and lex output files for recipients
+ who don't have yacc or lex.
+
+Aug 15, 1995:
+ initialized Cells in setsymtab more carefully; some fields
+ were not set. (thanks to purify, all of whose complaints i
+ think i now understand.)
+
+ fixed at least one error in gsub that looked at -1-th element
+ of an array when substituting for a null match (e.g., $).
+
+ delete arrayname is now legal; it clears the elements but leaves
+ the array, which may not be the right behavior.
+
+ modified makefile: my current make can't cope with the test used
+ to avoid unnecessary yacc invocations.
+
+Jul 17, 1995:
+ added dynamically growing strings to awk.lx.l and b.c
+ to permit regular expressions to be much bigger.
+ the state arrays can still overflow.
+
+Aug 24, 1994:
+ detect duplicate arguments in function definitions (mdm).
+
+May 11, 1994:
+ trivial fix to printf to limit string size in sub().
+
+Apr 22, 1994:
+ fixed yet another subtle self-assignment problem:
+ $1 = $2; $1 = $1 clobbered $1.
+
+ Regression tests now use private echo, to avoid quoting problems.
+
+Feb 2, 1994:
+ changed error() to print line number as %d, not %g.
+
+Jul 23, 1993:
+ cosmetic changes: increased sizes of some arrays,
+ reworded some error messages.
+
+ added CONVFMT as in posix (just replaced OFMT in getsval)
+
+ FILENAME is now "" until the first thing that causes a file
+ to be opened.
+
+Nov 28, 1992:
+ deleted yyunput and yyoutput from proto.h;
+ different versions of lex give these different declarations.
+
+May 31, 1992:
+ added -mr N and -mf N options: more record and fields.
+ these really ought to adjust automatically.
+
+ cleaned up some error messages; "out of space" now means
+ malloc returned NULL in all cases.
+
+ changed rehash so that if it runs out, it just returns;
+ things will continue to run slow, but maybe a bit longer.
+
+Apr 24, 1992:
+ remove redundant close of stdin when using -f -.
+
+ got rid of core dump with -d; awk -d just prints date.
+
+Apr 12, 1992:
+ added explicit check for /dev/std(in,out,err) in redirection.
+ unlike gawk, no /dev/fd/n yet.
+
+ added (file/pipe) builtin. hard to test satisfactorily.
+ not posix.
+
+Feb 20, 1992:
+ recompile after abortive changes; should be unchanged.
+
+Dec 2, 1991:
+ die-casting time: converted to ansi C, installed that.
+
+Nov 30, 1991:
+ fixed storage leak in freefa, failing to recover [N]CCL.
+ thanks to Bill Jones (jones@cs.usask.ca)
+
+Nov 19, 1991:
+ use RAND_MAX instead of literal in builtin().
+
+Nov 12, 1991:
+ cranked up some fixed-size arrays in b.c, and added a test for
+ overflow in penter. thanks to mark larsen.
+
+Sep 24, 1991:
+ increased buffer in gsub. a very crude fix to a general problem.
+ and again on Sep 26.
+
+Aug 18, 1991:
+ enforce variable name syntax for commandline variables: has to
+ start with letter or _.
+
+Jul 27, 1991:
+ allow newline after ; in for statements.
+
+Jul 21, 1991:
+ fixed so that in self-assignment like $1=$1, side effects
+ like recomputing $0 take place. (this is getting subtle.)
+
+Jun 30, 1991:
+ better test for detecting too-long output record.
+
+Jun 2, 1991:
+ better defense against very long printf strings.
+ made break and continue illegal outside of loops.
+
+May 13, 1991:
+ removed extra arg on gettemp, tempfree. minor error message rewording.
+
+May 6, 1991:
+ fixed silly bug in hex parsing in hexstr().
+ removed an apparently unnecessary test in isnumber().
+ warn about weird printf conversions.
+ fixed unchecked array overwrite in relex().
+
+ changed for (i in array) to access elements in sorted order.
+ then unchanged it -- it really does run slower in too many cases.
+ left the code in place, commented out.
+
+Feb 10, 1991:
+ check error status on all writes, to avoid banging on full disks.
+
+Jan 28, 1991:
+ awk -f - reads the program from stdin.
+
+Jan 11, 1991:
+ failed to set numeric state on $0 in cmd|getline context in run.c.
+
+Nov 2, 1990:
+ fixed sleazy test for integrality in getsval; use modf.
+
+Oct 29, 1990:
+ fixed sleazy buggy code in lib.c that looked (incorrectly) for
+ too long input lines.
+
+Oct 14, 1990:
+ fixed the bug on p. 198 in which it couldn't deduce that an
+ argument was an array in some contexts. replaced the error
+ message in intest() by code that damn well makes it an array.
+
+Oct 8, 1990:
+ fixed horrible bug: types and values were not preserved in
+ some kinds of self-assignment. (in assign().)
+
+Aug 24, 1990:
+ changed NCHARS to 256 to handle 8-bit characters in strings
+ presented to match(), etc.
+
+Jun 26, 1990:
+ changed struct rrow (awk.h) to use long instead of int for lval,
+ since cfoll() stores a pointer in it. now works better when int's
+ are smaller than pointers!
+
+May 6, 1990:
+ AVA fixed the grammar so that ! is uniformly of the same precedence as
+ unary + and -. This renders illegal some constructs like !x=y, which
+ now has to be parenthesized as !(x=y), and makes others work properly:
+ !x+y is (!x)+y, and x!y is x !y, not two pattern-action statements.
+ (These problems were pointed out by Bob Lenk of Posix.)
+
+ Added \x to regular expressions (already in strings).
+ Limited octal to octal digits; \8 and \9 are not octal.
+ Centralized the code for parsing escapes in regular expressions.
+ Added a bunch of tests to T.re and T.sub to verify some of this.
+
+Feb 9, 1990:
+ fixed null pointer dereference bug in main.c: -F[nothing]. sigh.
+
+ restored srand behavior: it returns the current seed.
+
+Jan 18, 1990:
+ srand now returns previous seed value (0 to start).
+
+Jan 5, 1990:
+ fix potential problem in tran.c -- something was freed,
+ then used in freesymtab.
+
+Oct 18, 1989:
+ another try to get the max number of open files set with
+ relatively machine-independent code.
+
+ small fix to input() in case of multiple reads after EOF.
+
+Oct 11, 1989:
+ FILENAME is now defined in the BEGIN block -- too many old
+ programs broke.
+
+ "-" means stdin in getline as well as on the commandline.
+
+ added a bunch of casts to the code to tell the truth about
+ char * vs. unsigned char *, a right royal pain. added a
+ setlocale call to the front of main, though probably no one
+ has it usefully implemented yet.
+
+Aug 24, 1989:
+ removed redundant relational tests against nullnode if parse
+ tree already had a relational at that point.
+
+Aug 11, 1989:
+ fixed bug: commandline variable assignment has to look like
+ var=something. (consider the man page for =, in file =.1)
+
+ changed number of arguments to functions to static arrays
+ to avoid repeated malloc calls.
+
+Aug 2, 1989:
+ restored -F (space) separator
+
+Jul 30, 1989:
+ added -v x=1 y=2 ... for immediate commandline variable assignment;
+ done before the BEGIN block for sure. they have to precede the
+ program if the program is on the commandline.
+ Modified Aug 2 to require a separate -v for each assignment.
+
+Jul 10, 1989:
+ fixed ref-thru-zero bug in environment code in tran.c
+
+Jun 23, 1989:
+ add newline to usage message.
+
+Jun 14, 1989:
+ added some missing ansi printf conversion letters: %i %X %E %G.
+ no sensible meaning for h or L, so they may not do what one expects.
+
+ made %* conversions work.
+
+ changed x^y so that if n is a positive integer, it's done
+ by explicit multiplication, thus achieving maximum accuracy.
+ (this should be done by pow() but it seems not to be locally.)
+ done to x ^= y as well.
+
+Jun 4, 1989:
+ ENVIRON array contains environment: if shell variable V=thing,
+ ENVIRON["V"] is "thing"
+
+ multiple -f arguments permitted. error reporting is naive.
+ (they were permitted before, but only the last was used.)
+
+ fixed a really stupid botch in the debugging macro dprintf
+
+ fixed order of evaluation of commandline assignments to match
+ what the book claims: an argument of the form x=e is evaluated
+ at the time it would have been opened if it were a filename (p 63).
+ this invalidates the suggested answer to ex 4-1 (p 195).
+
+ removed some code that permitted -F (space) fieldseparator,
+ since it didn't quite work right anyway. (restored aug 2)
+
+Apr 27, 1989:
+ Line number now accumulated correctly for comment lines.
+
+Apr 26, 1989:
+ Debugging output now includes a version date,
+ if one compiles it into the source each time.
+
+Apr 9, 1989:
+ Changed grammar to prohibit constants as 3rd arg of sub and gsub;
+ prevents class of overwriting-a-constant errors. (Last one?)
+ This invalidates the "banana" example on page 43 of the book.
+
+ Added \a ("alert"), \v (vertical tab), \xhhh (hexadecimal),
+ as in ANSI, for strings. Rescinded the sloppiness that permitted
+ non-octal digits in \ooo. Warning: not all compilers and libraries
+ will be able to deal with \x correctly.
+
+Jan 9, 1989:
+ Fixed bug that caused tempcell list to contain a duplicate.
+ The fix is kludgy.
+
+Dec 17, 1988:
+ Catches some more commandline errors in main.
+ Removed redundant decl of modf in run.c (confuses some compilers).
+ Warning: there's no single declaration of malloc, etc., in awk.h
+ that seems to satisfy all compilers.
+
+Dec 7, 1988:
+ Added a bit of code to error printing to avoid printing nulls.
+ (Not clear that it actually would.)
+
+Nov 27, 1988:
+ With fear and trembling, modified the grammar to permit
+ multiple pattern-action statements on one line without
+ an explicit separator. By definition, this capitulation
+ to the ghost of ancient implementations remains undefined
+ and thus subject to change without notice or apology.
+ DO NOT COUNT ON IT.
+
+Oct 30, 1988:
+ Fixed bug in call() that failed to recover storage.
+
+ A warning is now generated if there are more arguments
+ in the call than in the definition (in lieu of fixing
+ another storage leak).
+
+Oct 20, 1988:
+ Fixed %c: if expr is numeric, use numeric value;
+ otherwise print 1st char of string value. still
+ doesn't work if the value is 0 -- won't print \0.
+
+ Added a few more checks for running out of malloc.
+
+Oct 12, 1988:
+ Fixed bug in call() that freed local arrays twice.
+
+ Fixed to handle deletion of non-existent array right;
+ complains about attempt to delete non-array element.
+
+Sep 30, 1988:
+ Now guarantees to evaluate all arguments of built-in
+ functions, as in C; the appearance is that arguments
+ are evaluated before the function is called. Places
+ affected are sub (gsub was ok), substr, printf, and
+ all the built-in arithmetic functions in bltin().
+ A warning is generated if a bltin() is called with
+ the wrong number of arguments.
+
+ This requires changing makeprof on p167 of the book.
+
+Aug 23, 1988:
+ setting FILENAME in BEGIN caused core dump, apparently
+ because it was freeing space not allocated by malloc.
+
+July 24, 1988:
+ fixed egregious error in toupper/tolower functions.
+ still subject to rescinding, however.
+
+July 2, 1988:
+ flush stdout before opening file or pipe
+
+July 2, 1988:
+ performance bug in b.c/cgoto(): not freeing some sets of states.
+ partial fix only right now, and the number of states increased
+ to make it less obvious.
+
+June 1, 1988:
+ check error status on close
+
+May 28, 1988:
+ srand returns seed value it's using.
+ see 1/18/90
+
+May 22, 1988:
+ Removed limit on depth of function calls.
+
+May 10, 1988:
+ Fixed lib.c to permit _ in commandline variable names.
+
+Mar 25, 1988:
+ main.c fixed to recognize -- as terminator of command-
+ line options. Illegal options flagged.
+ Error reporting slightly cleaned up.
+
+Dec 2, 1987:
+ Newer C compilers apply a strict scope rule to extern
+ declarations within functions. Two extern declarations in
+ lib.c and tran.c have been moved to obviate this problem.
+
+Oct xx, 1987:
+ Reluctantly added toupper and tolower functions.
+ Subject to rescinding without notice.
+
+Sep 17, 1987:
+ Error-message printer had printf(s) instead of
+ printf("%s",s); got core dumps when the message
+ included a %.
+
+Sep 12, 1987:
+ Very long printf strings caused core dump;
+ fixed aprintf, asprintf, format to catch them.
+ Can still get a core dump in printf itself.
+
+
diff --git a/utils/awk/NOTICE b/utils/awk/NOTICE
new file mode 100644
index 00000000..790db512
--- /dev/null
+++ b/utils/awk/NOTICE
@@ -0,0 +1,7 @@
+This is a copy of Brian Kernighan's awk from netlib,
+which can be used on systems that don't provide a reasonably
+modern version of awk. Awk is needed for kernel builds,
+amongst other things.
+
+See the README for the terms
+under which it is distributed.
diff --git a/utils/awk/README b/utils/awk/README
new file mode 100644
index 00000000..bdb7e503
--- /dev/null
+++ b/utils/awk/README
@@ -0,0 +1,83 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+This is the version of awk described in "The AWK Programming Language",
+by Al Aho, Brian Kernighan, and Peter Weinberger
+(Addison-Wesley, 1988, ISBN 0-201-07981-X).
+
+Changes, mostly bug fixes and occasional enhancements, are listed
+in FIXES. If you distribute this code further, please please please
+distribute FIXES with it. If you find errors, please report them
+to bwk@bell-labs.com. Thanks.
+
+The program itself is created by
+ make
+which should produce a sequence of messages roughly like this:
+
+ yacc -d awkgram.y
+
+conflicts: 43 shift/reduce, 85 reduce/reduce
+ mv y.tab.c ytab.c
+ mv y.tab.h ytab.h
+ cc -O -c ytab.c
+ cc -O -c b.c
+ cc -O -c main.c
+ cc -O -c parse.c
+ cc -O maketab.c -o maketab
+ ./maketab >proctab.c
+ cc -O -c proctab.c
+ cc -O -c tran.c
+ cc -O -c lib.c
+ cc -O -c run.c
+ cc -O -c lex.c
+ cc -O ytab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm
+
+This produces an executable a.out; you will eventually want to
+move this to some place like /usr/bin/awk.
+
+If your system is does not have yacc or bison (the GNU
+equivalent), you must compile the pieces manually. We have
+included yacc output in ytab.c and ytab.h, and backup copies in
+case you overwrite them. We have also included a copy of
+proctab.c so you do not need to run maketab.
+
+NOTE: This version uses ANSI C, as you should also. We have
+compiled this without any changes using gcc -Wall and/or local C
+compilers on a variety of systems, but new systems or compilers
+may raise some new complaint; reports of difficulties are
+welcome.
+
+This also compiles with Visual C++ on Windows 95 and Windows NT,
+*if* you provide versions of popen and pclose. The file
+missing95.c contains versions that can be used to get started
+with, though the underlying support has mysterious properties,
+the symptom of which can be truncated pipe output. Beware.
+
+This is also said to compile on Macintosh systems, using the
+file "buildmac" provided by Dan Allen (danallen@microsoft.com),
+to whom many thanks. Dan also provided buildwin.bat, a simple
+script for compiling on NT if you prefer.
+
+The version of malloc that comes with some systems is sometimes
+astonishly slow. If awk seems slow, you might try fixing that.
diff --git a/utils/awk/awk.1 b/utils/awk/awk.1
new file mode 100644
index 00000000..6119613c
--- /dev/null
+++ b/utils/awk/awk.1
@@ -0,0 +1,529 @@
+.de EX
+.nf
+.ft CW
+..
+.de EE
+.br
+.fi
+.ft 1
+..
+awk
+.TH AWK 1
+.CT 1 files prog_other
+.SH NAME
+awk \- pattern-directed scanning and processing language
+.SH SYNOPSIS
+.B awk
+[
+.BI \-F
+.I fs
+]
+[
+.BI \-v
+.I var=value
+]
+[
+.I 'prog'
+|
+.BI \-f
+.I progfile
+]
+[
+.I file ...
+]
+.SH DESCRIPTION
+.I Awk
+scans each input
+.I file
+for lines that match any of a set of patterns specified literally in
+.IR prog
+or in one or more files
+specified as
+.B \-f
+.IR progfile .
+With each pattern
+there can be an associated action that will be performed
+when a line of a
+.I file
+matches the pattern.
+Each line is matched against the
+pattern portion of every pattern-action statement;
+the associated action is performed for each matched pattern.
+The file name
+.B \-
+means the standard input.
+Any
+.IR file
+of the form
+.I var=value
+is treated as an assignment, not a filename,
+and is executed at the time it would have been opened if it were a filename.
+The option
+.B \-v
+followed by
+.I var=value
+is an assignment to be done before
+.I prog
+is executed;
+any number of
+.B \-v
+options may be present.
+The
+.B \-F
+.IR fs
+option defines the input field separator to be the regular expression
+.IR fs.
+.PP
+An input line is normally made up of fields separated by white space,
+or by regular expression
+.BR FS .
+The fields are denoted
+.BR $1 ,
+.BR $2 ,
+\&..., while
+.B $0
+refers to the entire line.
+If
+.BR FS
+is null, the input line is split into one field per character.
+.PP
+A pattern-action statement has the form
+.IP
+.IB pattern " { " action " }
+.PP
+A missing
+.BI { " action " }
+means print the line;
+a missing pattern always matches.
+Pattern-action statements are separated by newlines or semicolons.
+.PP
+An action is a sequence of statements.
+A statement can be one of the following:
+.PP
+.EX
+.ta \w'\f(CWdelete array[expression]'u
+.RS
+.nf
+.ft CW
+if(\fI expression \fP)\fI statement \fP\fR[ \fPelse\fI statement \fP\fR]\fP
+while(\fI expression \fP)\fI statement\fP
+for(\fI expression \fP;\fI expression \fP;\fI expression \fP)\fI statement\fP
+for(\fI var \fPin\fI array \fP)\fI statement\fP
+do\fI statement \fPwhile(\fI expression \fP)
+break
+continue
+{\fR [\fP\fI statement ... \fP\fR] \fP}
+\fIexpression\fP #\fR commonly\fP\fI var = expression\fP
+print\fR [ \fP\fIexpression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP
+printf\fI format \fP\fR[ \fP,\fI expression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP
+return\fR [ \fP\fIexpression \fP\fR]\fP
+next #\fR skip remaining patterns on this input line\fP
+nextfile #\fR skip rest of this file, open next, start at top\fP
+delete\fI array\fP[\fI expression \fP] #\fR delete an array element\fP
+delete\fI array\fP #\fR delete all elements of array\fP
+exit\fR [ \fP\fIexpression \fP\fR]\fP #\fR exit immediately; status is \fP\fIexpression\fP
+.fi
+.RE
+.EE
+.DT
+.PP
+Statements are terminated by
+semicolons, newlines or right braces.
+An empty
+.I expression-list
+stands for
+.BR $0 .
+String constants are quoted \&\f(CW"\ "\fR,
+with the usual C escapes recognized within.
+Expressions take on string or numeric values as appropriate,
+and are built using the operators
+.B + \- * / % ^
+(exponentiation), and concatenation (indicated by white space).
+The operators
+.B
+! ++ \-\- += \-= *= /= %= ^= > >= < <= == != ?:
+are also available in expressions.
+Variables may be scalars, array elements
+(denoted
+.IB x [ i ] )
+or fields.
+Variables are initialized to the null string.
+Array subscripts may be any string,
+not necessarily numeric;
+this allows for a form of associative memory.
+Multiple subscripts such as
+.B [i,j,k]
+are permitted; the constituents are concatenated,
+separated by the value of
+.BR SUBSEP .
+.PP
+The
+.B print
+statement prints its arguments on the standard output
+(or on a file if
+.BI > file
+or
+.BI >> file
+is present or on a pipe if
+.BI | cmd
+is present), separated by the current output field separator,
+and terminated by the output record separator.
+.I file
+and
+.I cmd
+may be literal names or parenthesized expressions;
+identical string values in different statements denote
+the same open file.
+The
+.B printf
+statement formats its expression list according to the format
+(see
+.IR printf (3)) .
+The built-in function
+.BI close( expr )
+closes the file or pipe
+.IR expr .
+The built-in function
+.BI fflush( expr )
+flushes any buffered output for the file or pipe
+.IR expr .
+.PP
+The mathematical functions
+.BR exp ,
+.BR log ,
+.BR sqrt ,
+.BR sin ,
+.BR cos ,
+and
+.BR atan2
+are built in.
+Other built-in functions:
+.TF length
+.TP
+.B length
+the length of its argument
+taken as a string,
+or of
+.B $0
+if no argument.
+.TP
+.B rand
+random number on (0,1)
+.TP
+.B srand
+sets seed for
+.B rand
+and returns the previous seed.
+.TP
+.B int
+truncates to an integer value
+.TP
+.BI substr( s , " m" , " n\fB)
+the
+.IR n -character
+substring of
+.I s
+that begins at position
+.IR m
+counted from 1.
+.TP
+.BI index( s , " t" )
+the position in
+.I s
+where the string
+.I t
+occurs, or 0 if it does not.
+.TP
+.BI match( s , " r" )
+the position in
+.I s
+where the regular expression
+.I r
+occurs, or 0 if it does not.
+The variables
+.B RSTART
+and
+.B RLENGTH
+are set to the position and length of the matched string.
+.TP
+.BI split( s , " a" , " fs\fB)
+splits the string
+.I s
+into array elements
+.IB a [1] ,
+.IB a [2] ,
+\&...,
+.IB a [ n ] ,
+and returns
+.IR n .
+The separation is done with the regular expression
+.I fs
+or with the field separator
+.B FS
+if
+.I fs
+is not given.
+An empty string as field separator splits the string
+into one array element per character.
+.TP
+.BI sub( r , " t" , " s\fB)
+substitutes
+.I t
+for the first occurrence of the regular expression
+.I r
+in the string
+.IR s .
+If
+.I s
+is not given,
+.B $0
+is used.
+.TP
+.B gsub
+same as
+.B sub
+except that all occurrences of the regular expression
+are replaced;
+.B sub
+and
+.B gsub
+return the number of replacements.
+.TP
+.BI sprintf( fmt , " expr" , " ...\fB )
+the string resulting from formatting
+.I expr ...
+according to the
+.IR printf (3)
+format
+.I fmt
+.TP
+.BI system( cmd )
+executes
+.I cmd
+and returns its exit status
+.TP
+.BI tolower( str )
+returns a copy of
+.I str
+with all upper-case characters translated to their
+corresponding lower-case equivalents.
+.TP
+.BI toupper( str )
+returns a copy of
+.I str
+with all lower-case characters translated to their
+corresponding upper-case equivalents.
+.PD
+.PP
+The ``function''
+.B getline
+sets
+.B $0
+to the next input record from the current input file;
+.B getline
+.BI < file
+sets
+.B $0
+to the next record from
+.IR file .
+.B getline
+.I x
+sets variable
+.I x
+instead.
+Finally,
+.IB cmd " | getline
+pipes the output of
+.I cmd
+into
+.BR getline ;
+each call of
+.B getline
+returns the next line of output from
+.IR cmd .
+In all cases,
+.B getline
+returns 1 for a successful input,
+0 for end of file, and \-1 for an error.
+.PP
+Patterns are arbitrary Boolean combinations
+(with
+.BR "! || &&" )
+of regular expressions and
+relational expressions.
+Regular expressions are as in
+.IR egrep ;
+see
+.IR grep (1).
+Isolated regular expressions
+in a pattern apply to the entire line.
+Regular expressions may also occur in
+relational expressions, using the operators
+.BR ~
+and
+.BR !~ .
+.BI / re /
+is a constant regular expression;
+any string (constant or variable) may be used
+as a regular expression, except in the position of an isolated regular expression
+in a pattern.
+.PP
+A pattern may consist of two patterns separated by a comma;
+in this case, the action is performed for all lines
+from an occurrence of the first pattern
+though an occurrence of the second.
+.PP
+A relational expression is one of the following:
+.IP
+.I expression matchop regular-expression
+.br
+.I expression relop expression
+.br
+.IB expression " in " array-name
+.br
+.BI ( expr , expr,... ") in " array-name
+.PP
+where a relop is any of the six relational operators in C,
+and a matchop is either
+.B ~
+(matches)
+or
+.B !~
+(does not match).
+A conditional is an arithmetic expression,
+a relational expression,
+or a Boolean combination
+of these.
+.PP
+The special patterns
+.B BEGIN
+and
+.B END
+may be used to capture control before the first input line is read
+and after the last.
+.B BEGIN
+and
+.B END
+do not combine with other patterns.
+.PP
+Variable names with special meanings:
+.TF FILENAME
+.TP
+.B CONVFMT
+conversion format used when converting numbers
+(default
+.BR "%.6g" )
+.TP
+.B FS
+regular expression used to separate fields; also settable
+by option
+.BI \-F fs.
+.TP
+.BR NF
+number of fields in the current record
+.TP
+.B NR
+ordinal number of the current record
+.TP
+.B FNR
+ordinal number of the current record in the current file
+.TP
+.B FILENAME
+the name of the current input file
+.TP
+.B RS
+input record separator (default newline)
+.TP
+.B OFS
+output field separator (default blank)
+.TP
+.B ORS
+output record separator (default newline)
+.TP
+.B OFMT
+output format for numbers (default
+.BR "%.6g" )
+.TP
+.B SUBSEP
+separates multiple subscripts (default 034)
+.TP
+.B ARGC
+argument count, assignable
+.TP
+.B ARGV
+argument array, assignable;
+non-null members are taken as filenames
+.TP
+.B ENVIRON
+array of environment variables; subscripts are names.
+.PD
+.PP
+Functions may be defined (at the position of a pattern-action statement) thus:
+.IP
+.B
+function foo(a, b, c) { ...; return x }
+.PP
+Parameters are passed by value if scalar and by reference if array name;
+functions may be called recursively.
+Parameters are local to the function; all other variables are global.
+Thus local variables may be created by providing excess parameters in
+the function definition.
+.SH EXAMPLES
+.TP
+.EX
+length($0) > 72
+.EE
+Print lines longer than 72 characters.
+.TP
+.EX
+{ print $2, $1 }
+.EE
+Print first two fields in opposite order.
+.PP
+.EX
+BEGIN { FS = ",[ \et]*|[ \et]+" }
+ { print $2, $1 }
+.EE
+.ns
+.IP
+Same, with input fields separated by comma and/or blanks and tabs.
+.PP
+.EX
+.nf
+ { s += $1 }
+END { print "sum is", s, " average is", s/NR }
+.fi
+.EE
+.ns
+.IP
+Add up first column, print sum and average.
+.TP
+.EX
+/start/, /stop/
+.EE
+Print all lines between start/stop pairs.
+.PP
+.EX
+.nf
+BEGIN { # Simulate echo(1)
+ for (i = 1; i < ARGC; i++) printf "%s ", ARGV[i]
+ printf "\en"
+ exit }
+.fi
+.EE
+.SH SEE ALSO
+.IR lex (1),
+.IR sed (1)
+.br
+A. V. Aho, B. W. Kernighan, P. J. Weinberger,
+.I
+The AWK Programming Language,
+Addison-Wesley, 1988. ISBN 0-201-07981-X
+.SH BUGS
+There are no explicit conversions between numbers and strings.
+To force an expression to be treated as a number add 0 to it;
+to force it to be treated as a string concatenate
+\&\f(CW""\fP to it.
+.br
+The scope rules for variables in functions are a botch;
+the syntax is worse.
diff --git a/utils/awk/awk.h b/utils/awk/awk.h
new file mode 100644
index 00000000..25fed144
--- /dev/null
+++ b/utils/awk/awk.h
@@ -0,0 +1,231 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+typedef double Awkfloat;
+
+/* unsigned char is more trouble than it's worth */
+
+typedef unsigned char uschar;
+
+#define xfree(a) { if ((a) != NULL) { free((char *) a); a = NULL; } }
+
+#define DEBUG
+#ifdef DEBUG
+ /* uses have to be doubly parenthesized */
+# define dprintf(x) if (dbg) printf x
+#else
+# define dprintf(x)
+#endif
+
+extern char errbuf[];
+
+extern int compile_time; /* 1 if compiling, 0 if running */
+extern int safe; /* 0 => unsafe, 1 => safe */
+
+#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */
+extern int recsize; /* size of current record, orig RECSIZE */
+
+extern char **FS;
+extern char **RS;
+extern char **ORS;
+extern char **OFS;
+extern char **OFMT;
+extern Awkfloat *NR;
+extern Awkfloat *FNR;
+extern Awkfloat *NF;
+extern char **FILENAME;
+extern char **SUBSEP;
+extern Awkfloat *RSTART;
+extern Awkfloat *RLENGTH;
+
+extern char *record; /* points to $0 */
+extern int lineno; /* line number in awk program */
+extern int errorflag; /* 1 if error has occurred */
+extern int donefld; /* 1 if record broken into fields */
+extern int donerec; /* 1 if record is valid (no fld has changed */
+extern char inputFS[]; /* FS at time of input, for field splitting */
+
+extern int dbg;
+
+extern char *patbeg; /* beginning of pattern matched */
+extern int patlen; /* length of pattern matched. set in b.c */
+
+/* Cell: all information about a variable or constant */
+
+typedef struct Cell {
+ uschar ctype; /* OCELL, OBOOL, OJUMP, etc. */
+ uschar csub; /* CCON, CTEMP, CFLD, etc. */
+ char *nval; /* name, for variables only */
+ char *sval; /* string value */
+ Awkfloat fval; /* value as number */
+ int tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE */
+ struct Cell *cnext; /* ptr to next if chained */
+} Cell;
+
+typedef struct Array { /* symbol table array */
+ int nelem; /* elements in table right now */
+ int size; /* size of tab */
+ Cell **tab; /* hash table pointers */
+} Array;
+
+#define NSYMTAB 50 /* initial size of a symbol table */
+extern Array *symtab;
+
+extern Cell *nrloc; /* NR */
+extern Cell *fnrloc; /* FNR */
+extern Cell *nfloc; /* NF */
+extern Cell *rstartloc; /* RSTART */
+extern Cell *rlengthloc; /* RLENGTH */
+
+/* Cell.tval values: */
+#define NUM 01 /* number value is valid */
+#define STR 02 /* string value is valid */
+#define DONTFREE 04 /* string space is not freeable */
+#define CON 010 /* this is a constant */
+#define ARR 020 /* this is an array */
+#define FCN 040 /* this is a function name */
+#define FLD 0100 /* this is a field $1, $2, ... */
+#define REC 0200 /* this is $0 */
+
+
+/* function types */
+#define FLENGTH 1
+#define FSQRT 2
+#define FEXP 3
+#define FLOG 4
+#define FINT 5
+#define FSYSTEM 6
+#define FRAND 7
+#define FSRAND 8
+#define FSIN 9
+#define FCOS 10
+#define FATAN 11
+#define FTOUPPER 12
+#define FTOLOWER 13
+#define FFLUSH 14
+
+/* Node: parse tree is made of nodes, with Cell's at bottom */
+
+typedef struct Node {
+ int ntype;
+ struct Node *nnext;
+ int lineno;
+ int nobj;
+ struct Node *narg[1]; /* variable: actual size set by calling malloc */
+} Node;
+
+#define NIL ((Node *) 0)
+
+extern Node *winner;
+extern Node *nullstat;
+extern Node *nullnode;
+
+/* ctypes */
+#define OCELL 1
+#define OBOOL 2
+#define OJUMP 3
+
+/* Cell subtypes: csub */
+#define CFREE 7
+#define CCOPY 6
+#define CCON 5
+#define CTEMP 4
+#define CNAME 3
+#define CVAR 2
+#define CFLD 1
+#define CUNK 0
+
+/* bool subtypes */
+#define BTRUE 11
+#define BFALSE 12
+
+/* jump subtypes */
+#define JEXIT 21
+#define JNEXT 22
+#define JBREAK 23
+#define JCONT 24
+#define JRET 25
+#define JNEXTFILE 26
+
+/* node types */
+#define NVALUE 1
+#define NSTAT 2
+#define NEXPR 3
+
+
+extern int pairstack[], paircnt;
+
+#define notlegal(n) (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN] == nullproc)
+#define isvalue(n) ((n)->ntype == NVALUE)
+#define isexpr(n) ((n)->ntype == NEXPR)
+#define isjump(n) ((n)->ctype == OJUMP)
+#define isexit(n) ((n)->csub == JEXIT)
+#define isbreak(n) ((n)->csub == JBREAK)
+#define iscont(n) ((n)->csub == JCONT)
+#define isnext(n) ((n)->csub == JNEXT || (n)->csub == JNEXTFILE)
+#define isret(n) ((n)->csub == JRET)
+#define isrec(n) ((n)->tval & REC)
+#define isfld(n) ((n)->tval & FLD)
+#define isstr(n) ((n)->tval & STR)
+#define isnum(n) ((n)->tval & NUM)
+#define isarr(n) ((n)->tval & ARR)
+#define isfcn(n) ((n)->tval & FCN)
+#define istrue(n) ((n)->csub == BTRUE)
+#define istemp(n) ((n)->csub == CTEMP)
+#define isargument(n) ((n)->nobj == ARG)
+/* #define freeable(p) (!((p)->tval & DONTFREE)) */
+#define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR )
+
+/* structures used by regular expression matching machinery, mostly b.c: */
+
+#define NCHARS (256+1) /* 256 handles 8-bit chars; 128 does 7-bit */
+ /* watch out in match(), etc. */
+#define NSTATES 32
+
+typedef struct rrow {
+ long ltype; /* long avoids pointer warnings on 64-bit */
+ union {
+ int i;
+ Node *np;
+ uschar *up;
+ } lval; /* because Al stores a pointer in it! */
+ int *lfollow;
+} rrow;
+
+typedef struct fa {
+ uschar gototab[NSTATES][NCHARS];
+ uschar out[NSTATES];
+ uschar *restr;
+ int *posns[NSTATES];
+ int anchor;
+ int use;
+ int initstat;
+ int curstat;
+ int accept;
+ int reset;
+ struct rrow re[1]; /* variable: actual size set by calling malloc */
+} fa;
+
+
+#include "proto.h"
diff --git a/utils/awk/awkgram.y b/utils/awk/awkgram.y
new file mode 100644
index 00000000..f9f6fd28
--- /dev/null
+++ b/utils/awk/awkgram.y
@@ -0,0 +1,486 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+%{
+#include <stdio.h>
+#include <string.h>
+#include "awk.h"
+
+void checkdup(Node *list, Cell *item);
+int yywrap(void) { return(1); }
+
+Node *beginloc = 0;
+Node *endloc = 0;
+int infunc = 0; /* = 1 if in arglist or body of func */
+int inloop = 0; /* = 1 if in while, for, do */
+char *curfname = 0; /* current function name */
+Node *arglist = 0; /* list of args for current function */
+%}
+
+%union {
+ Node *p;
+ Cell *cp;
+ int i;
+ char *s;
+}
+
+%token <i> FIRSTTOKEN /* must be first */
+%token <p> PROGRAM PASTAT PASTAT2 XBEGIN XEND
+%token <i> NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
+%token <i> ARRAY
+%token <i> MATCH NOTMATCH MATCHOP
+%token <i> FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS
+%token <i> AND BOR APPEND EQ GE GT LE LT NE IN
+%token <i> ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
+%token <i> SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
+%token <i> ADD MINUS MULT DIVIDE MOD
+%token <i> ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ
+%token <i> PRINT PRINTF SPRINTF
+%token <p> ELSE INTEST CONDEXPR
+%token <i> POSTINCR PREINCR POSTDECR PREDECR
+%token <cp> VAR IVAR VARNF CALL NUMBER STRING
+%token <s> REGEXPR
+
+%type <p> pas pattern ppattern plist pplist patlist prarg term re
+%type <p> pa_pat pa_stat pa_stats
+%type <s> reg_expr
+%type <p> simple_stmt opt_simple_stmt stmt stmtlist
+%type <p> var varname funcname varlist
+%type <p> for if else while
+%type <i> do st
+%type <i> pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
+%type <i> subop print
+
+%right ASGNOP
+%right '?'
+%right ':'
+%left BOR
+%left AND
+%left GETLINE
+%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
+%left ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC
+%left GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
+%left PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
+%left REGEXPR VAR VARNF IVAR WHILE '('
+%left CAT
+%left '+' '-'
+%left '*' '/' '%'
+%left NOT UMINUS
+%right POWER
+%right DECR INCR
+%left INDIRECT
+%token LASTTOKEN /* must be last */
+
+%%
+
+program:
+ pas { if (errorflag==0)
+ winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); }
+ | error { yyclearin; bracecheck(); SYNTAX("bailing out"); }
+ ;
+
+and:
+ AND | and NL
+ ;
+
+bor:
+ BOR | bor NL
+ ;
+
+comma:
+ ',' | comma NL
+ ;
+
+do:
+ DO | do NL
+ ;
+
+else:
+ ELSE | else NL
+ ;
+
+for:
+ FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
+ { --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); }
+ | FOR '(' opt_simple_stmt ';' ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
+ { --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); }
+ | FOR '(' varname IN varname rparen {inloop++;} stmt
+ { --inloop; $$ = stat3(IN, $3, makearr($5), $8); }
+ ;
+
+funcname:
+ VAR { setfname($1); }
+ | CALL { setfname($1); }
+ ;
+
+if:
+ IF '(' pattern rparen { $$ = notnull($3); }
+ ;
+
+lbrace:
+ '{' | lbrace NL
+ ;
+
+nl:
+ NL | nl NL
+ ;
+
+opt_nl:
+ /* empty */ { $$ = 0; }
+ | nl
+ ;
+
+opt_pst:
+ /* empty */ { $$ = 0; }
+ | pst
+ ;
+
+
+opt_simple_stmt:
+ /* empty */ { $$ = 0; }
+ | simple_stmt
+ ;
+
+pas:
+ opt_pst { $$ = 0; }
+ | opt_pst pa_stats opt_pst { $$ = $2; }
+ ;
+
+pa_pat:
+ pattern { $$ = notnull($1); }
+ ;
+
+pa_stat:
+ pa_pat { $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); }
+ | pa_pat lbrace stmtlist '}' { $$ = stat2(PASTAT, $1, $3); }
+ | pa_pat ',' pa_pat { $$ = pa2stat($1, $3, stat2(PRINT, rectonode(), NIL)); }
+ | pa_pat ',' pa_pat lbrace stmtlist '}' { $$ = pa2stat($1, $3, $5); }
+ | lbrace stmtlist '}' { $$ = stat2(PASTAT, NIL, $2); }
+ | XBEGIN lbrace stmtlist '}'
+ { beginloc = linkum(beginloc, $3); $$ = 0; }
+ | XEND lbrace stmtlist '}'
+ { endloc = linkum(endloc, $3); $$ = 0; }
+ | FUNC funcname '(' varlist rparen {infunc++;} lbrace stmtlist '}'
+ { infunc--; curfname=0; defn((Cell *)$2, $4, $8); $$ = 0; }
+ ;
+
+pa_stats:
+ pa_stat
+ | pa_stats opt_pst pa_stat { $$ = linkum($1, $3); }
+ ;
+
+patlist:
+ pattern
+ | patlist comma pattern { $$ = linkum($1, $3); }
+ ;
+
+ppattern:
+ var ASGNOP ppattern { $$ = op2($2, $1, $3); }
+ | ppattern '?' ppattern ':' ppattern %prec '?'
+ { $$ = op3(CONDEXPR, notnull($1), $3, $5); }
+ | ppattern bor ppattern %prec BOR
+ { $$ = op2(BOR, notnull($1), notnull($3)); }
+ | ppattern and ppattern %prec AND
+ { $$ = op2(AND, notnull($1), notnull($3)); }
+ | ppattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
+ | ppattern MATCHOP ppattern
+ { if (constnode($3))
+ $$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
+ else
+ $$ = op3($2, (Node *)1, $1, $3); }
+ | ppattern IN varname { $$ = op2(INTEST, $1, makearr($3)); }
+ | '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); }
+ | ppattern term %prec CAT { $$ = op2(CAT, $1, $2); }
+ | re
+ | term
+ ;
+
+pattern:
+ var ASGNOP pattern { $$ = op2($2, $1, $3); }
+ | pattern '?' pattern ':' pattern %prec '?'
+ { $$ = op3(CONDEXPR, notnull($1), $3, $5); }
+ | pattern bor pattern %prec BOR
+ { $$ = op2(BOR, notnull($1), notnull($3)); }
+ | pattern and pattern %prec AND
+ { $$ = op2(AND, notnull($1), notnull($3)); }
+ | pattern EQ pattern { $$ = op2($2, $1, $3); }
+ | pattern GE pattern { $$ = op2($2, $1, $3); }
+ | pattern GT pattern { $$ = op2($2, $1, $3); }
+ | pattern LE pattern { $$ = op2($2, $1, $3); }
+ | pattern LT pattern { $$ = op2($2, $1, $3); }
+ | pattern NE pattern { $$ = op2($2, $1, $3); }
+ | pattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
+ | pattern MATCHOP pattern
+ { if (constnode($3))
+ $$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
+ else
+ $$ = op3($2, (Node *)1, $1, $3); }
+ | pattern IN varname { $$ = op2(INTEST, $1, makearr($3)); }
+ | '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); }
+ | pattern '|' GETLINE var {
+ if (safe) SYNTAX("cmd | getline is unsafe");
+ else $$ = op3(GETLINE, $4, itonp($2), $1); }
+ | pattern '|' GETLINE {
+ if (safe) SYNTAX("cmd | getline is unsafe");
+ else $$ = op3(GETLINE, (Node*)0, itonp($2), $1); }
+ | pattern term %prec CAT { $$ = op2(CAT, $1, $2); }
+ | re
+ | term
+ ;
+
+plist:
+ pattern comma pattern { $$ = linkum($1, $3); }
+ | plist comma pattern { $$ = linkum($1, $3); }
+ ;
+
+pplist:
+ ppattern
+ | pplist comma ppattern { $$ = linkum($1, $3); }
+ ;
+
+prarg:
+ /* empty */ { $$ = rectonode(); }
+ | pplist
+ | '(' plist ')' { $$ = $2; }
+ ;
+
+print:
+ PRINT | PRINTF
+ ;
+
+pst:
+ NL | ';' | pst NL | pst ';'
+ ;
+
+rbrace:
+ '}' | rbrace NL
+ ;
+
+re:
+ reg_expr
+ { $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
+ | NOT re { $$ = op1(NOT, notnull($2)); }
+ ;
+
+reg_expr:
+ '/' {startreg();} REGEXPR '/' { $$ = $3; }
+ ;
+
+rparen:
+ ')' | rparen NL
+ ;
+
+simple_stmt:
+ print prarg '|' term {
+ if (safe) SYNTAX("print | is unsafe");
+ else $$ = stat3($1, $2, itonp($3), $4); }
+ | print prarg APPEND term {
+ if (safe) SYNTAX("print >> is unsafe");
+ else $$ = stat3($1, $2, itonp($3), $4); }
+ | print prarg GT term {
+ if (safe) SYNTAX("print > is unsafe");
+ else $$ = stat3($1, $2, itonp($3), $4); }
+ | print prarg { $$ = stat3($1, $2, NIL, NIL); }
+ | DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); }
+ | DELETE varname { $$ = stat2(DELETE, makearr($2), 0); }
+ | pattern { $$ = exptostat($1); }
+ | error { yyclearin; SYNTAX("illegal statement"); }
+ ;
+
+st:
+ nl
+ | ';' opt_nl
+ ;
+
+stmt:
+ BREAK st { if (!inloop) SYNTAX("break illegal outside of loops");
+ $$ = stat1(BREAK, NIL); }
+ | CONTINUE st { if (!inloop) SYNTAX("continue illegal outside of loops");
+ $$ = stat1(CONTINUE, NIL); }
+ | do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st
+ { $$ = stat2(DO, $3, notnull($7)); }
+ | EXIT pattern st { $$ = stat1(EXIT, $2); }
+ | EXIT st { $$ = stat1(EXIT, NIL); }
+ | for
+ | if stmt else stmt { $$ = stat3(IF, $1, $2, $4); }
+ | if stmt { $$ = stat3(IF, $1, $2, NIL); }
+ | lbrace stmtlist rbrace { $$ = $2; }
+ | NEXT st { if (infunc)
+ SYNTAX("next is illegal inside a function");
+ $$ = stat1(NEXT, NIL); }
+ | NEXTFILE st { if (infunc)
+ SYNTAX("nextfile is illegal inside a function");
+ $$ = stat1(NEXTFILE, NIL); }
+ | RETURN pattern st { $$ = stat1(RETURN, $2); }
+ | RETURN st { $$ = stat1(RETURN, NIL); }
+ | simple_stmt st
+ | while {inloop++;} stmt { --inloop; $$ = stat2(WHILE, $1, $3); }
+ | ';' opt_nl { $$ = 0; }
+ ;
+
+stmtlist:
+ stmt
+ | stmtlist stmt { $$ = linkum($1, $2); }
+ ;
+
+subop:
+ SUB | GSUB
+ ;
+
+term:
+ term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); }
+ | term '+' term { $$ = op2(ADD, $1, $3); }
+ | term '-' term { $$ = op2(MINUS, $1, $3); }
+ | term '*' term { $$ = op2(MULT, $1, $3); }
+ | term '/' term { $$ = op2(DIVIDE, $1, $3); }
+ | term '%' term { $$ = op2(MOD, $1, $3); }
+ | term POWER term { $$ = op2(POWER, $1, $3); }
+ | '-' term %prec UMINUS { $$ = op1(UMINUS, $2); }
+ | '+' term %prec UMINUS { $$ = $2; }
+ | NOT term %prec UMINUS { $$ = op1(NOT, notnull($2)); }
+ | BLTIN '(' ')' { $$ = op2(BLTIN, itonp($1), rectonode()); }
+ | BLTIN '(' patlist ')' { $$ = op2(BLTIN, itonp($1), $3); }
+ | BLTIN { $$ = op2(BLTIN, itonp($1), rectonode()); }
+ | CALL '(' ')' { $$ = op2(CALL, celltonode($1,CVAR), NIL); }
+ | CALL '(' patlist ')' { $$ = op2(CALL, celltonode($1,CVAR), $3); }
+ | CLOSE term { $$ = op1(CLOSE, $2); }
+ | DECR var { $$ = op1(PREDECR, $2); }
+ | INCR var { $$ = op1(PREINCR, $2); }
+ | var DECR { $$ = op1(POSTDECR, $1); }
+ | var INCR { $$ = op1(POSTINCR, $1); }
+ | GETLINE var LT term { $$ = op3(GETLINE, $2, itonp($3), $4); }
+ | GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($2), $3); }
+ | GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); }
+ | GETLINE { $$ = op3(GETLINE, NIL, NIL, NIL); }
+ | INDEX '(' pattern comma pattern ')'
+ { $$ = op2(INDEX, $3, $5); }
+ | INDEX '(' pattern comma reg_expr ')'
+ { SYNTAX("index() doesn't permit regular expressions");
+ $$ = op2(INDEX, $3, (Node*)$5); }
+ | '(' pattern ')' { $$ = $2; }
+ | MATCHFCN '(' pattern comma reg_expr ')'
+ { $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); }
+ | MATCHFCN '(' pattern comma pattern ')'
+ { if (constnode($5))
+ $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1));
+ else
+ $$ = op3(MATCHFCN, (Node *)1, $3, $5); }
+ | NUMBER { $$ = celltonode($1, CCON); }
+ | SPLIT '(' pattern comma varname comma pattern ')' /* string */
+ { $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); }
+ | SPLIT '(' pattern comma varname comma reg_expr ')' /* const /regexp/ */
+ { $$ = op4(SPLIT, $3, makearr($5), (Node*)makedfa($7, 1), (Node *)REGEXPR); }
+ | SPLIT '(' pattern comma varname ')'
+ { $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */
+ | SPRINTF '(' patlist ')' { $$ = op1($1, $3); }
+ | STRING { $$ = celltonode($1, CCON); }
+ | subop '(' reg_expr comma pattern ')'
+ { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
+ | subop '(' pattern comma pattern ')'
+ { if (constnode($3))
+ $$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode());
+ else
+ $$ = op4($1, (Node *)1, $3, $5, rectonode()); }
+ | subop '(' reg_expr comma pattern comma var ')'
+ { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); }
+ | subop '(' pattern comma pattern comma var ')'
+ { if (constnode($3))
+ $$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7);
+ else
+ $$ = op4($1, (Node *)1, $3, $5, $7); }
+ | SUBSTR '(' pattern comma pattern comma pattern ')'
+ { $$ = op3(SUBSTR, $3, $5, $7); }
+ | SUBSTR '(' pattern comma pattern ')'
+ { $$ = op3(SUBSTR, $3, $5, NIL); }
+ | var
+ ;
+
+var:
+ varname
+ | varname '[' patlist ']' { $$ = op2(ARRAY, makearr($1), $3); }
+ | IVAR { $$ = op1(INDIRECT, celltonode($1, CVAR)); }
+ | INDIRECT term { $$ = op1(INDIRECT, $2); }
+ ;
+
+varlist:
+ /* nothing */ { arglist = $$ = 0; }
+ | VAR { arglist = $$ = celltonode($1,CVAR); }
+ | varlist comma VAR {
+ checkdup($1, $3);
+ arglist = $$ = linkum($1,celltonode($3,CVAR)); }
+ ;
+
+varname:
+ VAR { $$ = celltonode($1, CVAR); }
+ | ARG { $$ = op1(ARG, itonp($1)); }
+ | VARNF { $$ = op1(VARNF, (Node *) $1); }
+ ;
+
+
+while:
+ WHILE '(' pattern rparen { $$ = notnull($3); }
+ ;
+
+%%
+
+void setfname(Cell *p)
+{
+ if (isarr(p))
+ SYNTAX("%s is an array, not a function", p->nval);
+ else if (isfcn(p))
+ SYNTAX("you can't define function %s more than once", p->nval);
+ curfname = p->nval;
+}
+
+int constnode(Node *p)
+{
+ return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON;
+}
+
+char *strnode(Node *p)
+{
+ return ((Cell *)(p->narg[0]))->sval;
+}
+
+Node *notnull(Node *n)
+{
+ switch (n->nobj) {
+ case LE: case LT: case EQ: case NE: case GT: case GE:
+ case BOR: case AND: case NOT:
+ return n;
+ default:
+ return op2(NE, n, nullnode);
+ }
+}
+
+void checkdup(Node *vl, Cell *cp) /* check if name already in list */
+{
+ char *s = cp->nval;
+ for ( ; vl; vl = vl->nnext) {
+ if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) {
+ SYNTAX("duplicate argument %s", s);
+ break;
+ }
+ }
+}
diff --git a/utils/awk/b.c b/utils/awk/b.c
new file mode 100644
index 00000000..3153151f
--- /dev/null
+++ b/utils/awk/b.c
@@ -0,0 +1,855 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+/* lasciate ogne speranza, voi ch'entrate. */
+
+#define DEBUG
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "awk.h"
+#include "ytab.h"
+
+#define HAT (NCHARS-2) /* matches ^ in regular expr */
+ /* NCHARS is 2**n */
+#define MAXLIN 22
+
+#define type(v) (v)->nobj /* badly overloaded here */
+#define info(v) (v)->ntype /* badly overloaded here */
+#define left(v) (v)->narg[0]
+#define right(v) (v)->narg[1]
+#define parent(v) (v)->nnext
+
+#define LEAF case CCL: case NCCL: case CHAR: case DOT: case FINAL: case ALL:
+#define UNARY case STAR: case PLUS: case QUEST:
+
+/* encoding in tree Nodes:
+ leaf (CCL, NCCL, CHAR, DOT, FINAL, ALL):
+ left is index, right contains value or pointer to value
+ unary (STAR, PLUS, QUEST): left is child, right is null
+ binary (CAT, OR): left and right are children
+ parent contains pointer to parent
+*/
+
+
+int *setvec;
+int *tmpset;
+int maxsetvec = 0;
+
+int rtok; /* next token in current re */
+int rlxval;
+static uschar *rlxstr;
+static uschar *prestr; /* current position in current re */
+static uschar *lastre; /* origin of last re */
+
+static int setcnt;
+static int poscnt;
+
+char *patbeg;
+int patlen;
+
+#define NFA 20 /* cache this many dynamic fa's */
+fa *fatab[NFA];
+int nfatab = 0; /* entries in fatab */
+
+fa *makedfa(char *s, int anchor) /* returns dfa for reg expr s */
+{
+ int i, use, nuse;
+ fa *pfa;
+ static int now = 1;
+
+ if (setvec == 0) { /* first time through any RE */
+ maxsetvec = MAXLIN;
+ setvec = (int *) malloc(maxsetvec * sizeof(int));
+ tmpset = (int *) malloc(maxsetvec * sizeof(int));
+ if (setvec == 0 || tmpset == 0)
+ overflo("out of space initializing makedfa");
+ }
+
+ if (compile_time) /* a constant for sure */
+ return mkdfa(s, anchor);
+ for (i = 0; i < nfatab; i++) /* is it there already? */
+ if (fatab[i]->anchor == anchor
+ && strcmp(fatab[i]->restr, s) == 0) {
+ fatab[i]->use = now++;
+ return fatab[i];
+ }
+ pfa = mkdfa(s, anchor);
+ if (nfatab < NFA) { /* room for another */
+ fatab[nfatab] = pfa;
+ fatab[nfatab]->use = now++;
+ nfatab++;
+ return pfa;
+ }
+ use = fatab[0]->use; /* replace least-recently used */
+ nuse = 0;
+ for (i = 1; i < nfatab; i++)
+ if (fatab[i]->use < use) {
+ use = fatab[i]->use;
+ nuse = i;
+ }
+ freefa(fatab[nuse]);
+ fatab[nuse] = pfa;
+ pfa->use = now++;
+ return pfa;
+}
+
+fa *mkdfa(char *s, int anchor) /* does the real work of making a dfa */
+ /* anchor = 1 for anchored matches, else 0 */
+{
+ Node *p, *p1;
+ fa *f;
+
+ p = reparse(s);
+ p1 = op2(CAT, op2(STAR, op2(ALL, NIL, NIL), NIL), p);
+ /* put ALL STAR in front of reg. exp. */
+ p1 = op2(CAT, p1, op2(FINAL, NIL, NIL));
+ /* put FINAL after reg. exp. */
+
+ poscnt = 0;
+ penter(p1); /* enter parent pointers and leaf indices */
+ if ((f = (fa *) calloc(1, sizeof(fa) + poscnt*sizeof(rrow))) == NULL)
+ overflo("out of space for fa");
+ f->accept = poscnt-1; /* penter has computed number of positions in re */
+ cfoll(f, p1); /* set up follow sets */
+ freetr(p1);
+ if ((f->posns[0] = (int *) calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL)
+ overflo("out of space in makedfa");
+ if ((f->posns[1] = (int *) calloc(1, sizeof(int))) == NULL)
+ overflo("out of space in makedfa");
+ *f->posns[1] = 0;
+ f->initstat = makeinit(f, anchor);
+ f->anchor = anchor;
+ f->restr = (uschar *) tostring(s);
+ return f;
+}
+
+int makeinit(fa *f, int anchor)
+{
+ int i, k;
+
+ f->curstat = 2;
+ f->out[2] = 0;
+ f->reset = 0;
+ k = *(f->re[0].lfollow);
+ xfree(f->posns[2]);
+ if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
+ overflo("out of space in makeinit");
+ for (i=0; i <= k; i++) {
+ (f->posns[2])[i] = (f->re[0].lfollow)[i];
+ }
+ if ((f->posns[2])[1] == f->accept)
+ f->out[2] = 1;
+ for (i=0; i < NCHARS; i++)
+ f->gototab[2][i] = 0;
+ f->curstat = cgoto(f, 2, HAT);
+ if (anchor) {
+ *f->posns[2] = k-1; /* leave out position 0 */
+ for (i=0; i < k; i++) {
+ (f->posns[0])[i] = (f->posns[2])[i];
+ }
+
+ f->out[0] = f->out[2];
+ if (f->curstat != 2)
+ --(*f->posns[f->curstat]);
+ }
+ return f->curstat;
+}
+
+void penter(Node *p) /* set up parent pointers and leaf indices */
+{
+ switch (type(p)) {
+ LEAF
+ info(p) = poscnt;
+ poscnt++;
+ break;
+ UNARY
+ penter(left(p));
+ parent(left(p)) = p;
+ break;
+ case CAT:
+ case OR:
+ penter(left(p));
+ penter(right(p));
+ parent(left(p)) = p;
+ parent(right(p)) = p;
+ break;
+ default: /* can't happen */
+ FATAL("can't happen: unknown type %d in penter", type(p));
+ break;
+ }
+}
+
+void freetr(Node *p) /* free parse tree */
+{
+ switch (type(p)) {
+ LEAF
+ xfree(p);
+ break;
+ UNARY
+ freetr(left(p));
+ xfree(p);
+ break;
+ case CAT:
+ case OR:
+ freetr(left(p));
+ freetr(right(p));
+ xfree(p);
+ break;
+ default: /* can't happen */
+ FATAL("can't happen: unknown type %d in freetr", type(p));
+ break;
+ }
+}
+
+/* in the parsing of regular expressions, metacharacters like . have */
+/* to be seen literally; \056 is not a metacharacter. */
+
+int hexstr(char **pp) /* find and eval hex string at pp, return new p */
+{ /* only pick up one 8-bit byte (2 chars) */
+ uschar *p;
+ int n = 0;
+ int i;
+
+ for (i = 0, p = (uschar *) *pp; i < 2 && isxdigit(*p); i++, p++) {
+ if (isdigit(*p))
+ n = 16 * n + *p - '0';
+ else if (*p >= 'a' && *p <= 'f')
+ n = 16 * n + *p - 'a' + 10;
+ else if (*p >= 'A' && *p <= 'F')
+ n = 16 * n + *p - 'A' + 10;
+ }
+ *pp = (char *) p;
+ return n;
+}
+
+#define isoctdigit(c) ((c) >= '0' && (c) <= '7') /* multiple use of arg */
+
+int quoted(char **pp) /* pick up next thing after a \\ */
+ /* and increment *pp */
+{
+ char *p = *pp;
+ int c;
+
+ if ((c = *p++) == 't')
+ c = '\t';
+ else if (c == 'n')
+ c = '\n';
+ else if (c == 'f')
+ c = '\f';
+ else if (c == 'r')
+ c = '\r';
+ else if (c == 'b')
+ c = '\b';
+ else if (c == '\\')
+ c = '\\';
+ else if (c == 'x') { /* hexadecimal goo follows */
+ c = hexstr(&p); /* this adds a null if number is invalid */
+ } else if (isoctdigit(c)) { /* \d \dd \ddd */
+ int n = c - '0';
+ if (isoctdigit(*p)) {
+ n = 8 * n + *p++ - '0';
+ if (isoctdigit(*p))
+ n = 8 * n + *p++ - '0';
+ }
+ c = n;
+ } /* else */
+ /* c = c; */
+ *pp = p;
+ return c;
+}
+
+char *cclenter(char *argp) /* add a character class */
+{
+ int i, c, c2;
+ uschar *p = (uschar *) argp;
+ uschar *op, *bp;
+ static uschar *buf = 0;
+ static int bufsz = 100;
+
+ op = p;
+ if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL)
+ FATAL("out of space for character class [%.10s...] 1", p);
+ bp = buf;
+ for (i = 0; (c = *p++) != 0; ) {
+ if (c == '\\') {
+ c = quoted((char **) &p);
+ } else if (c == '-' && i > 0 && bp[-1] != 0) {
+ if (*p != 0) {
+ c = bp[-1];
+ c2 = *p++;
+ if (c2 == '\\')
+ c2 = quoted((char **) &p);
+ if (c > c2) { /* empty; ignore */
+ bp--;
+ i--;
+ continue;
+ }
+ while (c < c2) {
+ if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, 0))
+ FATAL("out of space for character class [%.10s...] 2", p);
+ *bp++ = ++c;
+ i++;
+ }
+ continue;
+ }
+ }
+ if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, 0))
+ FATAL("out of space for character class [%.10s...] 3", p);
+ *bp++ = c;
+ i++;
+ }
+ *bp = 0;
+ dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) );
+ xfree(op);
+ return (char *) tostring((char *) buf);
+}
+
+void overflo(char *s)
+{
+ FATAL("regular expression too big: %.30s...", s);
+}
+
+void cfoll(fa *f, Node *v) /* enter follow set of each leaf of vertex v into lfollow[leaf] */
+{
+ int i;
+ int *p;
+
+ switch (type(v)) {
+ LEAF
+ f->re[info(v)].ltype = type(v);
+ f->re[info(v)].lval.np = right(v);
+ while (f->accept >= maxsetvec) { /* guessing here! */
+ maxsetvec *= 4;
+ setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
+ tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
+ if (setvec == 0 || tmpset == 0)
+ overflo("out of space in cfoll()");
+ }
+ for (i = 0; i <= f->accept; i++)
+ setvec[i] = 0;
+ setcnt = 0;
+ follow(v); /* computes setvec and setcnt */
+ if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL)
+ overflo("out of space building follow set");
+ f->re[info(v)].lfollow = p;
+ *p = setcnt;
+ for (i = f->accept; i >= 0; i--)
+ if (setvec[i] == 1)
+ *++p = i;
+ break;
+ UNARY
+ cfoll(f,left(v));
+ break;
+ case CAT:
+ case OR:
+ cfoll(f,left(v));
+ cfoll(f,right(v));
+ break;
+ default: /* can't happen */
+ FATAL("can't happen: unknown type %d in cfoll", type(v));
+ }
+}
+
+int first(Node *p) /* collects initially active leaves of p into setvec */
+ /* returns 1 if p matches empty string */
+{
+ int b, lp;
+
+ switch (type(p)) {
+ LEAF
+ lp = info(p); /* look for high-water mark of subscripts */
+ while (setcnt >= maxsetvec || lp >= maxsetvec) { /* guessing here! */
+ maxsetvec *= 4;
+ setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
+ tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
+ if (setvec == 0 || tmpset == 0)
+ overflo("out of space in first()");
+ }
+ if (setvec[lp] != 1) {
+ setvec[lp] = 1;
+ setcnt++;
+ }
+ if (type(p) == CCL && (*(char *) right(p)) == '\0')
+ return(0); /* empty CCL */
+ else return(1);
+ case PLUS:
+ if (first(left(p)) == 0) return(0);
+ return(1);
+ case STAR:
+ case QUEST:
+ first(left(p));
+ return(0);
+ case CAT:
+ if (first(left(p)) == 0 && first(right(p)) == 0) return(0);
+ return(1);
+ case OR:
+ b = first(right(p));
+ if (first(left(p)) == 0 || b == 0) return(0);
+ return(1);
+ }
+ FATAL("can't happen: unknown type %d in first", type(p)); /* can't happen */
+ return(-1);
+}
+
+void follow(Node *v) /* collects leaves that can follow v into setvec */
+{
+ Node *p;
+
+ if (type(v) == FINAL)
+ return;
+ p = parent(v);
+ switch (type(p)) {
+ case STAR:
+ case PLUS:
+ first(v);
+ follow(p);
+ return;
+
+ case OR:
+ case QUEST:
+ follow(p);
+ return;
+
+ case CAT:
+ if (v == left(p)) { /* v is left child of p */
+ if (first(right(p)) == 0) {
+ follow(p);
+ return;
+ }
+ } else /* v is right child */
+ follow(p);
+ return;
+ }
+}
+
+int member(int c, char *sarg) /* is c in s? */
+{
+ uschar *s = (uschar *) sarg;
+
+ while (*s)
+ if (c == *s++)
+ return(1);
+ return(0);
+}
+
+int match(fa *f, char *p0) /* shortest match ? */
+{
+ int s, ns;
+ uschar *p = (uschar *) p0;
+
+ s = f->reset ? makeinit(f,0) : f->initstat;
+ if (f->out[s])
+ return(1);
+ do {
+ if ((ns = f->gototab[s][*p]) != 0)
+ s = ns;
+ else
+ s = cgoto(f, s, *p);
+ if (f->out[s])
+ return(1);
+ } while (*p++ != 0);
+ return(0);
+}
+
+int pmatch(fa *f, char *p0) /* longest match, for sub */
+{
+ int s, ns;
+ uschar *p = (uschar *) p0;
+ uschar *q;
+ int i, k;
+
+ s = f->reset ? makeinit(f,1) : f->initstat;
+ patbeg = (char *) p;
+ patlen = -1;
+ do {
+ q = p;
+ do {
+ if (f->out[s]) /* final state */
+ patlen = q-p;
+ if ((ns = f->gototab[s][*q]) != 0)
+ s = ns;
+ else
+ s = cgoto(f, s, *q);
+ if (s == 1) { /* no transition */
+ if (patlen >= 0) {
+ patbeg = (char *) p;
+ return(1);
+ }
+ else
+ goto nextin; /* no match */
+ }
+ } while (*q++ != 0);
+ if (f->out[s])
+ patlen = q-p-1; /* don't count $ */
+ if (patlen >= 0) {
+ patbeg = (char *) p;
+ return(1);
+ }
+ nextin:
+ s = 2;
+ if (f->reset) {
+ for (i = 2; i <= f->curstat; i++)
+ xfree(f->posns[i]);
+ k = *f->posns[0];
+ if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
+ overflo("out of space in pmatch");
+ for (i = 0; i <= k; i++)
+ (f->posns[2])[i] = (f->posns[0])[i];
+ f->initstat = f->curstat = 2;
+ f->out[2] = f->out[0];
+ for (i = 0; i < NCHARS; i++)
+ f->gototab[2][i] = 0;
+ }
+ } while (*p++ != 0);
+ return (0);
+}
+
+int nematch(fa *f, char *p0) /* non-empty match, for sub */
+{
+ int s, ns;
+ uschar *p = (uschar *) p0;
+ uschar *q;
+ int i, k;
+
+ s = f->reset ? makeinit(f,1) : f->initstat;
+ patlen = -1;
+ while (*p) {
+ q = p;
+ do {
+ if (f->out[s]) /* final state */
+ patlen = q-p;
+ if ((ns = f->gototab[s][*q]) != 0)
+ s = ns;
+ else
+ s = cgoto(f, s, *q);
+ if (s == 1) { /* no transition */
+ if (patlen > 0) {
+ patbeg = (char *) p;
+ return(1);
+ } else
+ goto nnextin; /* no nonempty match */
+ }
+ } while (*q++ != 0);
+ if (f->out[s])
+ patlen = q-p-1; /* don't count $ */
+ if (patlen > 0 ) {
+ patbeg = (char *) p;
+ return(1);
+ }
+ nnextin:
+ s = 2;
+ if (f->reset) {
+ for (i = 2; i <= f->curstat; i++)
+ xfree(f->posns[i]);
+ k = *f->posns[0];
+ if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
+ overflo("out of state space");
+ for (i = 0; i <= k; i++)
+ (f->posns[2])[i] = (f->posns[0])[i];
+ f->initstat = f->curstat = 2;
+ f->out[2] = f->out[0];
+ for (i = 0; i < NCHARS; i++)
+ f->gototab[2][i] = 0;
+ }
+ p++;
+ }
+ return (0);
+}
+
+Node *reparse(char *p) /* parses regular expression pointed to by p */
+{ /* uses relex() to scan regular expression */
+ Node *np;
+
+ dprintf( ("reparse <%s>\n", p) );
+ lastre = prestr = (uschar *) p; /* prestr points to string to be parsed */
+ rtok = relex();
+ if (rtok == '\0')
+ FATAL("empty regular expression");
+ np = regexp();
+ if (rtok != '\0')
+ FATAL("syntax error in regular expression %s at %s", lastre, prestr);
+ return(np);
+}
+
+Node *regexp(void) /* top-level parse of reg expr */
+{
+ return (alt(concat(primary())));
+}
+
+Node *primary(void)
+{
+ Node *np;
+
+ switch (rtok) {
+ case CHAR:
+ np = op2(CHAR, NIL, itonp(rlxval));
+ rtok = relex();
+ return (unary(np));
+ case ALL:
+ rtok = relex();
+ return (unary(op2(ALL, NIL, NIL)));
+ case DOT:
+ rtok = relex();
+ return (unary(op2(DOT, NIL, NIL)));
+ case CCL:
+ np = op2(CCL, NIL, (Node*) cclenter((char *) rlxstr));
+ rtok = relex();
+ return (unary(np));
+ case NCCL:
+ np = op2(NCCL, NIL, (Node *) cclenter((char *) rlxstr));
+ rtok = relex();
+ return (unary(np));
+ case '^':
+ rtok = relex();
+ return (unary(op2(CHAR, NIL, itonp(HAT))));
+ case '$':
+ rtok = relex();
+ return (unary(op2(CHAR, NIL, NIL)));
+ case '(':
+ rtok = relex();
+ if (rtok == ')') { /* special pleading for () */
+ rtok = relex();
+ return unary(op2(CCL, NIL, (Node *) tostring("")));
+ }
+ np = regexp();
+ if (rtok == ')') {
+ rtok = relex();
+ return (unary(np));
+ }
+ else
+ FATAL("syntax error in regular expression %s at %s", lastre, prestr);
+ default:
+ FATAL("illegal primary in regular expression %s at %s", lastre, prestr);
+ }
+ return 0; /*NOTREACHED*/
+}
+
+Node *concat(Node *np)
+{
+ switch (rtok) {
+ case CHAR: case DOT: case ALL: case CCL: case NCCL: case '$': case '(':
+ return (concat(op2(CAT, np, primary())));
+ }
+ return (np);
+}
+
+Node *alt(Node *np)
+{
+ if (rtok == OR) {
+ rtok = relex();
+ return (alt(op2(OR, np, concat(primary()))));
+ }
+ return (np);
+}
+
+Node *unary(Node *np)
+{
+ switch (rtok) {
+ case STAR:
+ rtok = relex();
+ return (unary(op2(STAR, np, NIL)));
+ case PLUS:
+ rtok = relex();
+ return (unary(op2(PLUS, np, NIL)));
+ case QUEST:
+ rtok = relex();
+ return (unary(op2(QUEST, np, NIL)));
+ default:
+ return (np);
+ }
+}
+
+int relex(void) /* lexical analyzer for reparse */
+{
+ int c, n;
+ int cflag;
+ static uschar *buf = 0;
+ static int bufsz = 100;
+ uschar *bp;
+
+ switch (c = *prestr++) {
+ case '|': return OR;
+ case '*': return STAR;
+ case '+': return PLUS;
+ case '?': return QUEST;
+ case '.': return DOT;
+ case '\0': prestr--; return '\0';
+ case '^':
+ case '$':
+ case '(':
+ case ')':
+ return c;
+ case '\\':
+ rlxval = quoted((char **) &prestr);
+ return CHAR;
+ default:
+ rlxval = c;
+ return CHAR;
+ case '[':
+ if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL)
+ FATAL("out of space in reg expr %.10s..", lastre);
+ bp = buf;
+ if (*prestr == '^') {
+ cflag = 1;
+ prestr++;
+ }
+ else
+ cflag = 0;
+ n = 2 * strlen(prestr)+1;
+ if (!adjbuf((char **) &buf, &bufsz, n, n, (char **) &bp, 0))
+ FATAL("out of space for reg expr %.10s...", lastre);
+ for (; ; ) {
+ if ((c = *prestr++) == '\\') {
+ *bp++ = '\\';
+ if ((c = *prestr++) == '\0')
+ FATAL("nonterminated character class %.20s...", lastre);
+ *bp++ = c;
+ /* } else if (c == '\n') { */
+ /* FATAL("newline in character class %.20s...", lastre); */
+ } else if (c == '\0') {
+ FATAL("nonterminated character class %.20s", lastre);
+ } else if (bp == buf) { /* 1st char is special */
+ *bp++ = c;
+ } else if (c == ']') {
+ *bp++ = 0;
+ rlxstr = (uschar *) tostring((char *) buf);
+ if (cflag == 0)
+ return CCL;
+ else
+ return NCCL;
+ } else
+ *bp++ = c;
+ }
+ }
+}
+
+int cgoto(fa *f, int s, int c)
+{
+ int i, j, k;
+ int *p, *q;
+
+ if (c < 0 || c > 255)
+ FATAL("can't happen: neg char %d in cgoto", c);
+ while (f->accept >= maxsetvec) { /* guessing here! */
+ maxsetvec *= 4;
+ setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
+ tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
+ if (setvec == 0 || tmpset == 0)
+ overflo("out of space in cgoto()");
+ }
+ for (i = 0; i <= f->accept; i++)
+ setvec[i] = 0;
+ setcnt = 0;
+ /* compute positions of gototab[s,c] into setvec */
+ p = f->posns[s];
+ for (i = 1; i <= *p; i++) {
+ if ((k = f->re[p[i]].ltype) != FINAL) {
+ if ((k == CHAR && c == ptoi(f->re[p[i]].lval.np))
+ || (k == DOT && c != 0 && c != HAT)
+ || (k == ALL && c != 0)
+ || (k == CCL && member(c, (char *) f->re[p[i]].lval.up))
+ || (k == NCCL && !member(c, (char *) f->re[p[i]].lval.up) && c != 0 && c != HAT)) {
+ q = f->re[p[i]].lfollow;
+ for (j = 1; j <= *q; j++) {
+ if (q[j] >= maxsetvec) {
+ maxsetvec *= 4;
+ setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
+ tmpset = (int *) realloc(setvec, maxsetvec * sizeof(int));
+ if (setvec == 0 || tmpset == 0)
+ overflo("cgoto overflow");
+ }
+ if (setvec[q[j]] == 0) {
+ setcnt++;
+ setvec[q[j]] = 1;
+ }
+ }
+ }
+ }
+ }
+ /* determine if setvec is a previous state */
+ tmpset[0] = setcnt;
+ j = 1;
+ for (i = f->accept; i >= 0; i--)
+ if (setvec[i]) {
+ tmpset[j++] = i;
+ }
+ /* tmpset == previous state? */
+ for (i = 1; i <= f->curstat; i++) {
+ p = f->posns[i];
+ if ((k = tmpset[0]) != p[0])
+ goto different;
+ for (j = 1; j <= k; j++)
+ if (tmpset[j] != p[j])
+ goto different;
+ /* setvec is state i */
+ f->gototab[s][c] = i;
+ return i;
+ different:;
+ }
+
+ /* add tmpset to current set of states */
+ if (f->curstat >= NSTATES-1) {
+ f->curstat = 2;
+ f->reset = 1;
+ for (i = 2; i < NSTATES; i++)
+ xfree(f->posns[i]);
+ } else
+ ++(f->curstat);
+ for (i = 0; i < NCHARS; i++)
+ f->gototab[f->curstat][i] = 0;
+ xfree(f->posns[f->curstat]);
+ if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL)
+ overflo("out of space in cgoto");
+
+ f->posns[f->curstat] = p;
+ f->gototab[s][c] = f->curstat;
+ for (i = 0; i <= setcnt; i++)
+ p[i] = tmpset[i];
+ if (setvec[f->accept])
+ f->out[f->curstat] = 1;
+ else
+ f->out[f->curstat] = 0;
+ return f->curstat;
+}
+
+
+void freefa(fa *f) /* free a finite automaton */
+{
+ int i;
+
+ if (f == NULL)
+ return;
+ for (i = 0; i <= f->curstat; i++)
+ xfree(f->posns[i]);
+ for (i = 0; i <= f->accept; i++) {
+ xfree(f->re[i].lfollow);
+ if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
+ xfree((f->re[i].lval.np));
+ }
+ xfree(f->restr);
+ xfree(f);
+}
diff --git a/utils/awk/buildwin.bat b/utils/awk/buildwin.bat
new file mode 100644
index 00000000..77513429
--- /dev/null
+++ b/utils/awk/buildwin.bat
@@ -0,0 +1,12 @@
+@echo off
+rem buildwin.bat - build AWK under Windows NT using Visual C++.
+rem 22 Jan 1999 - Created by Dan Allen.
+rem
+rem If you delete the call to setlocal it will probably work under Win95/Win98 as well.
+
+setlocal
+set cl=-w -Ox -QIfdiv- -nologo -link -nologo setargv.obj
+
+cl maketab.c -o maketab.exe
+maketab.exe > proctab.c
+cl -o awk.exe b.c main.c parse.c proctab.c tran.c lib.c run.c lex.c ytab.c missing95.c
diff --git a/utils/awk/lex.c b/utils/awk/lex.c
new file mode 100644
index 00000000..a9471098
--- /dev/null
+++ b/utils/awk/lex.c
@@ -0,0 +1,571 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "awk.h"
+#include "ytab.h"
+
+extern YYSTYPE yylval;
+extern int infunc;
+
+int lineno = 1;
+int bracecnt = 0;
+int brackcnt = 0;
+int parencnt = 0;
+
+typedef struct Keyword {
+ char *word;
+ int sub;
+ int type;
+} Keyword;
+
+Keyword keywords[] ={ /* keep sorted: binary searched */
+ { "BEGIN", XBEGIN, XBEGIN },
+ { "END", XEND, XEND },
+ { "NF", VARNF, VARNF },
+ { "atan2", FATAN, BLTIN },
+ { "break", BREAK, BREAK },
+ { "close", CLOSE, CLOSE },
+ { "continue", CONTINUE, CONTINUE },
+ { "cos", FCOS, BLTIN },
+ { "delete", DELETE, DELETE },
+ { "do", DO, DO },
+ { "else", ELSE, ELSE },
+ { "exit", EXIT, EXIT },
+ { "exp", FEXP, BLTIN },
+ { "fflush", FFLUSH, BLTIN },
+ { "for", FOR, FOR },
+ { "func", FUNC, FUNC },
+ { "function", FUNC, FUNC },
+ { "getline", GETLINE, GETLINE },
+ { "gsub", GSUB, GSUB },
+ { "if", IF, IF },
+ { "in", IN, IN },
+ { "index", INDEX, INDEX },
+ { "int", FINT, BLTIN },
+ { "length", FLENGTH, BLTIN },
+ { "log", FLOG, BLTIN },
+ { "match", MATCHFCN, MATCHFCN },
+ { "next", NEXT, NEXT },
+ { "nextfile", NEXTFILE, NEXTFILE },
+ { "print", PRINT, PRINT },
+ { "printf", PRINTF, PRINTF },
+ { "rand", FRAND, BLTIN },
+ { "return", RETURN, RETURN },
+ { "sin", FSIN, BLTIN },
+ { "split", SPLIT, SPLIT },
+ { "sprintf", SPRINTF, SPRINTF },
+ { "sqrt", FSQRT, BLTIN },
+ { "srand", FSRAND, BLTIN },
+ { "sub", SUB, SUB },
+ { "substr", SUBSTR, SUBSTR },
+ { "system", FSYSTEM, BLTIN },
+ { "tolower", FTOLOWER, BLTIN },
+ { "toupper", FTOUPPER, BLTIN },
+ { "while", WHILE, WHILE },
+};
+
+#define DEBUG
+#ifdef DEBUG
+#define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
+#else
+#define RET(x) return(x)
+#endif
+
+int peek(void)
+{
+ int c = input();
+ unput(c);
+ return c;
+}
+
+int gettok(char **pbuf, int *psz) /* get next input token */
+{
+ int c;
+ char *buf = *pbuf;
+ int sz = *psz;
+ char *bp = buf;
+
+ c = input();
+ if (c == 0)
+ return 0;
+ buf[0] = c;
+ buf[1] = 0;
+ if (!isalnum(c) && c != '.' && c != '_')
+ return c;
+
+ *bp++ = c;
+ if (isalpha(c) || c == '_') { /* it's a varname */
+ for ( ; (c = input()) != 0; ) {
+ if (bp-buf >= sz)
+ if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
+ FATAL( "out of space for name %.10s...", buf );
+ if (isalnum(c) || c == '_')
+ *bp++ = c;
+ else {
+ *bp = 0;
+ unput(c);
+ break;
+ }
+ }
+ *bp = 0;
+ } else { /* it's a number */
+ char *rem;
+ /* read input until can't be a number */
+ for ( ; (c = input()) != 0; ) {
+ if (bp-buf >= sz)
+ if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
+ FATAL( "out of space for number %.10s...", buf );
+ if (isdigit(c) || c == 'e' || c == 'E'
+ || c == '.' || c == '+' || c == '-')
+ *bp++ = c;
+ else {
+ unput(c);
+ break;
+ }
+ }
+ *bp = 0;
+ strtod(buf, &rem); /* parse the number */
+ unputstr(rem); /* put rest back for later */
+ rem[0] = 0;
+ }
+ *pbuf = buf;
+ *psz = sz;
+ return buf[0];
+}
+
+int word(char *);
+int string(void);
+int regexpr(void);
+int sc = 0; /* 1 => return a } right now */
+int reg = 0; /* 1 => return a REGEXPR now */
+
+int yylex(void)
+{
+ int c;
+ static char *buf = 0;
+ static int bufsize = 500;
+
+ if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
+ FATAL( "out of space in yylex" );
+ if (sc) {
+ sc = 0;
+ RET('}');
+ }
+ if (reg) {
+ reg = 0;
+ return regexpr();
+ }
+ for (;;) {
+ c = gettok(&buf, &bufsize);
+ if (c == 0)
+ return 0;
+ if (isalpha(c) || c == '_')
+ return word(buf);
+ if (isdigit(c) || c == '.') {
+ yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
+ /* should this also have STR set? */
+ RET(NUMBER);
+ }
+
+ yylval.i = c;
+ switch (c) {
+ case '\n': /* {EOL} */
+ RET(NL);
+ case '\r': /* assume \n is coming */
+ case ' ': /* {WS}+ */
+ case '\t':
+ break;
+ case '#': /* #.* strip comments */
+ while ((c = input()) != '\n' && c != 0)
+ ;
+ unput(c);
+ break;
+ case ';':
+ RET(';');
+ case '\\':
+ if (peek() == '\n') {
+ input();
+ } else if (peek() == '\r') {
+ input(); input(); /* \n */
+ lineno++;
+ } else {
+ RET(c);
+ }
+ break;
+ case '&':
+ if (peek() == '&') {
+ input(); RET(AND);
+ } else
+ RET('&');
+ case '|':
+ if (peek() == '|') {
+ input(); RET(BOR);
+ } else
+ RET('|');
+ case '!':
+ if (peek() == '=') {
+ input(); yylval.i = NE; RET(NE);
+ } else if (peek() == '~') {
+ input(); yylval.i = NOTMATCH; RET(MATCHOP);
+ } else
+ RET(NOT);
+ case '~':
+ yylval.i = MATCH;
+ RET(MATCHOP);
+ case '<':
+ if (peek() == '=') {
+ input(); yylval.i = LE; RET(LE);
+ } else {
+ yylval.i = LT; RET(LT);
+ }
+ case '=':
+ if (peek() == '=') {
+ input(); yylval.i = EQ; RET(EQ);
+ } else {
+ yylval.i = ASSIGN; RET(ASGNOP);
+ }
+ case '>':
+ if (peek() == '=') {
+ input(); yylval.i = GE; RET(GE);
+ } else if (peek() == '>') {
+ input(); yylval.i = APPEND; RET(APPEND);
+ } else {
+ yylval.i = GT; RET(GT);
+ }
+ case '+':
+ if (peek() == '+') {
+ input(); yylval.i = INCR; RET(INCR);
+ } else if (peek() == '=') {
+ input(); yylval.i = ADDEQ; RET(ASGNOP);
+ } else
+ RET('+');
+ case '-':
+ if (peek() == '-') {
+ input(); yylval.i = DECR; RET(DECR);
+ } else if (peek() == '=') {
+ input(); yylval.i = SUBEQ; RET(ASGNOP);
+ } else
+ RET('-');
+ case '*':
+ if (peek() == '=') { /* *= */
+ input(); yylval.i = MULTEQ; RET(ASGNOP);
+ } else if (peek() == '*') { /* ** or **= */
+ input(); /* eat 2nd * */
+ if (peek() == '=') {
+ input(); yylval.i = POWEQ; RET(ASGNOP);
+ } else {
+ RET(POWER);
+ }
+ } else
+ RET('*');
+ case '/':
+ RET('/');
+ case '%':
+ if (peek() == '=') {
+ input(); yylval.i = MODEQ; RET(ASGNOP);
+ } else
+ RET('%');
+ case '^':
+ if (peek() == '=') {
+ input(); yylval.i = POWEQ; RET(ASGNOP);
+ } else
+ RET(POWER);
+
+ case '$':
+ /* BUG: awkward, if not wrong */
+ c = gettok(&buf, &bufsize);
+ if (isalpha(c)) {
+ if (strcmp(buf, "NF") == 0) { /* very special */
+ unputstr("(NF)");
+ RET(INDIRECT);
+ }
+ c = peek();
+ if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
+ unputstr(buf);
+ RET(INDIRECT);
+ }
+ yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
+ RET(IVAR);
+ } else {
+ unputstr(buf);
+ RET(INDIRECT);
+ }
+
+ case '}':
+ if (--bracecnt < 0)
+ SYNTAX( "extra }" );
+ sc = 1;
+ RET(';');
+ case ']':
+ if (--brackcnt < 0)
+ SYNTAX( "extra ]" );
+ RET(']');
+ case ')':
+ if (--parencnt < 0)
+ SYNTAX( "extra )" );
+ RET(')');
+ case '{':
+ bracecnt++;
+ RET('{');
+ case '[':
+ brackcnt++;
+ RET('[');
+ case '(':
+ parencnt++;
+ RET('(');
+
+ case '"':
+ return string(); /* BUG: should be like tran.c ? */
+
+ default:
+ RET(c);
+ }
+ }
+}
+
+int string(void)
+{
+ int c, n;
+ char *s, *bp;
+ static char *buf = 0;
+ static int bufsz = 500;
+
+ if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of space for strings");
+ for (bp = buf; (c = input()) != '"'; ) {
+ if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0))
+ FATAL("out of space for string %.10s...", buf);
+ switch (c) {
+ case '\n':
+ case '\r':
+ case 0:
+ SYNTAX( "non-terminated string %.10s...", buf );
+ lineno++;
+ break;
+ case '\\':
+ c = input();
+ switch (c) {
+ case '"': *bp++ = '"'; break;
+ case 'n': *bp++ = '\n'; break;
+ case 't': *bp++ = '\t'; break;
+ case 'f': *bp++ = '\f'; break;
+ case 'r': *bp++ = '\r'; break;
+ case 'b': *bp++ = '\b'; break;
+ case 'v': *bp++ = '\v'; break;
+ case 'a': *bp++ = '\007'; break;
+ case '\\': *bp++ = '\\'; break;
+
+ case '0': case '1': case '2': /* octal: \d \dd \ddd */
+ case '3': case '4': case '5': case '6': case '7':
+ n = c - '0';
+ if ((c = peek()) >= '0' && c < '8') {
+ n = 8 * n + input() - '0';
+ if ((c = peek()) >= '0' && c < '8')
+ n = 8 * n + input() - '0';
+ }
+ *bp++ = n;
+ break;
+
+ case 'x': /* hex \x0-9a-fA-F + */
+ { char xbuf[100], *px;
+ for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
+ if (isdigit(c)
+ || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F'))
+ *px++ = c;
+ else
+ break;
+ }
+ *px = 0;
+ unput(c);
+ sscanf(xbuf, "%x", &n);
+ *bp++ = n;
+ break;
+ }
+
+ default:
+ *bp++ = c;
+ break;
+ }
+ break;
+ default:
+ *bp++ = c;
+ break;
+ }
+ }
+ *bp = 0;
+ s = tostring(buf);
+ *bp++ = ' '; *bp++ = 0;
+ yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
+ RET(STRING);
+}
+
+
+int binsearch(char *w, Keyword *kp, int n)
+{
+ int cond, low, mid, high;
+
+ low = 0;
+ high = n - 1;
+ while (low <= high) {
+ mid = (low + high) / 2;
+ if ((cond = strcmp(w, kp[mid].word)) < 0)
+ high = mid - 1;
+ else if (cond > 0)
+ low = mid + 1;
+ else
+ return mid;
+ }
+ return -1;
+}
+
+int word(char *w)
+{
+ Keyword *kp;
+ int c, n;
+
+ n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
+ kp = keywords + n;
+ if (n != -1) { /* found in table */
+ yylval.i = kp->sub;
+ switch (kp->type) { /* special handling */
+ case FSYSTEM:
+ if (safe)
+ SYNTAX( "system is unsafe" );
+ RET(kp->type);
+ case FUNC:
+ if (infunc)
+ SYNTAX( "illegal nested function" );
+ RET(kp->type);
+ case RETURN:
+ if (!infunc)
+ SYNTAX( "return not in function" );
+ RET(kp->type);
+ case VARNF:
+ yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
+ RET(VARNF);
+ default:
+ RET(kp->type);
+ }
+ }
+ c = peek(); /* look for '(' */
+ if (c != '(' && infunc && (n=isarg(w)) >= 0) {
+ yylval.i = n;
+ RET(ARG);
+ } else {
+ yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
+ if (c == '(') {
+ RET(CALL);
+ } else {
+ RET(VAR);
+ }
+ }
+}
+
+void startreg(void) /* next call to yyles will return a regular expression */
+{
+ reg = 1;
+}
+
+int regexpr(void)
+{
+ int c;
+ static char *buf = 0;
+ static int bufsz = 500;
+ char *bp;
+
+ if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of space for rex expr");
+ bp = buf;
+ for ( ; (c = input()) != '/' && c != 0; ) {
+ if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0))
+ FATAL("out of space for reg expr %.10s...", buf);
+ if (c == '\n') {
+ SYNTAX( "newline in regular expression %.10s...", buf );
+ unput('\n');
+ break;
+ } else if (c == '\\') {
+ *bp++ = '\\';
+ *bp++ = input();
+ } else {
+ *bp++ = c;
+ }
+ }
+ *bp = 0;
+ yylval.s = tostring(buf);
+ unput('/');
+ RET(REGEXPR);
+}
+
+/* low-level lexical stuff, sort of inherited from lex */
+
+char ebuf[300];
+char *ep = ebuf;
+char yysbuf[100]; /* pushback buffer */
+char *yysptr = yysbuf;
+FILE *yyin = 0;
+
+int input(void) /* get next lexical input character */
+{
+ int c;
+ extern char *lexprog;
+
+ if (yysptr > yysbuf)
+ c = *--yysptr;
+ else if (lexprog != NULL) { /* awk '...' */
+ if ((c = *lexprog) != 0)
+ lexprog++;
+ } else /* awk -f ... */
+ c = pgetc();
+ if (c == '\n')
+ lineno++;
+ else if (c == EOF)
+ c = 0;
+ if (ep >= ebuf + sizeof ebuf)
+ ep = ebuf;
+ return *ep++ = c;
+}
+
+void unput(int c) /* put lexical character back on input */
+{
+ if (c == '\n')
+ lineno--;
+ if (yysptr >= yysbuf + sizeof(yysbuf))
+ FATAL("pushed back too much: %.20s...", yysbuf);
+ *yysptr++ = c;
+ if (--ep < ebuf)
+ ep = ebuf + sizeof(ebuf) - 1;
+}
+
+void unputstr(char *s) /* put a string back on input */
+{
+ int i;
+
+ for (i = strlen(s)-1; i >= 0; i--)
+ unput(s[i]);
+}
diff --git a/utils/awk/lib.c b/utils/awk/lib.c
new file mode 100644
index 00000000..a44466f1
--- /dev/null
+++ b/utils/awk/lib.c
@@ -0,0 +1,682 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+#define DEBUG
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "awk.h"
+#include "ytab.h"
+
+FILE *infile = NULL;
+char *file = "";
+char *record;
+int recsize = RECSIZE;
+char *fields;
+int fieldssize = RECSIZE;
+
+Cell **fldtab; /* pointers to Cells */
+char inputFS[100] = " ";
+
+#define MAXFLD 200
+int nfields = MAXFLD; /* last allocated slot for $i */
+
+int donefld; /* 1 = implies rec broken into fields */
+int donerec; /* 1 = record is valid (no flds have changed) */
+
+int lastfld = 0; /* last used field */
+int argno = 1; /* current input argument number */
+extern Awkfloat *ARGC;
+
+static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
+static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
+
+void recinit(unsigned int n)
+{
+ record = (char *) malloc(n);
+ fields = (char *) malloc(n);
+ fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
+ if (record == NULL || fields == NULL || fldtab == NULL)
+ FATAL("out of space for $0 and fields");
+
+ fldtab[0] = (Cell *) malloc(sizeof (Cell));
+ *fldtab[0] = dollar0;
+ fldtab[0]->sval = record;
+ fldtab[0]->nval = tostring("0");
+ makefields(1, nfields);
+}
+
+void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
+{
+ char temp[50];
+ int i;
+
+ for (i = n1; i <= n2; i++) {
+ fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
+ if (fldtab[i] == NULL)
+ FATAL("out of space in makefields %d", i);
+ *fldtab[i] = dollar1;
+ sprintf(temp, "%d", i);
+ fldtab[i]->nval = tostring(temp);
+ }
+}
+
+void initgetrec(void)
+{
+ int i;
+ char *p;
+
+ for (i = 1; i < *ARGC; i++) {
+ if (!isclvar(p = getargv(i))) { /* find 1st real filename */
+ setsval(lookup("FILENAME", symtab), getargv(i));
+ return;
+ }
+ setclvar(p); /* a commandline assignment before filename */
+ argno++;
+ }
+ infile = stdin; /* no filenames, so use stdin */
+}
+
+int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
+{ /* note: cares whether buf == record */
+ int c;
+ static int firsttime = 1;
+ char *buf = *pbuf;
+ int bufsize = *pbufsize;
+
+ if (firsttime) {
+ firsttime = 0;
+ initgetrec();
+ }
+ dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
+ *RS, *FS, *ARGC, *FILENAME) );
+ if (isrecord) {
+ donefld = 0;
+ donerec = 1;
+ }
+ buf[0] = 0;
+ while (argno < *ARGC || infile == stdin) {
+ dprintf( ("argno=%d, file=|%s|\n", argno, file) );
+ if (infile == NULL) { /* have to open a new file */
+ file = getargv(argno);
+ if (*file == '\0') { /* it's been zapped */
+ argno++;
+ continue;
+ }
+ if (isclvar(file)) { /* a var=value arg */
+ setclvar(file);
+ argno++;
+ continue;
+ }
+ *FILENAME = file;
+ dprintf( ("opening file %s\n", file) );
+ if (*file == '-' && *(file+1) == '\0')
+ infile = stdin;
+ else if ((infile = fopen(file, "r")) == NULL)
+ FATAL("can't open file %s", file);
+ setfval(fnrloc, 0.0);
+ }
+ c = readrec(&buf, &bufsize, infile);
+ if (c != 0 || buf[0] != '\0') { /* normal record */
+ if (isrecord) {
+ if (freeable(fldtab[0]))
+ xfree(fldtab[0]->sval);
+ fldtab[0]->sval = buf; /* buf == record */
+ fldtab[0]->tval = REC | STR | DONTFREE;
+ if (is_number(fldtab[0]->sval)) {
+ fldtab[0]->fval = atof(fldtab[0]->sval);
+ fldtab[0]->tval |= NUM;
+ }
+ }
+ setfval(nrloc, nrloc->fval+1);
+ setfval(fnrloc, fnrloc->fval+1);
+ *pbuf = buf;
+ *pbufsize = bufsize;
+ return 1;
+ }
+ /* EOF arrived on this file; set up next */
+ if (infile != stdin)
+ fclose(infile);
+ infile = NULL;
+ argno++;
+ }
+ *pbuf = buf;
+ *pbufsize = bufsize;
+ return 0; /* true end of file */
+}
+
+void nextfile(void)
+{
+ if (infile != stdin)
+ fclose(infile);
+ infile = NULL;
+ argno++;
+}
+
+int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
+{
+ int sep, c;
+ char *rr, *buf = *pbuf;
+ int bufsize = *pbufsize;
+
+ if (strlen(*FS) >= sizeof(inputFS))
+ FATAL("field separator %.10s... is too long", *FS);
+ strcpy(inputFS, *FS); /* for subsequent field splitting */
+ if ((sep = **RS) == 0) {
+ sep = '\n';
+ while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
+ ;
+ if (c != EOF)
+ ungetc(c, inf);
+ }
+ for (rr = buf; ; ) {
+ for (; (c=getc(inf)) != sep && c != EOF; ) {
+ if (rr-buf+1 > bufsize)
+ if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
+ FATAL("input record `%.30s...' too long", buf);
+ *rr++ = c;
+ }
+ if (**RS == sep || c == EOF)
+ break;
+ if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
+ break;
+ if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
+ FATAL("input record `%.30s...' too long", buf);
+ *rr++ = '\n';
+ *rr++ = c;
+ }
+ if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
+ FATAL("input record `%.30s...' too long", buf);
+ *rr = 0;
+ dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
+ *pbuf = buf;
+ *pbufsize = bufsize;
+ return c == EOF && rr == buf ? 0 : 1;
+}
+
+char *getargv(int n) /* get ARGV[n] */
+{
+ Cell *x;
+ char *s, temp[50];
+ extern Array *ARGVtab;
+
+ sprintf(temp, "%d", n);
+ x = setsymtab(temp, "", 0.0, STR, ARGVtab);
+ s = getsval(x);
+ dprintf( ("getargv(%d) returns |%s|\n", n, s) );
+ return s;
+}
+
+void setclvar(char *s) /* set var=value from s */
+{
+ char *p;
+ Cell *q;
+
+ for (p=s; *p != '='; p++)
+ ;
+ *p++ = 0;
+ p = qstring(p, '\0');
+ q = setsymtab(s, p, 0.0, STR, symtab);
+ setsval(q, p);
+ if (is_number(q->sval)) {
+ q->fval = atof(q->sval);
+ q->tval |= NUM;
+ }
+ dprintf( ("command line set %s to |%s|\n", s, p) );
+}
+
+
+void fldbld(void) /* create fields from current record */
+{
+ /* this relies on having fields[] the same length as $0 */
+ /* the fields are all stored in this one array with \0's */
+ char *r, *fr, sep;
+ Cell *p;
+ int i, j, n;
+
+ if (donefld)
+ return;
+ if (!isstr(fldtab[0]))
+ getsval(fldtab[0]);
+ r = fldtab[0]->sval;
+ n = strlen(r);
+ if (n > fieldssize) {
+ xfree(fields);
+ if ((fields = (char *) malloc(n+1)) == NULL)
+ FATAL("out of space for fields in fldbld %d", n);
+ fieldssize = n;
+ }
+ fr = fields;
+ i = 0; /* number of fields accumulated here */
+ if (strlen(inputFS) > 1) { /* it's a regular expression */
+ i = refldbld(r, inputFS);
+ } else if ((sep = *inputFS) == ' ') { /* default whitespace */
+ for (i = 0; ; ) {
+ while (*r == ' ' || *r == '\t' || *r == '\n')
+ r++;
+ if (*r == 0)
+ break;
+ i++;
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ fldtab[i]->sval = fr;
+ fldtab[i]->tval = FLD | STR | DONTFREE;
+ do
+ *fr++ = *r++;
+ while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
+ *fr++ = 0;
+ }
+ *fr = 0;
+ } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
+ for (i = 0; *r != 0; r++) {
+ char buf[2];
+ i++;
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ buf[0] = *r;
+ buf[1] = 0;
+ fldtab[i]->sval = tostring(buf);
+ fldtab[i]->tval = FLD | STR;
+ }
+ *fr = 0;
+ } else if (*r != 0) { /* if 0, it's a null field */
+ for (;;) {
+ i++;
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ fldtab[i]->sval = fr;
+ fldtab[i]->tval = FLD | STR | DONTFREE;
+ while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */
+ *fr++ = *r++;
+ *fr++ = 0;
+ if (*r++ == 0)
+ break;
+ }
+ *fr = 0;
+ }
+ if (i > nfields)
+ FATAL("record `%.30s...' has too many fields; can't happen", r);
+ cleanfld(i+1, lastfld); /* clean out junk from previous record */
+ lastfld = i;
+ donefld = 1;
+ for (j = 1; j <= lastfld; j++) {
+ p = fldtab[j];
+ if(is_number(p->sval)) {
+ p->fval = atof(p->sval);
+ p->tval |= NUM;
+ }
+ }
+ setfval(nfloc, (Awkfloat) lastfld);
+ if (dbg) {
+ for (j = 0; j <= lastfld; j++) {
+ p = fldtab[j];
+ printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
+ }
+ }
+}
+
+void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
+{ /* nvals remain intact */
+ Cell *p;
+ int i;
+
+ for (i = n1; i <= n2; i++) {
+ p = fldtab[i];
+ if (freeable(p))
+ xfree(p->sval);
+ p->sval = "";
+ p->tval = FLD | STR | DONTFREE;
+ }
+}
+
+void newfld(int n) /* add field n after end of existing lastfld */
+{
+ if (n > nfields)
+ growfldtab(n);
+ cleanfld(lastfld+1, n);
+ lastfld = n;
+ setfval(nfloc, (Awkfloat) n);
+}
+
+Cell *fieldadr(int n) /* get nth field */
+{
+ if (n < 0)
+ FATAL("trying to access field %d", n);
+ if (n > nfields) /* fields after NF are empty */
+ growfldtab(n); /* but does not increase NF */
+ return(fldtab[n]);
+}
+
+void growfldtab(int n) /* make new fields up to at least $n */
+{
+ int nf = 2 * nfields;
+
+ if (n > nf)
+ nf = n;
+ fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
+ if (fldtab == NULL)
+ FATAL("out of space creating %d fields", nf);
+ makefields(nfields+1, nf);
+ nfields = nf;
+}
+
+int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */
+{
+ /* this relies on having fields[] the same length as $0 */
+ /* the fields are all stored in this one array with \0's */
+ char *fr;
+ int i, tempstat, n;
+ fa *pfa;
+
+ n = strlen(rec);
+ if (n > fieldssize) {
+ xfree(fields);
+ if ((fields = (char *) malloc(n+1)) == NULL)
+ FATAL("out of space for fields in refldbld %d", n);
+ fieldssize = n;
+ }
+ fr = fields;
+ *fr = '\0';
+ if (*rec == '\0')
+ return 0;
+ pfa = makedfa(fs, 1);
+ dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
+ tempstat = pfa->initstat;
+ for (i = 1; ; i++) {
+ if (i > nfields)
+ growfldtab(i);
+ if (freeable(fldtab[i]))
+ xfree(fldtab[i]->sval);
+ fldtab[i]->tval = FLD | STR | DONTFREE;
+ fldtab[i]->sval = fr;
+ dprintf( ("refldbld: i=%d\n", i) );
+ if (nematch(pfa, rec)) {
+ pfa->initstat = 2; /* horrible coupling to b.c */
+ dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
+ strncpy(fr, rec, patbeg-rec);
+ fr += patbeg - rec + 1;
+ *(fr-1) = '\0';
+ rec = patbeg + patlen;
+ } else {
+ dprintf( ("no match %s\n", rec) );
+ strcpy(fr, rec);
+ pfa->initstat = tempstat;
+ break;
+ }
+ }
+ return i;
+}
+
+void recbld(void) /* create $0 from $1..$NF if necessary */
+{
+ int i;
+ char *r, *p;
+
+ if (donerec == 1)
+ return;
+ r = record;
+ for (i = 1; i <= *NF; i++) {
+ p = getsval(fldtab[i]);
+ if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
+ FATAL("created $0 `%.30s...' too long", record);
+ while ((*r = *p++) != 0)
+ r++;
+ if (i < *NF) {
+ if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
+ FATAL("created $0 `%.30s...' too long", record);
+ for (p = *OFS; (*r = *p++) != 0; )
+ r++;
+ }
+ }
+ if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
+ FATAL("built giant record `%.30s...'", record);
+ *r = '\0';
+ dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
+
+ if (freeable(fldtab[0]))
+ xfree(fldtab[0]->sval);
+ fldtab[0]->tval = REC | STR | DONTFREE;
+ fldtab[0]->sval = record;
+
+ dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
+ dprintf( ("recbld = |%s|\n", record) );
+ donerec = 1;
+}
+
+int errorflag = 0;
+
+void yyerror(char *s)
+{
+ SYNTAX(s);
+}
+
+void SYNTAX(char *fmt, ...)
+{
+ extern char *cmdname, *curfname;
+ static int been_here = 0;
+ va_list varg;
+
+ if (been_here++ > 2)
+ return;
+ fprintf(stderr, "%s: ", cmdname);
+ va_start(varg, fmt);
+ vfprintf(stderr, fmt, varg);
+ va_end(varg);
+ fprintf(stderr, " at source line %d", lineno);
+ if (curfname != NULL)
+ fprintf(stderr, " in function %s", curfname);
+ if (compile_time == 1 && cursource() != NULL)
+ fprintf(stderr, " source file %s", cursource());
+ fprintf(stderr, "\n");
+ errorflag = 2;
+ eprint();
+}
+
+void fpecatch(int n)
+{
+ FATAL("floating point exception %d", n);
+}
+
+extern int bracecnt, brackcnt, parencnt;
+
+void bracecheck(void)
+{
+ int c;
+ static int beenhere = 0;
+
+ if (beenhere++)
+ return;
+ while ((c = input()) != EOF && c != '\0')
+ bclass(c);
+ bcheck2(bracecnt, '{', '}');
+ bcheck2(brackcnt, '[', ']');
+ bcheck2(parencnt, '(', ')');
+}
+
+void bcheck2(int n, int c1, int c2)
+{
+ if (n == 1)
+ fprintf(stderr, "\tmissing %c\n", c2);
+ else if (n > 1)
+ fprintf(stderr, "\t%d missing %c's\n", n, c2);
+ else if (n == -1)
+ fprintf(stderr, "\textra %c\n", c2);
+ else if (n < -1)
+ fprintf(stderr, "\t%d extra %c's\n", -n, c2);
+}
+
+void FATAL(char *fmt, ...)
+{
+ extern char *cmdname;
+ va_list varg;
+
+ fflush(stdout);
+ fprintf(stderr, "%s: ", cmdname);
+ va_start(varg, fmt);
+ vfprintf(stderr, fmt, varg);
+ va_end(varg);
+ error();
+ if (dbg > 1) /* core dump if serious debugging on */
+ abort();
+ exit(2);
+}
+
+void WARNING(char *fmt, ...)
+{
+ extern char *cmdname;
+ va_list varg;
+
+ fflush(stdout);
+ fprintf(stderr, "%s: ", cmdname);
+ va_start(varg, fmt);
+ vfprintf(stderr, fmt, varg);
+ va_end(varg);
+ error();
+}
+
+void error()
+{
+ extern Node *curnode;
+
+ fprintf(stderr, "\n");
+ if (compile_time != 2 && NR && *NR > 0) {
+ fprintf(stderr, " input record number %d", (int) (*FNR));
+ if (strcmp(*FILENAME, "-") != 0)
+ fprintf(stderr, ", file %s", *FILENAME);
+ fprintf(stderr, "\n");
+ }
+ if (compile_time != 2 && curnode)
+ fprintf(stderr, " source line number %d", curnode->lineno);
+ else if (compile_time != 2 && lineno)
+ fprintf(stderr, " source line number %d", lineno);
+ if (compile_time == 1 && cursource() != NULL)
+ fprintf(stderr, " source file %s", cursource());
+ fprintf(stderr, "\n");
+ eprint();
+}
+
+void eprint(void) /* try to print context around error */
+{
+ char *p, *q;
+ int c;
+ static int been_here = 0;
+ extern char ebuf[], *ep;
+
+ if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
+ return;
+ p = ep - 1;
+ if (p > ebuf && *p == '\n')
+ p--;
+ for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
+ ;
+ while (*p == '\n')
+ p++;
+ fprintf(stderr, " context is\n\t");
+ for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
+ ;
+ for ( ; p < q; p++)
+ if (*p)
+ putc(*p, stderr);
+ fprintf(stderr, " >>> ");
+ for ( ; p < ep; p++)
+ if (*p)
+ putc(*p, stderr);
+ fprintf(stderr, " <<< ");
+ if (*ep)
+ while ((c = input()) != '\n' && c != '\0' && c != EOF) {
+ putc(c, stderr);
+ bclass(c);
+ }
+ putc('\n', stderr);
+ ep = ebuf;
+}
+
+void bclass(int c)
+{
+ switch (c) {
+ case '{': bracecnt++; break;
+ case '}': bracecnt--; break;
+ case '[': brackcnt++; break;
+ case ']': brackcnt--; break;
+ case '(': parencnt++; break;
+ case ')': parencnt--; break;
+ }
+}
+
+double errcheck(double x, char *s)
+{
+
+ if (errno == EDOM) {
+ errno = 0;
+ WARNING("%s argument out of domain", s);
+ x = 1;
+ } else if (errno == ERANGE) {
+ errno = 0;
+ WARNING("%s result out of range", s);
+ x = 1;
+ }
+ return x;
+}
+
+int isclvar(char *s) /* is s of form var=something ? */
+{
+ char *os = s;
+
+ if (!isalpha((uschar) *s) && *s != '_')
+ return 0;
+ for ( ; *s; s++)
+ if (!(isalnum((uschar) *s) || *s == '_'))
+ break;
+ return *s == '=' && s > os && *(s+1) != '=';
+}
+
+/* strtod is supposed to be a proper test of what's a valid number */
+/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
+/* wrong: violates 4.10.1.4 of ansi C standard */
+
+#include <math.h>
+int is_number(char *s)
+{
+ double r;
+ char *ep;
+ errno = 0;
+ r = strtod(s, &ep);
+ if (ep == s || r == HUGE_VAL || errno == ERANGE)
+ return 0;
+ while (*ep == ' ' || *ep == '\t' || *ep == '\n')
+ ep++;
+ if (*ep == '\0')
+ return 1;
+ else
+ return 0;
+}
diff --git a/utils/awk/mac.code b/utils/awk/mac.code
new file mode 100644
index 00000000..269d2105
--- /dev/null
+++ b/utils/awk/mac.code
@@ -0,0 +1,65 @@
+This file contains a make shell script and a version
+of the file missing95.c for the Mac, courtesy of
+Dan Allen.
+
+make shell script:
+
+# MPW Shell script to build Awk using Apple's MRC compiler.
+# 22 Jan 1999 - Created by Dan Allen.
+# 25 Mar 1999 - Updated for newer Awk.
+#
+# Porting notes for the Mac:
+#
+# 1. main in main.c needs to have its prototype changed to:
+#
+# int main(int argc, char *argv[], char *environ[])
+#
+# 2. popen and pclose in missing95.c need to have as their body the
+# older style
+#
+# return NULL;
+#
+# as parallel pipes are not supported by MPW.
+#
+# 3. To make your Mac more responsive while long awk scripts run,
+# you may want to add some SpinCursor calls to support cooperative multitasking.
+#
+# All of these minor changes can be put under "#ifdef powerc" for portability's sake.
+#
+#
+
+If {1} == "clean"
+ Delete -i awk maketab maketab.c.o ytab.c.o b.c.o main.c.o parse.c.o proctab.c proctab.c.o tran.c.o lib.c.o run.c.o lex.c.o missing95.c.o
+Else
+ MRC ytab.c -w off -opt speed
+ MRC b.c -w off -opt speed
+ MRC main.c -w off -opt speed
+ MRC parse.c -w off -opt speed
+ MRC maketab.c -w off -opt speed
+ PPCLink -o maketab maketab.c.o "{PPCLibraries}InterfaceLib" "{PPCLibraries}MathLib" "{PPCLibraries}StdCLib" "{PPCLibraries}StdCRuntime.o" "{PPCLibraries}PPCCRuntime.o" "{PPCLibraries}PPCToolLibs.o" -t MPST -c 'MPS '
+ maketab > proctab.c
+ MRC proctab.c -w off -opt speed
+ MRC tran.c -w off -opt speed
+ MRC lib.c -w off -opt speed
+ MRC run.c -w off -opt speed
+ MRC lex.c -w off -opt speed
+ MRC missing95.c -w off -opt speed
+ PPCLink -o awk ytab.c.o b.c.o main.c.o parse.c.o proctab.c.o tran.c.o lib.c.o run.c.o lex.c.o missing95.c.o "{PPCLibraries}InterfaceLib" "{PPCLibraries}MathLib" "{PPCLibraries}StdCLib" "{PPCLibraries}StdCRuntime.o" "{PPCLibraries}PPCCRuntime.o" "{PPCLibraries}PPCToolLibs.o" -d
+ SetFile awk -d . -m . -t MPST -c 'MPS '
+End
+
+
+missing95.c for the Mac:
+
+/* popen and pclose are not available on the Mac. */
+
+#include <stdio.h>
+
+FILE *popen(char *s, char *m) {
+ return NULL;
+}
+
+int pclose(FILE *f) {
+ return NULL;
+}
+
diff --git a/utils/awk/main.c b/utils/awk/main.c
new file mode 100644
index 00000000..d807ca5b
--- /dev/null
+++ b/utils/awk/main.c
@@ -0,0 +1,197 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+char *version = "version 20001115";
+
+#define DEBUG
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include "awk.h"
+#include "ytab.h"
+
+extern char **environ;
+extern int nfields;
+
+int dbg = 0;
+char *cmdname; /* gets argv[0] for error messages */
+extern FILE *yyin; /* lex input file */
+char *lexprog; /* points to program argument if it exists */
+extern int errorflag; /* non-zero if any syntax errors; set by yyerror */
+int compile_time = 2; /* for error printing: */
+ /* 2 = cmdline, 1 = compile, 0 = running */
+
+char *pfile[20]; /* program filenames from -f's */
+int npfile = 0; /* number of filenames */
+int curpfile = 0; /* current filename */
+
+int safe = 0; /* 1 => "safe" mode */
+
+int main(int argc, char *argv[])
+{
+ char *fs = NULL, *marg;
+ int temp;
+
+ cmdname = argv[0];
+ if (argc == 1) {
+ fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname);
+ exit(1);
+ }
+ signal(SIGFPE, fpecatch);
+ yyin = NULL;
+ symtab = makesymtab(NSYMTAB);
+ while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
+ if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
+ argc--;
+ argv++;
+ break;
+ }
+ switch (argv[1][1]) {
+ case 's':
+ if (strcmp(argv[1], "-safe") == 0)
+ safe = 1;
+ break;
+ case 'f': /* next argument is program filename */
+ argc--;
+ argv++;
+ if (argc <= 1)
+ FATAL("no program filename");
+ pfile[npfile++] = argv[1];
+ break;
+ case 'F': /* set field separator */
+ if (argv[1][2] != 0) { /* arg is -Fsomething */
+ if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */
+ fs = "\t";
+ else if (argv[1][2] != 0)
+ fs = &argv[1][2];
+ } else { /* arg is -F something */
+ argc--; argv++;
+ if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */
+ fs = "\t";
+ else if (argc > 1 && argv[1][0] != 0)
+ fs = &argv[1][0];
+ }
+ if (fs == NULL || *fs == '\0')
+ WARNING("field separator FS is empty");
+ break;
+ case 'v': /* -v a=1 to be done NOW. one -v for each */
+ if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1]))
+ setclvar(argv[1]);
+ break;
+ case 'm': /* more memory: -mr=record, -mf=fields */
+ /* no longer needed */
+ marg = argv[1];
+ if (argv[1][3])
+ temp = atoi(&argv[1][3]);
+ else {
+ argv++; argc--;
+ temp = atoi(&argv[1][0]);
+ }
+ switch (marg[2]) {
+ case 'r': recsize = temp; break;
+ case 'f': nfields = temp; break;
+ default: FATAL("unknown option %s\n", marg);
+ }
+ break;
+ case 'd':
+ dbg = atoi(&argv[1][2]);
+ if (dbg == 0)
+ dbg = 1;
+ printf("awk %s\n", version);
+ break;
+ case 'V': /* added for exptools "standard" */
+ printf("awk %s\n", version);
+ exit(0);
+ break;
+ default:
+ WARNING("unknown option %s ignored", argv[1]);
+ break;
+ }
+ argc--;
+ argv++;
+ }
+ /* argv[1] is now the first argument */
+ if (npfile == 0) { /* no -f; first argument is program */
+ if (argc <= 1) {
+ if (dbg)
+ exit(0);
+ FATAL("no program given");
+ }
+ dprintf( ("program = |%s|\n", argv[1]) );
+ lexprog = argv[1];
+ argc--;
+ argv++;
+ }
+ recinit(recsize);
+ syminit();
+ compile_time = 1;
+ argv[0] = cmdname; /* put prog name at front of arglist */
+ dprintf( ("argc=%d, argv[0]=%s\n", argc, argv[0]) );
+ arginit(argc, argv);
+ if (!safe)
+ envinit(environ);
+ yyparse();
+ if (fs)
+ *FS = qstring(fs, '\0');
+ dprintf( ("errorflag=%d\n", errorflag) );
+ if (errorflag == 0) {
+ compile_time = 0;
+ run(winner);
+ } else
+ bracecheck();
+ return(errorflag);
+}
+
+int pgetc(void) /* get 1 character from awk program */
+{
+ int c;
+
+ for (;;) {
+ if (yyin == NULL) {
+ if (curpfile >= npfile)
+ return EOF;
+ if (strcmp(pfile[curpfile], "-") == 0)
+ yyin = stdin;
+ else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
+ FATAL("can't open file %s", pfile[curpfile]);
+ lineno = 1;
+ }
+ if ((c = getc(yyin)) != EOF)
+ return c;
+ if (yyin != stdin)
+ fclose(yyin);
+ yyin = NULL;
+ curpfile++;
+ }
+}
+
+char *cursource(void) /* current source file name */
+{
+ if (npfile > 0)
+ return pfile[curpfile];
+ else
+ return NULL;
+}
diff --git a/utils/awk/makefile b/utils/awk/makefile
new file mode 100644
index 00000000..86520c9e
--- /dev/null
+++ b/utils/awk/makefile
@@ -0,0 +1,81 @@
+# /****************************************************************
+# Copyright (C) Lucent Technologies 1997
+# All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and
+# its documentation for any purpose and without fee is hereby
+# granted, provided that the above copyright notice appear in all
+# copies and that both that the copyright notice and this
+# permission notice and warranty disclaimer appear in supporting
+# documentation, and that the name Lucent Technologies or any of
+# its entities not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.
+#
+# LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+# IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+# THIS SOFTWARE.
+# ****************************************************************/
+
+CFLAGS = -g
+CFLAGS = -O2
+CFLAGS =
+
+CC = gcc -Wall -g
+CC = /opt/pure/purify/purify cc
+CC = cc
+
+YACC = bison -y
+YACC = yacc
+YFLAGS = -d
+
+OFILES = b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o
+
+SOURCE = awk.h ytab.c ytab.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c lib.c run.c tran.c proctab.c missing95.c
+
+LISTING = awk.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c lib.c run.c tran.c missing95.c
+
+SHIP = README FIXES $(SOURCE) ytab[ch].bak makefile awk.1 buildwin.bat mac.code
+
+a.out: ytab.o $(OFILES)
+ $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC) -lm
+
+$(OFILES): awk.h ytab.h proto.h
+
+ytab.o: awk.h proto.h awkgram.y
+ $(YACC) $(YFLAGS) awkgram.y
+ mv y.tab.c ytab.c
+ mv y.tab.h ytab.h
+ $(CC) $(CFLAGS) -c ytab.c
+
+proctab.c: maketab
+ ./maketab >proctab.c
+
+maketab: ytab.h maketab.c
+ $(CC) $(CFLAGS) maketab.c -o maketab
+
+bundle:
+ @cp ytab.h ytabh.bak
+ @cp ytab.c ytabc.bak
+ @bundle $(SHIP)
+
+tar:
+ @cp ytab.h ytabh.bak
+ @cp ytab.c ytabc.bak
+ @bundle $(SHIP) >awk.shar
+ @tar cf awk.tar $(SHIP)
+ gzip awk.tar
+ ls -l awk.tar.gz
+ @zip awk.zip $(SHIP)
+ ls -l awk.zip
+
+names:
+ @echo $(LISTING)
+
+clean:
+ rm -f a.out *.o maketab # proctab.c
diff --git a/utils/awk/maketab.c b/utils/awk/maketab.c
new file mode 100644
index 00000000..10a038c4
--- /dev/null
+++ b/utils/awk/maketab.c
@@ -0,0 +1,168 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+/*
+ * this program makes the table to link function names
+ * and type indices that is used by execute() in run.c.
+ * it finds the indices in ytab.h, produced by yacc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "awk.h"
+#include "ytab.h"
+
+struct xx
+{ int token;
+ char *name;
+ char *pname;
+} proc[] = {
+ { PROGRAM, "program", NULL },
+ { BOR, "boolop", " || " },
+ { AND, "boolop", " && " },
+ { NOT, "boolop", " !" },
+ { NE, "relop", " != " },
+ { EQ, "relop", " == " },
+ { LE, "relop", " <= " },
+ { LT, "relop", " < " },
+ { GE, "relop", " >= " },
+ { GT, "relop", " > " },
+ { ARRAY, "array", NULL },
+ { INDIRECT, "indirect", "$(" },
+ { SUBSTR, "substr", "substr" },
+ { SUB, "sub", "sub" },
+ { GSUB, "gsub", "gsub" },
+ { INDEX, "sindex", "sindex" },
+ { SPRINTF, "awksprintf", "sprintf " },
+ { ADD, "arith", " + " },
+ { MINUS, "arith", " - " },
+ { MULT, "arith", " * " },
+ { DIVIDE, "arith", " / " },
+ { MOD, "arith", " % " },
+ { UMINUS, "arith", " -" },
+ { POWER, "arith", " **" },
+ { PREINCR, "incrdecr", "++" },
+ { POSTINCR, "incrdecr", "++" },
+ { PREDECR, "incrdecr", "--" },
+ { POSTDECR, "incrdecr", "--" },
+ { CAT, "cat", " " },
+ { PASTAT, "pastat", NULL },
+ { PASTAT2, "dopa2", NULL },
+ { MATCH, "matchop", " ~ " },
+ { NOTMATCH, "matchop", " !~ " },
+ { MATCHFCN, "matchop", "matchop" },
+ { INTEST, "intest", "intest" },
+ { PRINTF, "awkprintf", "printf" },
+ { PRINT, "printstat", "print" },
+ { CLOSE, "closefile", "closefile" },
+ { DELETE, "awkdelete", "awkdelete" },
+ { SPLIT, "split", "split" },
+ { ASSIGN, "assign", " = " },
+ { ADDEQ, "assign", " += " },
+ { SUBEQ, "assign", " -= " },
+ { MULTEQ, "assign", " *= " },
+ { DIVEQ, "assign", " /= " },
+ { MODEQ, "assign", " %= " },
+ { POWEQ, "assign", " ^= " },
+ { CONDEXPR, "condexpr", " ?: " },
+ { IF, "ifstat", "if(" },
+ { WHILE, "whilestat", "while(" },
+ { FOR, "forstat", "for(" },
+ { DO, "dostat", "do" },
+ { IN, "instat", "instat" },
+ { NEXT, "jump", "next" },
+ { NEXTFILE, "jump", "nextfile" },
+ { EXIT, "jump", "exit" },
+ { BREAK, "jump", "break" },
+ { CONTINUE, "jump", "continue" },
+ { RETURN, "jump", "ret" },
+ { BLTIN, "bltin", "bltin" },
+ { CALL, "call", "call" },
+ { ARG, "arg", "arg" },
+ { VARNF, "getnf", "NF" },
+ { GETLINE, "getline", "getline" },
+ { 0, "", "" },
+};
+
+#define SIZE (LASTTOKEN - FIRSTTOKEN + 1)
+char *table[SIZE];
+char *names[SIZE];
+
+int main(int argc, char *argv[])
+{
+ struct xx *p;
+ int i, n, tok;
+ char c;
+ FILE *fp;
+ char buf[200], name[200], def[200];
+
+ printf("#include <stdio.h>\n");
+ printf("#include \"awk.h\"\n");
+ printf("#include \"ytab.h\"\n\n");
+ for (i = SIZE; --i >= 0; )
+ names[i] = "";
+
+ if ((fp = fopen("ytab.h", "r")) == NULL) {
+ fprintf(stderr, "maketab can't open ytab.h!\n");
+ exit(1);
+ }
+ printf("static char *printname[%d] = {\n", SIZE);
+ i = 0;
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok);
+ if (c != '#' || (n != 4 && strcmp(def,"define") != 0)) /* not a valid #define */
+ continue;
+ if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
+ fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf);
+ continue;
+ }
+ names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1);
+ strcpy(names[tok-FIRSTTOKEN], name);
+ printf("\t(char *) \"%s\",\t/* %d */\n", name, tok);
+ i++;
+ }
+ printf("};\n\n");
+
+ for (p=proc; p->token!=0; p++)
+ table[p->token-FIRSTTOKEN] = p->name;
+ printf("\nCell *(*proctab[%d])(Node **, int) = {\n", SIZE);
+ for (i=0; i<SIZE; i++)
+ if (table[i]==0)
+ printf("\tnullproc,\t/* %s */\n", names[i]);
+ else
+ printf("\t%s,\t/* %s */\n", table[i], names[i]);
+ printf("};\n\n");
+
+ printf("char *tokname(int n)\n"); /* print a tokname() function */
+ printf("{\n");
+ printf(" static char buf[100];\n\n");
+ printf(" if (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
+ printf(" sprintf(buf, \"token %%d\", n);\n");
+ printf(" return buf;\n");
+ printf(" }\n");
+ printf(" return printname[n-FIRSTTOKEN];\n");
+ printf("}\n");
+ return 0;
+}
diff --git a/utils/awk/missing95.c b/utils/awk/missing95.c
new file mode 100644
index 00000000..64138ade
--- /dev/null
+++ b/utils/awk/missing95.c
@@ -0,0 +1,12 @@
+/* popen and pclose are not part of win 95 and nt,
+ but it appears that _popen and _pclose "work".
+ if this won't load, use the return NULL statements. */
+
+#include <stdio.h>
+FILE *popen(char *s, char *m) {
+ return _popen(s, m); /* return NULL; */
+}
+
+int pclose(FILE *f) {
+ return _pclose(f); /* return NULL; */
+}
diff --git a/utils/awk/mkfile b/utils/awk/mkfile
new file mode 100644
index 00000000..78847147
--- /dev/null
+++ b/utils/awk/mkfile
@@ -0,0 +1,29 @@
+<../../mkconfig
+
+TARG=awk
+
+OFILES=\
+ b.$O\
+ lex.$O\
+ lib.$O\
+ main.$O\
+ missing95.$O\
+ parse.$O\
+ proctab.$O\
+ run.$O\
+ tran.$O\
+ ytab.$O\
+
+HFILES=\
+ awk.h\
+ proto.h\
+ ytab.h\
+
+LIBS=bio # order is important
+
+CFLAGS=$CFLAGS -QIfdiv-
+LDFLAGS=$LDFLAGS setargv.obj
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/awk/parse.c b/utils/awk/parse.c
new file mode 100644
index 00000000..ec7faca8
--- /dev/null
+++ b/utils/awk/parse.c
@@ -0,0 +1,276 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+#define DEBUG
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "awk.h"
+#include "ytab.h"
+
+Node *nodealloc(int n)
+{
+ Node *x;
+
+ x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *));
+ if (x == NULL)
+ FATAL("out of space in nodealloc");
+ x->nnext = NULL;
+ x->lineno = lineno;
+ return(x);
+}
+
+Node *exptostat(Node *a)
+{
+ a->ntype = NSTAT;
+ return(a);
+}
+
+Node *node1(int a, Node *b)
+{
+ Node *x;
+
+ x = nodealloc(1);
+ x->nobj = a;
+ x->narg[0]=b;
+ return(x);
+}
+
+Node *node2(int a, Node *b, Node *c)
+{
+ Node *x;
+
+ x = nodealloc(2);
+ x->nobj = a;
+ x->narg[0] = b;
+ x->narg[1] = c;
+ return(x);
+}
+
+Node *node3(int a, Node *b, Node *c, Node *d)
+{
+ Node *x;
+
+ x = nodealloc(3);
+ x->nobj = a;
+ x->narg[0] = b;
+ x->narg[1] = c;
+ x->narg[2] = d;
+ return(x);
+}
+
+Node *node4(int a, Node *b, Node *c, Node *d, Node *e)
+{
+ Node *x;
+
+ x = nodealloc(4);
+ x->nobj = a;
+ x->narg[0] = b;
+ x->narg[1] = c;
+ x->narg[2] = d;
+ x->narg[3] = e;
+ return(x);
+}
+
+Node *stat1(int a, Node *b)
+{
+ Node *x;
+
+ x = node1(a,b);
+ x->ntype = NSTAT;
+ return(x);
+}
+
+Node *stat2(int a, Node *b, Node *c)
+{
+ Node *x;
+
+ x = node2(a,b,c);
+ x->ntype = NSTAT;
+ return(x);
+}
+
+Node *stat3(int a, Node *b, Node *c, Node *d)
+{
+ Node *x;
+
+ x = node3(a,b,c,d);
+ x->ntype = NSTAT;
+ return(x);
+}
+
+Node *stat4(int a, Node *b, Node *c, Node *d, Node *e)
+{
+ Node *x;
+
+ x = node4(a,b,c,d,e);
+ x->ntype = NSTAT;
+ return(x);
+}
+
+Node *op1(int a, Node *b)
+{
+ Node *x;
+
+ x = node1(a,b);
+ x->ntype = NEXPR;
+ return(x);
+}
+
+Node *op2(int a, Node *b, Node *c)
+{
+ Node *x;
+
+ x = node2(a,b,c);
+ x->ntype = NEXPR;
+ return(x);
+}
+
+Node *op3(int a, Node *b, Node *c, Node *d)
+{
+ Node *x;
+
+ x = node3(a,b,c,d);
+ x->ntype = NEXPR;
+ return(x);
+}
+
+Node *op4(int a, Node *b, Node *c, Node *d, Node *e)
+{
+ Node *x;
+
+ x = node4(a,b,c,d,e);
+ x->ntype = NEXPR;
+ return(x);
+}
+
+Node *celltonode(Cell *a, int b)
+{
+ Node *x;
+
+ a->ctype = OCELL;
+ a->csub = b;
+ x = node1(0, (Node *) a);
+ x->ntype = NVALUE;
+ return(x);
+}
+
+Node *rectonode(void) /* make $0 into a Node */
+{
+ extern Cell *literal0;
+ return op1(INDIRECT, celltonode(literal0, CUNK));
+}
+
+Node *makearr(Node *p)
+{
+ Cell *cp;
+
+ if (isvalue(p)) {
+ cp = (Cell *) (p->narg[0]);
+ if (isfcn(cp))
+ SYNTAX( "%s is a function, not an array", cp->nval );
+ else if (!isarr(cp)) {
+ xfree(cp->sval);
+ cp->sval = (char *) makesymtab(NSYMTAB);
+ cp->tval = ARR;
+ }
+ }
+ return p;
+}
+
+#define PA2NUM 50 /* max number of pat,pat patterns allowed */
+int paircnt; /* number of them in use */
+int pairstack[PA2NUM]; /* state of each pat,pat */
+
+Node *pa2stat(Node *a, Node *b, Node *c) /* pat, pat {...} */
+{
+ Node *x;
+
+ x = node4(PASTAT2, a, b, c, itonp(paircnt));
+ if (paircnt++ >= PA2NUM)
+ SYNTAX( "limited to %d pat,pat statements", PA2NUM );
+ x->ntype = NSTAT;
+ return(x);
+}
+
+Node *linkum(Node *a, Node *b)
+{
+ Node *c;
+
+ if (errorflag) /* don't link things that are wrong */
+ return a;
+ if (a == NULL)
+ return(b);
+ else if (b == NULL)
+ return(a);
+ for (c = a; c->nnext != NULL; c = c->nnext)
+ ;
+ c->nnext = b;
+ return(a);
+}
+
+void defn(Cell *v, Node *vl, Node *st) /* turn on FCN bit in definition, */
+{ /* body of function, arglist */
+ Node *p;
+ int n;
+
+ if (isarr(v)) {
+ SYNTAX( "`%s' is an array name and a function name", v->nval );
+ return;
+ }
+ if (isarg(v->nval) != -1) {
+ SYNTAX( "`%s' is both function name and argument name", v->nval );
+ return;
+ }
+
+ v->tval = FCN;
+ v->sval = (char *) st;
+ n = 0; /* count arguments */
+ for (p = vl; p; p = p->nnext)
+ n++;
+ v->fval = n;
+ dprintf( ("defining func %s (%d args)\n", v->nval, n) );
+}
+
+int isarg(char *s) /* is s in argument list for current function? */
+{ /* return -1 if not, otherwise arg # */
+ extern Node *arglist;
+ Node *p = arglist;
+ int n;
+
+ for (n = 0; p != 0; p = p->nnext, n++)
+ if (strcmp(((Cell *)(p->narg[0]))->nval, s) == 0)
+ return n;
+ return -1;
+}
+
+int ptoi(void *p) /* convert pointer to integer */
+{
+ return (int) (long) p; /* swearing that p fits, of course */
+}
+
+Node *itonp(int i) /* and vice versa */
+{
+ return (Node *) (long) i;
+}
diff --git a/utils/awk/proctab.c b/utils/awk/proctab.c
new file mode 100644
index 00000000..def5b67a
--- /dev/null
+++ b/utils/awk/proctab.c
@@ -0,0 +1,205 @@
+#include <stdio.h>
+#include "awk.h"
+#include "ytab.h"
+
+static char *printname[92] = {
+ (char *) "FIRSTTOKEN", /* 57346 */
+ (char *) "PROGRAM", /* 57347 */
+ (char *) "PASTAT", /* 57348 */
+ (char *) "PASTAT2", /* 57349 */
+ (char *) "XBEGIN", /* 57350 */
+ (char *) "XEND", /* 57351 */
+ (char *) "NL", /* 57352 */
+ (char *) "ARRAY", /* 57353 */
+ (char *) "MATCH", /* 57354 */
+ (char *) "NOTMATCH", /* 57355 */
+ (char *) "MATCHOP", /* 57356 */
+ (char *) "FINAL", /* 57357 */
+ (char *) "DOT", /* 57358 */
+ (char *) "ALL", /* 57359 */
+ (char *) "CCL", /* 57360 */
+ (char *) "NCCL", /* 57361 */
+ (char *) "CHAR", /* 57362 */
+ (char *) "OR", /* 57363 */
+ (char *) "STAR", /* 57364 */
+ (char *) "QUEST", /* 57365 */
+ (char *) "PLUS", /* 57366 */
+ (char *) "AND", /* 57367 */
+ (char *) "BOR", /* 57368 */
+ (char *) "APPEND", /* 57369 */
+ (char *) "EQ", /* 57370 */
+ (char *) "GE", /* 57371 */
+ (char *) "GT", /* 57372 */
+ (char *) "LE", /* 57373 */
+ (char *) "LT", /* 57374 */
+ (char *) "NE", /* 57375 */
+ (char *) "IN", /* 57376 */
+ (char *) "ARG", /* 57377 */
+ (char *) "BLTIN", /* 57378 */
+ (char *) "BREAK", /* 57379 */
+ (char *) "CLOSE", /* 57380 */
+ (char *) "CONTINUE", /* 57381 */
+ (char *) "DELETE", /* 57382 */
+ (char *) "DO", /* 57383 */
+ (char *) "EXIT", /* 57384 */
+ (char *) "FOR", /* 57385 */
+ (char *) "FUNC", /* 57386 */
+ (char *) "SUB", /* 57387 */
+ (char *) "GSUB", /* 57388 */
+ (char *) "IF", /* 57389 */
+ (char *) "INDEX", /* 57390 */
+ (char *) "LSUBSTR", /* 57391 */
+ (char *) "MATCHFCN", /* 57392 */
+ (char *) "NEXT", /* 57393 */
+ (char *) "NEXTFILE", /* 57394 */
+ (char *) "ADD", /* 57395 */
+ (char *) "MINUS", /* 57396 */
+ (char *) "MULT", /* 57397 */
+ (char *) "DIVIDE", /* 57398 */
+ (char *) "MOD", /* 57399 */
+ (char *) "ASSIGN", /* 57400 */
+ (char *) "ASGNOP", /* 57401 */
+ (char *) "ADDEQ", /* 57402 */
+ (char *) "SUBEQ", /* 57403 */
+ (char *) "MULTEQ", /* 57404 */
+ (char *) "DIVEQ", /* 57405 */
+ (char *) "MODEQ", /* 57406 */
+ (char *) "POWEQ", /* 57407 */
+ (char *) "PRINT", /* 57408 */
+ (char *) "PRINTF", /* 57409 */
+ (char *) "SPRINTF", /* 57410 */
+ (char *) "ELSE", /* 57411 */
+ (char *) "INTEST", /* 57412 */
+ (char *) "CONDEXPR", /* 57413 */
+ (char *) "POSTINCR", /* 57414 */
+ (char *) "PREINCR", /* 57415 */
+ (char *) "POSTDECR", /* 57416 */
+ (char *) "PREDECR", /* 57417 */
+ (char *) "VAR", /* 57418 */
+ (char *) "IVAR", /* 57419 */
+ (char *) "VARNF", /* 57420 */
+ (char *) "CALL", /* 57421 */
+ (char *) "NUMBER", /* 57422 */
+ (char *) "STRING", /* 57423 */
+ (char *) "REGEXPR", /* 57424 */
+ (char *) "GETLINE", /* 57425 */
+ (char *) "RETURN", /* 57426 */
+ (char *) "SPLIT", /* 57427 */
+ (char *) "SUBSTR", /* 57428 */
+ (char *) "WHILE", /* 57429 */
+ (char *) "CAT", /* 57430 */
+ (char *) "NOT", /* 57431 */
+ (char *) "UMINUS", /* 57432 */
+ (char *) "POWER", /* 57433 */
+ (char *) "DECR", /* 57434 */
+ (char *) "INCR", /* 57435 */
+ (char *) "INDIRECT", /* 57436 */
+ (char *) "LASTTOKEN", /* 57437 */
+};
+
+
+Cell *(*proctab[92])(Node **, int) = {
+ nullproc, /* FIRSTTOKEN */
+ program, /* PROGRAM */
+ pastat, /* PASTAT */
+ dopa2, /* PASTAT2 */
+ nullproc, /* XBEGIN */
+ nullproc, /* XEND */
+ nullproc, /* NL */
+ array, /* ARRAY */
+ matchop, /* MATCH */
+ matchop, /* NOTMATCH */
+ nullproc, /* MATCHOP */
+ nullproc, /* FINAL */
+ nullproc, /* DOT */
+ nullproc, /* ALL */
+ nullproc, /* CCL */
+ nullproc, /* NCCL */
+ nullproc, /* CHAR */
+ nullproc, /* OR */
+ nullproc, /* STAR */
+ nullproc, /* QUEST */
+ nullproc, /* PLUS */
+ boolop, /* AND */
+ boolop, /* BOR */
+ nullproc, /* APPEND */
+ relop, /* EQ */
+ relop, /* GE */
+ relop, /* GT */
+ relop, /* LE */
+ relop, /* LT */
+ relop, /* NE */
+ instat, /* IN */
+ arg, /* ARG */
+ bltin, /* BLTIN */
+ jump, /* BREAK */
+ closefile, /* CLOSE */
+ jump, /* CONTINUE */
+ awkdelete, /* DELETE */
+ dostat, /* DO */
+ jump, /* EXIT */
+ forstat, /* FOR */
+ nullproc, /* FUNC */
+ sub, /* SUB */
+ gsub, /* GSUB */
+ ifstat, /* IF */
+ sindex, /* INDEX */
+ nullproc, /* LSUBSTR */
+ matchop, /* MATCHFCN */
+ jump, /* NEXT */
+ jump, /* NEXTFILE */
+ arith, /* ADD */
+ arith, /* MINUS */
+ arith, /* MULT */
+ arith, /* DIVIDE */
+ arith, /* MOD */
+ assign, /* ASSIGN */
+ nullproc, /* ASGNOP */
+ assign, /* ADDEQ */
+ assign, /* SUBEQ */
+ assign, /* MULTEQ */
+ assign, /* DIVEQ */
+ assign, /* MODEQ */
+ assign, /* POWEQ */
+ printstat, /* PRINT */
+ awkprintf, /* PRINTF */
+ awksprintf, /* SPRINTF */
+ nullproc, /* ELSE */
+ intest, /* INTEST */
+ condexpr, /* CONDEXPR */
+ incrdecr, /* POSTINCR */
+ incrdecr, /* PREINCR */
+ incrdecr, /* POSTDECR */
+ incrdecr, /* PREDECR */
+ nullproc, /* VAR */
+ nullproc, /* IVAR */
+ getnf, /* VARNF */
+ call, /* CALL */
+ nullproc, /* NUMBER */
+ nullproc, /* STRING */
+ nullproc, /* REGEXPR */
+ getline, /* GETLINE */
+ jump, /* RETURN */
+ split, /* SPLIT */
+ substr, /* SUBSTR */
+ whilestat, /* WHILE */
+ cat, /* CAT */
+ boolop, /* NOT */
+ arith, /* UMINUS */
+ arith, /* POWER */
+ nullproc, /* DECR */
+ nullproc, /* INCR */
+ indirect, /* INDIRECT */
+ nullproc, /* LASTTOKEN */
+};
+
+char *tokname(int n)
+{
+ static char buf[100];
+
+ if (n < FIRSTTOKEN || n > LASTTOKEN) {
+ sprintf(buf, "token %d", n);
+ return buf;
+ }
+ return printname[n-FIRSTTOKEN];
+}
diff --git a/utils/awk/proto.h b/utils/awk/proto.h
new file mode 100644
index 00000000..45f2908d
--- /dev/null
+++ b/utils/awk/proto.h
@@ -0,0 +1,194 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+extern int yywrap(void);
+extern void setfname(Cell *);
+extern int constnode(Node *);
+extern char *strnode(Node *);
+extern Node *notnull(Node *);
+extern int yyparse(void);
+
+extern int yylex(void);
+extern void startreg(void);
+extern int input(void);
+extern void unput(int);
+extern void unputstr(char *);
+extern int yylook(void);
+extern int yyback(int *, int);
+extern int yyinput(void);
+
+extern fa *makedfa(char *, int);
+extern fa *mkdfa(char *, int);
+extern int makeinit(fa *, int);
+extern void penter(Node *);
+extern void freetr(Node *);
+extern int hexstr(char **);
+extern int quoted(char **);
+extern char *cclenter(char *);
+extern void overflo(char *);
+extern void cfoll(fa *, Node *);
+extern int first(Node *);
+extern void follow(Node *);
+extern int member(int, char *);
+extern int match(fa *, char *);
+extern int pmatch(fa *, char *);
+extern int nematch(fa *, char *);
+extern Node *reparse(char *);
+extern Node *regexp(void);
+extern Node *primary(void);
+extern Node *concat(Node *);
+extern Node *alt(Node *);
+extern Node *unary(Node *);
+extern int relex(void);
+extern int cgoto(fa *, int, int);
+extern void freefa(fa *);
+
+extern int pgetc(void);
+extern char *cursource(void);
+
+extern Node *nodealloc(int);
+extern Node *exptostat(Node *);
+extern Node *node1(int, Node *);
+extern Node *node2(int, Node *, Node *);
+extern Node *node3(int, Node *, Node *, Node *);
+extern Node *node4(int, Node *, Node *, Node *, Node *);
+extern Node *stat3(int, Node *, Node *, Node *);
+extern Node *op2(int, Node *, Node *);
+extern Node *op1(int, Node *);
+extern Node *stat1(int, Node *);
+extern Node *op3(int, Node *, Node *, Node *);
+extern Node *op4(int, Node *, Node *, Node *, Node *);
+extern Node *stat2(int, Node *, Node *);
+extern Node *stat4(int, Node *, Node *, Node *, Node *);
+extern Node *celltonode(Cell *, int);
+extern Node *rectonode(void);
+extern Node *makearr(Node *);
+extern Node *pa2stat(Node *, Node *, Node *);
+extern Node *linkum(Node *, Node *);
+extern void defn(Cell *, Node *, Node *);
+extern int isarg(char *);
+extern char *tokname(int);
+extern Cell *(*proctab[])(Node **, int);
+extern int ptoi(void *);
+extern Node *itonp(int);
+
+extern void syminit(void);
+extern void arginit(int, char **);
+extern void envinit(char **);
+extern Array *makesymtab(int);
+extern void freesymtab(Cell *);
+extern void freeelem(Cell *, char *);
+extern Cell *setsymtab(char *, char *, double, unsigned int, Array *);
+extern int hash(char *, int);
+extern void rehash(Array *);
+extern Cell *lookup(char *, Array *);
+extern double setfval(Cell *, double);
+extern void funnyvar(Cell *, char *);
+extern char *setsval(Cell *, char *);
+extern double getfval(Cell *);
+extern char *getsval(Cell *);
+extern char *tostring(char *);
+extern char *qstring(char *, int);
+
+extern void recinit(unsigned int);
+extern void initgetrec(void);
+extern void makefields(int, int);
+extern void growfldtab(int n);
+extern int getrec(char **, int *, int);
+extern void nextfile(void);
+extern int readrec(char **buf, int *bufsize, FILE *inf);
+extern char *getargv(int);
+extern void setclvar(char *);
+extern void fldbld(void);
+extern void cleanfld(int, int);
+extern void newfld(int);
+extern int refldbld(char *, char *);
+extern void recbld(void);
+extern Cell *fieldadr(int);
+extern void yyerror(char *);
+extern void fpecatch(int);
+extern void bracecheck(void);
+extern void bcheck2(int, int, int);
+extern void SYNTAX(char *, ...);
+extern void FATAL(char *, ...);
+extern void WARNING(char *, ...);
+extern void error(void);
+extern void eprint(void);
+extern void bclass(int);
+extern double errcheck(double, char *);
+extern int isclvar(char *);
+extern int is_number(char *);
+
+extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, char *what);
+extern void run(Node *);
+extern Cell *execute(Node *);
+extern Cell *program(Node **, int);
+extern Cell *call(Node **, int);
+extern Cell *copycell(Cell *);
+extern Cell *arg(Node **, int);
+extern Cell *jump(Node **, int);
+extern Cell *getline(Node **, int);
+extern Cell *getnf(Node **, int);
+extern Cell *array(Node **, int);
+extern Cell *awkdelete(Node **, int);
+extern Cell *intest(Node **, int);
+extern Cell *matchop(Node **, int);
+extern Cell *boolop(Node **, int);
+extern Cell *relop(Node **, int);
+extern void tfree(Cell *);
+extern Cell *gettemp(void);
+extern Cell *field(Node **, int);
+extern Cell *indirect(Node **, int);
+extern Cell *substr(Node **, int);
+extern Cell *sindex(Node **, int);
+extern int format(char **, int *, char *, Node *);
+extern Cell *awksprintf(Node **, int);
+extern Cell *awkprintf(Node **, int);
+extern Cell *arith(Node **, int);
+extern double ipow(double, int);
+extern Cell *incrdecr(Node **, int);
+extern Cell *assign(Node **, int);
+extern Cell *cat(Node **, int);
+extern Cell *pastat(Node **, int);
+extern Cell *dopa2(Node **, int);
+extern Cell *split(Node **, int);
+extern Cell *condexpr(Node **, int);
+extern Cell *ifstat(Node **, int);
+extern Cell *whilestat(Node **, int);
+extern Cell *dostat(Node **, int);
+extern Cell *forstat(Node **, int);
+extern Cell *instat(Node **, int);
+extern Cell *bltin(Node **, int);
+extern Cell *printstat(Node **, int);
+extern Cell *nullproc(Node **, int);
+extern FILE *redirect(int, Node *);
+extern FILE *openfile(int, char *);
+extern char *filename(FILE *);
+extern Cell *closefile(Node **, int);
+extern void closeall(void);
+extern Cell *sub(Node **, int);
+extern Cell *gsub(Node **, int);
+
+extern FILE *popen(const char *, const char *);
+extern int pclose(FILE *);
diff --git a/utils/awk/run.c b/utils/awk/run.c
new file mode 100644
index 00000000..a6cbb406
--- /dev/null
+++ b/utils/awk/run.c
@@ -0,0 +1,1891 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+#define DEBUG
+#include <stdio.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "awk.h"
+#include "ytab.h"
+
+#define tempfree(x) if (istemp(x)) tfree(x); else
+
+/*
+#undef tempfree
+
+void tempfree(Cell *p) {
+ if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
+ WARNING("bad csub %d in Cell %d %s",
+ p->csub, p->ctype, p->sval);
+ }
+ if (istemp(p))
+ tfree(p);
+}
+*/
+
+#ifdef _NFILE
+#ifndef FOPEN_MAX
+#define FOPEN_MAX _NFILE
+#endif
+#endif
+
+#ifndef FOPEN_MAX
+#define FOPEN_MAX 40 /* max number of open files */
+#endif
+
+#ifndef RAND_MAX
+#define RAND_MAX 32767 /* all that ansi guarantees */
+#endif
+
+jmp_buf env;
+extern int pairstack[];
+
+Node *winner = NULL; /* root of parse tree */
+Cell *tmps; /* free temporary cells for execution */
+
+static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
+Cell *True = &truecell;
+static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
+Cell *False = &falsecell;
+static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
+Cell *jbreak = &breakcell;
+static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
+Cell *jcont = &contcell;
+static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
+Cell *jnext = &nextcell;
+static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
+Cell *jnextfile = &nextfilecell;
+static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
+Cell *jexit = &exitcell;
+static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
+Cell *jret = &retcell;
+static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
+
+Node *curnode = NULL; /* the node being executed, for debugging */
+
+/* buffer memory management */
+int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
+ char *whatrtn)
+/* pbuf: address of pointer to buffer being managed
+ * psiz: address of buffer size variable
+ * minlen: minimum length of buffer needed
+ * quantum: buffer size quantum
+ * pbptr: address of movable pointer into buffer, or 0 if none
+ * whatrtn: name of the calling routine if failure should cause fatal error
+ *
+ * return 0 for realloc failure, !=0 for success
+ */
+{
+ if (minlen > *psiz) {
+ char *tbuf;
+ int rminlen = quantum ? minlen % quantum : 0;
+ int boff = pbptr ? *pbptr - *pbuf : 0;
+ /* round up to next multiple of quantum */
+ if (rminlen)
+ minlen += quantum - rminlen;
+ tbuf = (char *) realloc(*pbuf, minlen);
+ if (tbuf == NULL) {
+ if (whatrtn)
+ FATAL("out of memory in %s", whatrtn);
+ return 0;
+ }
+ *pbuf = tbuf;
+ *psiz = minlen;
+ if (pbptr)
+ *pbptr = tbuf + boff;
+ }
+ return 1;
+}
+
+void run(Node *a) /* execution of parse tree starts here */
+{
+ extern void stdinit(void);
+
+ stdinit();
+ execute(a);
+ closeall();
+}
+
+Cell *execute(Node *u) /* execute a node of the parse tree */
+{
+ Cell *(*proc)(Node **, int);
+ Cell *x;
+ Node *a;
+
+ if (u == NULL)
+ return(True);
+ for (a = u; ; a = a->nnext) {
+ curnode = a;
+ if (isvalue(a)) {
+ x = (Cell *) (a->narg[0]);
+ if (isfld(x) && !donefld)
+ fldbld();
+ else if (isrec(x) && !donerec)
+ recbld();
+ return(x);
+ }
+ if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
+ FATAL("illegal statement");
+ proc = proctab[a->nobj-FIRSTTOKEN];
+ x = (*proc)(a->narg, a->nobj);
+ if (isfld(x) && !donefld)
+ fldbld();
+ else if (isrec(x) && !donerec)
+ recbld();
+ if (isexpr(a))
+ return(x);
+ if (isjump(x))
+ return(x);
+ if (a->nnext == NULL)
+ return(x);
+ tempfree(x);
+ }
+}
+
+
+Cell *program(Node **a, int n) /* execute an awk program */
+{ /* a[0] = BEGIN, a[1] = body, a[2] = END */
+ Cell *x;
+
+ if (setjmp(env) != 0)
+ goto ex;
+ if (a[0]) { /* BEGIN */
+ x = execute(a[0]);
+ if (isexit(x))
+ return(True);
+ if (isjump(x))
+ FATAL("illegal break, continue, next or nextfile from BEGIN");
+ tempfree(x);
+ }
+ if (a[1] || a[2])
+ while (getrec(&record, &recsize, 1) > 0) {
+ x = execute(a[1]);
+ if (isexit(x))
+ break;
+ tempfree(x);
+ }
+ ex:
+ if (setjmp(env) != 0) /* handles exit within END */
+ goto ex1;
+ if (a[2]) { /* END */
+ x = execute(a[2]);
+ if (isbreak(x) || isnext(x) || iscont(x))
+ FATAL("illegal break, continue, next or nextfile from END");
+ tempfree(x);
+ }
+ ex1:
+ return(True);
+}
+
+struct Frame { /* stack frame for awk function calls */
+ int nargs; /* number of arguments in this call */
+ Cell *fcncell; /* pointer to Cell for function */
+ Cell **args; /* pointer to array of arguments after execute */
+ Cell *retval; /* return value */
+};
+
+#define NARGS 50 /* max args in a call */
+
+struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
+int nframe = 0; /* number of frames allocated */
+struct Frame *fp = NULL; /* frame pointer. bottom level unused */
+
+Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
+{
+ static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
+ int i, ncall, ndef;
+ Node *x;
+ Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
+ Cell *y, *z, *fcn;
+ char *s;
+
+ fcn = execute(a[0]); /* the function itself */
+ s = fcn->nval;
+ if (!isfcn(fcn))
+ FATAL("calling undefined function %s", s);
+ if (frame == NULL) {
+ fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
+ if (frame == NULL)
+ FATAL("out of space for stack frames calling %s", s);
+ }
+ for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
+ ncall++;
+ ndef = (int) fcn->fval; /* args in defn */
+ dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
+ if (ncall > ndef)
+ WARNING("function %s called with %d args, uses only %d",
+ s, ncall, ndef);
+ if (ncall + ndef > NARGS)
+ FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
+ for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
+ dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
+ y = execute(x);
+ oargs[i] = y;
+ dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
+ i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
+ if (isfcn(y))
+ FATAL("can't use function %s as argument in %s", y->nval, s);
+ if (isarr(y))
+ args[i] = y; /* arrays by ref */
+ else
+ args[i] = copycell(y);
+ tempfree(y);
+ }
+ for ( ; i < ndef; i++) { /* add null args for ones not provided */
+ args[i] = gettemp();
+ *args[i] = newcopycell;
+ }
+ fp++; /* now ok to up frame */
+ if (fp >= frame + nframe) {
+ int dfp = fp - frame; /* old index */
+ frame = (struct Frame *)
+ realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
+ if (frame == NULL)
+ FATAL("out of space for stack frames in %s", s);
+ fp = frame + dfp;
+ }
+ fp->fcncell = fcn;
+ fp->args = args;
+ fp->nargs = ndef; /* number defined with (excess are locals) */
+ fp->retval = gettemp();
+
+ dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
+ y = execute((Node *)(fcn->sval)); /* execute body */
+ dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
+
+ for (i = 0; i < ndef; i++) {
+ Cell *t = fp->args[i];
+ if (isarr(t)) {
+ if (t->csub == CCOPY) {
+ if (i >= ncall) {
+ freesymtab(t);
+ t->csub = CTEMP;
+ tempfree(t);
+ } else {
+ oargs[i]->tval = t->tval;
+ oargs[i]->tval &= ~(STR|NUM|DONTFREE);
+ oargs[i]->sval = t->sval;
+ tempfree(t);
+ }
+ }
+ } else if (t != y) { /* kludge to prevent freeing twice */
+ t->csub = CTEMP;
+ tempfree(t);
+ }
+ }
+ tempfree(fcn);
+ if (isexit(y) || isnext(y))
+ return y;
+ tempfree(y); /* this can free twice! */
+ z = fp->retval; /* return value */
+ dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
+ fp--;
+ return(z);
+}
+
+Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
+{
+ Cell *y;
+
+ y = gettemp();
+ y->csub = CCOPY; /* prevents freeing until call is over */
+ y->nval = x->nval; /* BUG? */
+ if (isstr(x))
+ y->sval = tostring(x->sval);
+ y->fval = x->fval;
+ y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
+ /* is DONTFREE right? */
+ return y;
+}
+
+Cell *arg(Node **a, int n) /* nth argument of a function */
+{
+
+ n = ptoi(a[0]); /* argument number, counting from 0 */
+ dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
+ if (n+1 > fp->nargs)
+ FATAL("argument #%d of function %s was not supplied",
+ n+1, fp->fcncell->nval);
+ return fp->args[n];
+}
+
+Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
+{
+ Cell *y;
+
+ switch (n) {
+ case EXIT:
+ if (a[0] != NULL) {
+ y = execute(a[0]);
+ errorflag = (int) getfval(y);
+ tempfree(y);
+ }
+ longjmp(env, 1);
+ case RETURN:
+ if (a[0] != NULL) {
+ y = execute(a[0]);
+ if ((y->tval & (STR|NUM)) == (STR|NUM)) {
+ setsval(fp->retval, getsval(y));
+ fp->retval->fval = getfval(y);
+ fp->retval->tval |= NUM;
+ }
+ else if (y->tval & STR)
+ setsval(fp->retval, getsval(y));
+ else if (y->tval & NUM)
+ setfval(fp->retval, getfval(y));
+ else /* can't happen */
+ FATAL("bad type variable %d", y->tval);
+ tempfree(y);
+ }
+ return(jret);
+ case NEXT:
+ return(jnext);
+ case NEXTFILE:
+ nextfile();
+ return(jnextfile);
+ case BREAK:
+ return(jbreak);
+ case CONTINUE:
+ return(jcont);
+ default: /* can't happen */
+ FATAL("illegal jump type %d", n);
+ }
+ return 0; /* not reached */
+}
+
+Cell *getline(Node **a, int n) /* get next line from specific input */
+{ /* a[0] is variable, a[1] is operator, a[2] is filename */
+ Cell *r, *x;
+ extern Cell **fldtab;
+ FILE *fp;
+ char *buf;
+ int bufsize = recsize;
+ int mode;
+
+ if ((buf = (char *) malloc(bufsize)) == NULL)
+ FATAL("out of memory in getline");
+
+ fflush(stdout); /* in case someone is waiting for a prompt */
+ r = gettemp();
+ if (a[1] != NULL) { /* getline < file */
+ x = execute(a[2]); /* filename */
+ mode = ptoi(a[1]);
+ if (mode == '|') /* input pipe */
+ mode = LE; /* arbitrary flag */
+ fp = openfile(mode, getsval(x));
+ tempfree(x);
+ if (fp == NULL)
+ n = -1;
+ else
+ n = readrec(&buf, &bufsize, fp);
+ if (n <= 0) {
+ ;
+ } else if (a[0] != NULL) { /* getline var <file */
+ x = execute(a[0]);
+ setsval(x, buf);
+ tempfree(x);
+ } else { /* getline <file */
+ setsval(fldtab[0], buf);
+ if (is_number(fldtab[0]->sval)) {
+ fldtab[0]->fval = atof(fldtab[0]->sval);
+ fldtab[0]->tval |= NUM;
+ }
+ }
+ } else { /* bare getline; use current input */
+ if (a[0] == NULL) /* getline */
+ n = getrec(&record, &recsize, 1);
+ else { /* getline var */
+ n = getrec(&buf, &bufsize, 0);
+ x = execute(a[0]);
+ setsval(x, buf);
+ tempfree(x);
+ }
+ }
+ setfval(r, (Awkfloat) n);
+ free(buf);
+ return r;
+}
+
+Cell *getnf(Node **a, int n) /* get NF */
+{
+ if (donefld == 0)
+ fldbld();
+ return (Cell *) a[0];
+}
+
+Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
+{
+ Cell *x, *y, *z;
+ char *s;
+ Node *np;
+ char *buf;
+ int bufsz = recsize;
+ int nsub = strlen(*SUBSEP);
+
+ if ((buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of memory in array");
+
+ x = execute(a[0]); /* Cell* for symbol table */
+ buf[0] = 0;
+ for (np = a[1]; np; np = np->nnext) {
+ y = execute(np); /* subscript */
+ s = getsval(y);
+ if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
+ FATAL("out of memory for %s[%s...]", x->nval, buf);
+ strcat(buf, s);
+ if (np->nnext)
+ strcat(buf, *SUBSEP);
+ tempfree(y);
+ }
+ if (!isarr(x)) {
+ dprintf( ("making %s into an array\n", x->nval) );
+ if (freeable(x))
+ xfree(x->sval);
+ x->tval &= ~(STR|NUM|DONTFREE);
+ x->tval |= ARR;
+ x->sval = (char *) makesymtab(NSYMTAB);
+ }
+ z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
+ z->ctype = OCELL;
+ z->csub = CVAR;
+ tempfree(x);
+ free(buf);
+ return(z);
+}
+
+Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
+{
+ Cell *x, *y;
+ Node *np;
+ char *s;
+ int nsub = strlen(*SUBSEP);
+
+ x = execute(a[0]); /* Cell* for symbol table */
+ if (!isarr(x))
+ return True;
+ if (a[1] == 0) { /* delete the elements, not the table */
+ freesymtab(x);
+ x->tval &= ~STR;
+ x->tval |= ARR;
+ x->sval = (char *) makesymtab(NSYMTAB);
+ } else {
+ int bufsz = recsize;
+ char *buf;
+ if ((buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of memory in adelete");
+ buf[0] = 0;
+ for (np = a[1]; np; np = np->nnext) {
+ y = execute(np); /* subscript */
+ s = getsval(y);
+ if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
+ FATAL("out of memory deleting %s[%s...]", x->nval, buf);
+ strcat(buf, s);
+ if (np->nnext)
+ strcat(buf, *SUBSEP);
+ tempfree(y);
+ }
+ freeelem(x, buf);
+ free(buf);
+ }
+ tempfree(x);
+ return True;
+}
+
+Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
+{
+ Cell *x, *ap, *k;
+ Node *p;
+ char *buf;
+ char *s;
+ int bufsz = recsize;
+ int nsub = strlen(*SUBSEP);
+
+ ap = execute(a[1]); /* array name */
+ if (!isarr(ap)) {
+ dprintf( ("making %s into an array\n", ap->nval) );
+ if (freeable(ap))
+ xfree(ap->sval);
+ ap->tval &= ~(STR|NUM|DONTFREE);
+ ap->tval |= ARR;
+ ap->sval = (char *) makesymtab(NSYMTAB);
+ }
+ if ((buf = (char *) malloc(bufsz)) == NULL) {
+ FATAL("out of memory in intest");
+ }
+ buf[0] = 0;
+ for (p = a[0]; p; p = p->nnext) {
+ x = execute(p); /* expr */
+ s = getsval(x);
+ if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
+ FATAL("out of memory deleting %s[%s...]", x->nval, buf);
+ strcat(buf, s);
+ tempfree(x);
+ if (p->nnext)
+ strcat(buf, *SUBSEP);
+ }
+ k = lookup(buf, (Array *) ap->sval);
+ tempfree(ap);
+ free(buf);
+ if (k == NULL)
+ return(False);
+ else
+ return(True);
+}
+
+
+Cell *matchop(Node **a, int n) /* ~ and match() */
+{
+ Cell *x, *y;
+ char *s, *t;
+ int i;
+ fa *pfa;
+ int (*mf)(fa *, char *) = match, mode = 0;
+
+ if (n == MATCHFCN) {
+ mf = pmatch;
+ mode = 1;
+ }
+ x = execute(a[1]); /* a[1] = target text */
+ s = getsval(x);
+ if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
+ i = (*mf)((fa *) a[2], s);
+ else {
+ y = execute(a[2]); /* a[2] = regular expr */
+ t = getsval(y);
+ pfa = makedfa(t, mode);
+ i = (*mf)(pfa, s);
+ tempfree(y);
+ }
+ tempfree(x);
+ if (n == MATCHFCN) {
+ int start = patbeg - s + 1;
+ if (patlen < 0)
+ start = 0;
+ setfval(rstartloc, (Awkfloat) start);
+ setfval(rlengthloc, (Awkfloat) patlen);
+ x = gettemp();
+ x->tval = NUM;
+ x->fval = start;
+ return x;
+ } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
+ return(True);
+ else
+ return(False);
+}
+
+
+Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
+{
+ Cell *x, *y;
+ int i;
+
+ x = execute(a[0]);
+ i = istrue(x);
+ tempfree(x);
+ switch (n) {
+ case BOR:
+ if (i) return(True);
+ y = execute(a[1]);
+ i = istrue(y);
+ tempfree(y);
+ if (i) return(True);
+ else return(False);
+ case AND:
+ if ( !i ) return(False);
+ y = execute(a[1]);
+ i = istrue(y);
+ tempfree(y);
+ if (i) return(True);
+ else return(False);
+ case NOT:
+ if (i) return(False);
+ else return(True);
+ default: /* can't happen */
+ FATAL("unknown boolean operator %d", n);
+ }
+ return 0; /*NOTREACHED*/
+}
+
+Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
+{
+ int i;
+ Cell *x, *y;
+ Awkfloat j;
+
+ x = execute(a[0]);
+ y = execute(a[1]);
+ if (x->tval&NUM && y->tval&NUM) {
+ j = x->fval - y->fval;
+ i = j<0? -1: (j>0? 1: 0);
+ } else {
+ i = strcmp(getsval(x), getsval(y));
+ }
+ tempfree(x);
+ tempfree(y);
+ switch (n) {
+ case LT: if (i<0) return(True);
+ else return(False);
+ case LE: if (i<=0) return(True);
+ else return(False);
+ case NE: if (i!=0) return(True);
+ else return(False);
+ case EQ: if (i == 0) return(True);
+ else return(False);
+ case GE: if (i>=0) return(True);
+ else return(False);
+ case GT: if (i>0) return(True);
+ else return(False);
+ default: /* can't happen */
+ FATAL("unknown relational operator %d", n);
+ }
+ return 0; /*NOTREACHED*/
+}
+
+void tfree(Cell *a) /* free a tempcell */
+{
+ if (freeable(a)) {
+ dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
+ xfree(a->sval);
+ }
+ if (a == tmps)
+ FATAL("tempcell list is curdled");
+ a->cnext = tmps;
+ tmps = a;
+}
+
+Cell *gettemp(void) /* get a tempcell */
+{ int i;
+ Cell *x;
+
+ if (!tmps) {
+ tmps = (Cell *) calloc(100, sizeof(Cell));
+ if (!tmps)
+ FATAL("out of space for temporaries");
+ for(i = 1; i < 100; i++)
+ tmps[i-1].cnext = &tmps[i];
+ tmps[i-1].cnext = 0;
+ }
+ x = tmps;
+ tmps = x->cnext;
+ *x = tempcell;
+ return(x);
+}
+
+Cell *indirect(Node **a, int n) /* $( a[0] ) */
+{
+ Cell *x;
+ int m;
+ char *s;
+
+ x = execute(a[0]);
+ m = (int) getfval(x);
+ if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
+ FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
+ /* BUG: can x->nval ever be null??? */
+ tempfree(x);
+ x = fieldadr(m);
+ x->ctype = OCELL; /* BUG? why are these needed? */
+ x->csub = CFLD;
+ return(x);
+}
+
+Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
+{
+ int k, m, n;
+ char *s;
+ int temp;
+ Cell *x, *y, *z = 0;
+
+ x = execute(a[0]);
+ y = execute(a[1]);
+ if (a[2] != 0)
+ z = execute(a[2]);
+ s = getsval(x);
+ k = strlen(s) + 1;
+ if (k <= 1) {
+ tempfree(x);
+ tempfree(y);
+ if (a[2] != 0) {
+ tempfree(z);
+ }
+ x = gettemp();
+ setsval(x, "");
+ return(x);
+ }
+ m = (int) getfval(y);
+ if (m <= 0)
+ m = 1;
+ else if (m > k)
+ m = k;
+ tempfree(y);
+ if (a[2] != 0) {
+ n = (int) getfval(z);
+ tempfree(z);
+ } else
+ n = k - 1;
+ if (n < 0)
+ n = 0;
+ else if (n > k - m)
+ n = k - m;
+ dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
+ y = gettemp();
+ temp = s[n+m-1]; /* with thanks to John Linderman */
+ s[n+m-1] = '\0';
+ setsval(y, s + m - 1);
+ s[n+m-1] = temp;
+ tempfree(x);
+ return(y);
+}
+
+Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
+{
+ Cell *x, *y, *z;
+ char *s1, *s2, *p1, *p2, *q;
+ Awkfloat v = 0.0;
+
+ x = execute(a[0]);
+ s1 = getsval(x);
+ y = execute(a[1]);
+ s2 = getsval(y);
+
+ z = gettemp();
+ for (p1 = s1; *p1 != '\0'; p1++) {
+ for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
+ ;
+ if (*p2 == '\0') {
+ v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
+ break;
+ }
+ }
+ tempfree(x);
+ tempfree(y);
+ setfval(z, v);
+ return(z);
+}
+
+#define MAXNUMSIZE 50
+
+int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */
+{
+ char *fmt;
+ char *p, *t, *os;
+ Cell *x;
+ int flag = 0, n;
+ int fmtwd; /* format width */
+ int fmtsz = recsize;
+ char *buf = *pbuf;
+ int bufsize = *pbufsize;
+
+ os = s;
+ p = buf;
+ if ((fmt = (char *) malloc(fmtsz)) == NULL)
+ FATAL("out of memory in format()");
+ while (*s) {
+ adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
+ if (*s != '%') {
+ *p++ = *s++;
+ continue;
+ }
+ if (*(s+1) == '%') {
+ *p++ = '%';
+ s += 2;
+ continue;
+ }
+ /* have to be real careful in case this is a huge number, eg, %100000d */
+ fmtwd = atoi(s+1);
+ if (fmtwd < 0)
+ fmtwd = -fmtwd;
+ adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
+ for (t = fmt; (*t++ = *s) != '\0'; s++) {
+ if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
+ FATAL("format item %.30s... ran format() out of memory", os);
+ if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
+ break; /* the ansi panoply */
+ if (*s == '*') {
+ x = execute(a);
+ a = a->nnext;
+ sprintf(t-1, "%d", fmtwd=(int) getfval(x));
+ if (fmtwd < 0)
+ fmtwd = -fmtwd;
+ adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
+ t = fmt + strlen(fmt);
+ tempfree(x);
+ }
+ }
+ *t = '\0';
+ if (fmtwd < 0)
+ fmtwd = -fmtwd;
+ adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
+
+ switch (*s) {
+ case 'f': case 'e': case 'g': case 'E': case 'G':
+ flag = 1;
+ break;
+ case 'd': case 'i':
+ flag = 2;
+ if(*(s-1) == 'l') break;
+ *(t-1) = 'l';
+ *t = 'd';
+ *++t = '\0';
+ break;
+ case 'o': case 'x': case 'X': case 'u':
+ flag = *(s-1) == 'l' ? 2 : 3;
+ break;
+ case 's':
+ flag = 4;
+ break;
+ case 'c':
+ flag = 5;
+ break;
+ default:
+ WARNING("weird printf conversion %s", fmt);
+ flag = 0;
+ break;
+ }
+ if (a == NULL)
+ FATAL("not enough args in printf(%s)", os);
+ x = execute(a);
+ a = a->nnext;
+ n = MAXNUMSIZE;
+ if (fmtwd > n)
+ n = fmtwd;
+ adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
+ switch (flag) {
+ case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */
+ t = getsval(x);
+ n = strlen(t);
+ if (fmtwd > n)
+ n = fmtwd;
+ adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
+ p += strlen(p);
+ sprintf(p, "%s", t);
+ break;
+ case 1: sprintf(p, fmt, getfval(x)); break;
+ case 2: sprintf(p, fmt, (long) getfval(x)); break;
+ case 3: sprintf(p, fmt, (int) getfval(x)); break;
+ case 4:
+ t = getsval(x);
+ n = strlen(t);
+ if (fmtwd > n)
+ n = fmtwd;
+ if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
+ FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
+ sprintf(p, fmt, t);
+ break;
+ case 5:
+ if (isnum(x)) {
+ if (getfval(x))
+ sprintf(p, fmt, (int) getfval(x));
+ else
+ *p++ = '\0';
+ } else
+ sprintf(p, fmt, getsval(x)[0]);
+ break;
+ }
+ tempfree(x);
+ p += strlen(p);
+ s++;
+ }
+ *p = '\0';
+ free(fmt);
+ for ( ; a; a = a->nnext) /* evaluate any remaining args */
+ execute(a);
+ *pbuf = buf;
+ *pbufsize = bufsize;
+ return p - buf;
+}
+
+Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
+{
+ Cell *x;
+ Node *y;
+ char *buf;
+ int bufsz=3*recsize;
+
+ if ((buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of memory in awksprintf");
+ y = a[0]->nnext;
+ x = execute(a[0]);
+ if (format(&buf, &bufsz, getsval(x), y) == -1)
+ FATAL("sprintf string %.30s... too long. can't happen.", buf);
+ tempfree(x);
+ x = gettemp();
+ x->sval = buf;
+ x->tval = STR;
+ return(x);
+}
+
+Cell *awkprintf(Node **a, int n) /* printf */
+{ /* a[0] is list of args, starting with format string */
+ /* a[1] is redirection operator, a[2] is redirection file */
+ FILE *fp;
+ Cell *x;
+ Node *y;
+ char *buf;
+ int len;
+ int bufsz=3*recsize;
+
+ if ((buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of memory in awkprintf");
+ y = a[0]->nnext;
+ x = execute(a[0]);
+ if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
+ FATAL("printf string %.30s... too long. can't happen.", buf);
+ tempfree(x);
+ if (a[1] == NULL) {
+ /* fputs(buf, stdout); */
+ fwrite(buf, len, 1, stdout);
+ if (ferror(stdout))
+ FATAL("write error on stdout");
+ } else {
+ fp = redirect(ptoi(a[1]), a[2]);
+ /* fputs(buf, fp); */
+ fwrite(buf, len, 1, fp);
+ fflush(fp);
+ if (ferror(fp))
+ FATAL("write error on %s", filename(fp));
+ }
+ free(buf);
+ return(True);
+}
+
+Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
+{
+ Awkfloat i, j = 0;
+ double v;
+ Cell *x, *y, *z;
+
+ x = execute(a[0]);
+ i = getfval(x);
+ tempfree(x);
+ if (n != UMINUS) {
+ y = execute(a[1]);
+ j = getfval(y);
+ tempfree(y);
+ }
+ z = gettemp();
+ switch (n) {
+ case ADD:
+ i += j;
+ break;
+ case MINUS:
+ i -= j;
+ break;
+ case MULT:
+ i *= j;
+ break;
+ case DIVIDE:
+ if (j == 0)
+ FATAL("division by zero");
+ i /= j;
+ break;
+ case MOD:
+ if (j == 0)
+ FATAL("division by zero in mod");
+ modf(i/j, &v);
+ i = i - j * v;
+ break;
+ case UMINUS:
+ i = -i;
+ break;
+ case POWER:
+ if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
+ i = ipow(i, (int) j);
+ else
+ i = errcheck(pow(i, j), "pow");
+ break;
+ default: /* can't happen */
+ FATAL("illegal arithmetic operator %d", n);
+ }
+ setfval(z, i);
+ return(z);
+}
+
+double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
+{
+ double v;
+
+ if (n <= 0)
+ return 1;
+ v = ipow(x, n/2);
+ if (n % 2 == 0)
+ return v * v;
+ else
+ return x * v * v;
+}
+
+Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
+{
+ Cell *x, *z;
+ int k;
+ Awkfloat xf;
+
+ x = execute(a[0]);
+ xf = getfval(x);
+ k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
+ if (n == PREINCR || n == PREDECR) {
+ setfval(x, xf + k);
+ return(x);
+ }
+ z = gettemp();
+ setfval(z, xf);
+ setfval(x, xf + k);
+ tempfree(x);
+ return(z);
+}
+
+Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
+{ /* this is subtle; don't muck with it. */
+ Cell *x, *y;
+ Awkfloat xf, yf;
+ double v;
+
+ y = execute(a[1]);
+ x = execute(a[0]);
+ if (n == ASSIGN) { /* ordinary assignment */
+ if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
+ ; /* leave alone unless it's a field */
+ else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
+ setsval(x, getsval(y));
+ x->fval = getfval(y);
+ x->tval |= NUM;
+ }
+ else if (isstr(y))
+ setsval(x, getsval(y));
+ else if (isnum(y))
+ setfval(x, getfval(y));
+ else
+ funnyvar(y, "read value of");
+ tempfree(y);
+ return(x);
+ }
+ xf = getfval(x);
+ yf = getfval(y);
+ switch (n) {
+ case ADDEQ:
+ xf += yf;
+ break;
+ case SUBEQ:
+ xf -= yf;
+ break;
+ case MULTEQ:
+ xf *= yf;
+ break;
+ case DIVEQ:
+ if (yf == 0)
+ FATAL("division by zero in /=");
+ xf /= yf;
+ break;
+ case MODEQ:
+ if (yf == 0)
+ FATAL("division by zero in %%=");
+ modf(xf/yf, &v);
+ xf = xf - yf * v;
+ break;
+ case POWEQ:
+ if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
+ xf = ipow(xf, (int) yf);
+ else
+ xf = errcheck(pow(xf, yf), "pow");
+ break;
+ default:
+ FATAL("illegal assignment operator %d", n);
+ break;
+ }
+ tempfree(y);
+ setfval(x, xf);
+ return(x);
+}
+
+Cell *cat(Node **a, int q) /* a[0] cat a[1] */
+{
+ Cell *x, *y, *z;
+ int n1, n2;
+ char *s;
+
+ x = execute(a[0]);
+ y = execute(a[1]);
+ getsval(x);
+ getsval(y);
+ n1 = strlen(x->sval);
+ n2 = strlen(y->sval);
+ s = (char *) malloc(n1 + n2 + 1);
+ if (s == NULL)
+ FATAL("out of space concatenating %.15s... and %.15s...",
+ x->sval, y->sval);
+ strcpy(s, x->sval);
+ strcpy(s+n1, y->sval);
+ tempfree(y);
+ z = gettemp();
+ z->sval = s;
+ z->tval = STR;
+ tempfree(x);
+ return(z);
+}
+
+Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
+{
+ Cell *x;
+
+ if (a[0] == 0)
+ x = execute(a[1]);
+ else {
+ x = execute(a[0]);
+ if (istrue(x)) {
+ tempfree(x);
+ x = execute(a[1]);
+ }
+ }
+ return x;
+}
+
+Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
+{
+ Cell *x;
+ int pair;
+
+ pair = ptoi(a[3]);
+ if (pairstack[pair] == 0) {
+ x = execute(a[0]);
+ if (istrue(x))
+ pairstack[pair] = 1;
+ tempfree(x);
+ }
+ if (pairstack[pair] == 1) {
+ x = execute(a[1]);
+ if (istrue(x))
+ pairstack[pair] = 0;
+ tempfree(x);
+ x = execute(a[2]);
+ return(x);
+ }
+ return(False);
+}
+
+Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
+{
+ Cell *x = 0, *y, *ap;
+ char *s;
+ int sep;
+ char *t, temp, num[50], *fs = 0;
+ int n, tempstat, arg3type;
+
+ y = execute(a[0]); /* source string */
+ s = getsval(y);
+ arg3type = ptoi(a[3]);
+ if (a[2] == 0) /* fs string */
+ fs = *FS;
+ else if (arg3type == STRING) { /* split(str,arr,"string") */
+ x = execute(a[2]);
+ fs = getsval(x);
+ } else if (arg3type == REGEXPR)
+ fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
+ else
+ FATAL("illegal type of split");
+ sep = *fs;
+ ap = execute(a[1]); /* array name */
+ freesymtab(ap);
+ dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
+ ap->tval &= ~STR;
+ ap->tval |= ARR;
+ ap->sval = (char *) makesymtab(NSYMTAB);
+
+ n = 0;
+ if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
+ fa *pfa;
+ if (arg3type == REGEXPR) { /* it's ready already */
+ pfa = (fa *) a[2];
+ } else {
+ pfa = makedfa(fs, 1);
+ }
+ if (nematch(pfa,s)) {
+ tempstat = pfa->initstat;
+ pfa->initstat = 2;
+ do {
+ n++;
+ sprintf(num, "%d", n);
+ temp = *patbeg;
+ *patbeg = '\0';
+ if (is_number(s))
+ setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
+ else
+ setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
+ *patbeg = temp;
+ s = patbeg + patlen;
+ if (*(patbeg+patlen-1) == 0 || *s == 0) {
+ n++;
+ sprintf(num, "%d", n);
+ setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
+ pfa->initstat = tempstat;
+ goto spdone;
+ }
+ } while (nematch(pfa,s));
+ }
+ n++;
+ sprintf(num, "%d", n);
+ if (is_number(s))
+ setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
+ else
+ setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
+ spdone:
+ pfa = NULL;
+ } else if (sep == ' ') {
+ for (n = 0; ; ) {
+ while (*s == ' ' || *s == '\t' || *s == '\n')
+ s++;
+ if (*s == 0)
+ break;
+ n++;
+ t = s;
+ do
+ s++;
+ while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
+ temp = *s;
+ *s = '\0';
+ sprintf(num, "%d", n);
+ if (is_number(t))
+ setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
+ else
+ setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
+ *s = temp;
+ if (*s != 0)
+ s++;
+ }
+ } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
+ for (n = 0; *s != 0; s++) {
+ char buf[2];
+ n++;
+ sprintf(num, "%d", n);
+ buf[0] = *s;
+ buf[1] = 0;
+ if (isdigit((uschar)buf[0]))
+ setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
+ else
+ setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
+ }
+ } else if (*s != 0) {
+ for (;;) {
+ n++;
+ t = s;
+ while (*s != sep && *s != '\n' && *s != '\0')
+ s++;
+ temp = *s;
+ *s = '\0';
+ sprintf(num, "%d", n);
+ if (is_number(t))
+ setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
+ else
+ setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
+ *s = temp;
+ if (*s++ == 0)
+ break;
+ }
+ }
+ tempfree(ap);
+ tempfree(y);
+ if (a[2] != 0 && arg3type == STRING) {
+ tempfree(x);
+ }
+ x = gettemp();
+ x->tval = NUM;
+ x->fval = n;
+ return(x);
+}
+
+Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
+{
+ Cell *x;
+
+ x = execute(a[0]);
+ if (istrue(x)) {
+ tempfree(x);
+ x = execute(a[1]);
+ } else {
+ tempfree(x);
+ x = execute(a[2]);
+ }
+ return(x);
+}
+
+Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
+{
+ Cell *x;
+
+ x = execute(a[0]);
+ if (istrue(x)) {
+ tempfree(x);
+ x = execute(a[1]);
+ } else if (a[2] != 0) {
+ tempfree(x);
+ x = execute(a[2]);
+ }
+ return(x);
+}
+
+Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
+{
+ Cell *x;
+
+ for (;;) {
+ x = execute(a[0]);
+ if (!istrue(x))
+ return(x);
+ tempfree(x);
+ x = execute(a[1]);
+ if (isbreak(x)) {
+ x = True;
+ return(x);
+ }
+ if (isnext(x) || isexit(x) || isret(x))
+ return(x);
+ tempfree(x);
+ }
+}
+
+Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
+{
+ Cell *x;
+
+ for (;;) {
+ x = execute(a[0]);
+ if (isbreak(x))
+ return True;
+ if (isnext(x) || isexit(x) || isret(x))
+ return(x);
+ tempfree(x);
+ x = execute(a[1]);
+ if (!istrue(x))
+ return(x);
+ tempfree(x);
+ }
+}
+
+Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
+{
+ Cell *x;
+
+ x = execute(a[0]);
+ tempfree(x);
+ for (;;) {
+ if (a[1]!=0) {
+ x = execute(a[1]);
+ if (!istrue(x)) return(x);
+ else tempfree(x);
+ }
+ x = execute(a[3]);
+ if (isbreak(x)) /* turn off break */
+ return True;
+ if (isnext(x) || isexit(x) || isret(x))
+ return(x);
+ tempfree(x);
+ x = execute(a[2]);
+ tempfree(x);
+ }
+}
+
+Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
+{
+ Cell *x, *vp, *arrayp, *cp, *ncp;
+ Array *tp;
+ int i;
+
+ vp = execute(a[0]);
+ arrayp = execute(a[1]);
+ if (!isarr(arrayp)) {
+ return True;
+ }
+ tp = (Array *) arrayp->sval;
+ tempfree(arrayp);
+ for (i = 0; i < tp->size; i++) { /* this routine knows too much */
+ for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
+ setsval(vp, cp->nval);
+ ncp = cp->cnext;
+ x = execute(a[2]);
+ if (isbreak(x)) {
+ tempfree(vp);
+ return True;
+ }
+ if (isnext(x) || isexit(x) || isret(x)) {
+ tempfree(vp);
+ return(x);
+ }
+ tempfree(x);
+ }
+ }
+ return True;
+}
+
+Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
+{
+ Cell *x, *y;
+ Awkfloat u;
+ int t;
+ char *p, *buf;
+ Node *nextarg;
+ FILE *fp;
+
+ t = ptoi(a[0]);
+ x = execute(a[1]);
+ nextarg = a[1]->nnext;
+ switch (t) {
+ case FLENGTH:
+ u = strlen(getsval(x)); break;
+ case FLOG:
+ u = errcheck(log(getfval(x)), "log"); break;
+ case FINT:
+ modf(getfval(x), &u); break;
+ case FEXP:
+ u = errcheck(exp(getfval(x)), "exp"); break;
+ case FSQRT:
+ u = errcheck(sqrt(getfval(x)), "sqrt"); break;
+ case FSIN:
+ u = sin(getfval(x)); break;
+ case FCOS:
+ u = cos(getfval(x)); break;
+ case FATAN:
+ if (nextarg == 0) {
+ WARNING("atan2 requires two arguments; returning 1.0");
+ u = 1.0;
+ } else {
+ y = execute(a[1]->nnext);
+ u = atan2(getfval(x), getfval(y));
+ tempfree(y);
+ nextarg = nextarg->nnext;
+ }
+ break;
+ case FSYSTEM:
+ fflush(stdout); /* in case something is buffered already */
+ u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
+ break;
+ case FRAND:
+ /* in principle, rand() returns something in 0..RAND_MAX */
+ u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
+ break;
+ case FSRAND:
+ if (isrec(x)) /* no argument provided */
+ u = time((time_t *)0);
+ else
+ u = getfval(x);
+ srand((unsigned int) u);
+ break;
+ case FTOUPPER:
+ case FTOLOWER:
+ buf = tostring(getsval(x));
+ if (t == FTOUPPER) {
+ for (p = buf; *p; p++)
+ if (islower((uschar) *p))
+ *p = toupper(*p);
+ } else {
+ for (p = buf; *p; p++)
+ if (isupper((uschar) *p))
+ *p = tolower(*p);
+ }
+ tempfree(x);
+ x = gettemp();
+ setsval(x, buf);
+ free(buf);
+ return x;
+ case FFLUSH:
+ if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
+ u = EOF;
+ else
+ u = fflush(fp);
+ break;
+ default: /* can't happen */
+ FATAL("illegal function type %d", t);
+ break;
+ }
+ tempfree(x);
+ x = gettemp();
+ setfval(x, u);
+ if (nextarg != 0) {
+ WARNING("warning: function has too many arguments");
+ for ( ; nextarg; nextarg = nextarg->nnext)
+ execute(nextarg);
+ }
+ return(x);
+}
+
+Cell *printstat(Node **a, int n) /* print a[0] */
+{
+ Node *x;
+ Cell *y;
+ FILE *fp;
+
+ if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
+ fp = stdout;
+ else
+ fp = redirect(ptoi(a[1]), a[2]);
+ for (x = a[0]; x != NULL; x = x->nnext) {
+ y = execute(x);
+ fputs(getsval(y), fp);
+ tempfree(y);
+ if (x->nnext == NULL)
+ fputs(*ORS, fp);
+ else
+ fputs(*OFS, fp);
+ }
+ if (a[1] != 0)
+ fflush(fp);
+ if (ferror(fp))
+ FATAL("write error on %s", filename(fp));
+ return(True);
+}
+
+Cell *nullproc(Node **a, int n)
+{
+ n = n;
+ a = a;
+ return 0;
+}
+
+
+FILE *redirect(int a, Node *b) /* set up all i/o redirections */
+{
+ FILE *fp;
+ Cell *x;
+ char *fname;
+
+ x = execute(b);
+ fname = getsval(x);
+ fp = openfile(a, fname);
+ if (fp == NULL)
+ FATAL("can't open file %s", fname);
+ tempfree(x);
+ return fp;
+}
+
+struct files {
+ FILE *fp;
+ char *fname;
+ int mode; /* '|', 'a', 'w' => LE/LT, GT */
+} files[FOPEN_MAX] ={
+ { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
+ { NULL, "/dev/stdout", GT },
+ { NULL, "/dev/stderr", GT }
+};
+
+void stdinit(void) /* in case stdin, etc., are not constants */
+{
+ files[0].fp = stdin;
+ files[1].fp = stdout;
+ files[2].fp = stderr;
+}
+
+FILE *openfile(int a, char *us)
+{
+ char *s = us;
+ int i, m;
+ FILE *fp = 0;
+
+ if (*s == '\0')
+ FATAL("null file name in print or getline");
+ for (i=0; i < FOPEN_MAX; i++)
+ if (files[i].fname && strcmp(s, files[i].fname) == 0) {
+ if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
+ return files[i].fp;
+ if (a == FFLUSH)
+ return files[i].fp;
+ }
+ if (a == FFLUSH) /* didn't find it, so don't create it! */
+ return NULL;
+
+ for (i=0; i < FOPEN_MAX; i++)
+ if (files[i].fp == 0)
+ break;
+ if (i >= FOPEN_MAX)
+ FATAL("%s makes too many open files", s);
+ fflush(stdout); /* force a semblance of order */
+ m = a;
+ if (a == GT) {
+ fp = fopen(s, "w");
+ } else if (a == APPEND) {
+ fp = fopen(s, "a");
+ m = GT; /* so can mix > and >> */
+ } else if (a == '|') { /* output pipe */
+ fp = popen(s, "w");
+ } else if (a == LE) { /* input pipe */
+ fp = popen(s, "r");
+ } else if (a == LT) { /* getline <file */
+ fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
+ } else /* can't happen */
+ FATAL("illegal redirection %d", a);
+ if (fp != NULL) {
+ files[i].fname = tostring(s);
+ files[i].fp = fp;
+ files[i].mode = m;
+ }
+ return fp;
+}
+
+char *filename(FILE *fp)
+{
+ int i;
+
+ for (i = 0; i < FOPEN_MAX; i++)
+ if (fp == files[i].fp)
+ return files[i].fname;
+ return "???";
+}
+
+Cell *closefile(Node **a, int n)
+{
+ Cell *x;
+ int i, stat;
+
+ n = n;
+ x = execute(a[0]);
+ getsval(x);
+ stat = -1;
+ for (i = 0; i < FOPEN_MAX; i++) {
+ if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
+ if (ferror(files[i].fp))
+ WARNING( "i/o error occurred on %s", files[i].fname );
+ if (files[i].mode == '|' || files[i].mode == LE)
+ stat = pclose(files[i].fp);
+ else
+ stat = fclose(files[i].fp);
+ if (stat == EOF)
+ WARNING( "i/o error occurred closing %s", files[i].fname );
+ if (i > 2) /* don't do /dev/std... */
+ xfree(files[i].fname);
+ files[i].fname = NULL; /* watch out for ref thru this */
+ files[i].fp = NULL;
+ }
+ }
+ tempfree(x);
+ x = gettemp();
+ setfval(x, (Awkfloat) stat);
+ return(x);
+}
+
+void closeall(void)
+{
+ int i, stat;
+
+ for (i = 0; i < FOPEN_MAX; i++) {
+ if (files[i].fp) {
+ if (ferror(files[i].fp))
+ WARNING( "i/o error occurred on %s", files[i].fname );
+ if (files[i].mode == '|' || files[i].mode == LE)
+ stat = pclose(files[i].fp);
+ else
+ stat = fclose(files[i].fp);
+ if (stat == EOF && i != 0)
+ WARNING( "i/o error occurred while closing %s", files[i].fname );
+ }
+ }
+}
+
+void backsub(char **pb_ptr, char **sptr_ptr);
+
+Cell *sub(Node **a, int nnn) /* substitute command */
+{
+ char *sptr, *pb, *q;
+ Cell *x, *y, *result;
+ char *t, *buf;
+ fa *pfa;
+ int bufsz = recsize;
+
+ if ((buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of memory in sub");
+ x = execute(a[3]); /* target string */
+ t = getsval(x);
+ if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
+ pfa = (fa *) a[1]; /* regular expression */
+ else {
+ y = execute(a[1]);
+ pfa = makedfa(getsval(y), 1);
+ tempfree(y);
+ }
+ y = execute(a[2]); /* replacement string */
+ result = False;
+ if (pmatch(pfa, t)) {
+ sptr = t;
+ adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
+ pb = buf;
+ while (sptr < patbeg)
+ *pb++ = *sptr++;
+ sptr = getsval(y);
+ while (*sptr != 0) {
+ adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
+ if (*sptr == '\\') {
+ backsub(&pb, &sptr);
+ } else if (*sptr == '&') {
+ sptr++;
+ adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
+ for (q = patbeg; q < patbeg+patlen; )
+ *pb++ = *q++;
+ } else
+ *pb++ = *sptr++;
+ }
+ *pb = '\0';
+ if (pb > buf + bufsz)
+ FATAL("sub result1 %.30s too big; can't happen", buf);
+ sptr = patbeg + patlen;
+ if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
+ adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
+ while ((*pb++ = *sptr++) != 0)
+ ;
+ }
+ if (pb > buf + bufsz)
+ FATAL("sub result2 %.30s too big; can't happen", buf);
+ setsval(x, buf); /* BUG: should be able to avoid copy */
+ result = True;;
+ }
+ tempfree(x);
+ tempfree(y);
+ free(buf);
+ return result;
+}
+
+Cell *gsub(Node **a, int nnn) /* global substitute */
+{
+ Cell *x, *y;
+ char *rptr, *sptr, *t, *pb, *q;
+ char *buf;
+ fa *pfa;
+ int mflag, tempstat, num;
+ int bufsz = recsize;
+
+ if ((buf = (char *) malloc(bufsz)) == NULL)
+ FATAL("out of memory in gsub");
+ mflag = 0; /* if mflag == 0, can replace empty string */
+ num = 0;
+ x = execute(a[3]); /* target string */
+ t = getsval(x);
+ if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
+ pfa = (fa *) a[1]; /* regular expression */
+ else {
+ y = execute(a[1]);
+ pfa = makedfa(getsval(y), 1);
+ tempfree(y);
+ }
+ y = execute(a[2]); /* replacement string */
+ if (pmatch(pfa, t)) {
+ tempstat = pfa->initstat;
+ pfa->initstat = 2;
+ pb = buf;
+ rptr = getsval(y);
+ do {
+ if (patlen == 0 && *patbeg != 0) { /* matched empty string */
+ if (mflag == 0) { /* can replace empty */
+ num++;
+ sptr = rptr;
+ while (*sptr != 0) {
+ adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
+ if (*sptr == '\\') {
+ backsub(&pb, &sptr);
+ } else if (*sptr == '&') {
+ sptr++;
+ adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
+ for (q = patbeg; q < patbeg+patlen; )
+ *pb++ = *q++;
+ } else
+ *pb++ = *sptr++;
+ }
+ }
+ if (*t == 0) /* at end */
+ goto done;
+ adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
+ *pb++ = *t++;
+ if (pb > buf + bufsz) /* BUG: not sure of this test */
+ FATAL("gsub result0 %.30s too big; can't happen", buf);
+ mflag = 0;
+ }
+ else { /* matched nonempty string */
+ num++;
+ sptr = t;
+ adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
+ while (sptr < patbeg)
+ *pb++ = *sptr++;
+ sptr = rptr;
+ while (*sptr != 0) {
+ adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
+ if (*sptr == '\\') {
+ backsub(&pb, &sptr);
+ } else if (*sptr == '&') {
+ sptr++;
+ adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
+ for (q = patbeg; q < patbeg+patlen; )
+ *pb++ = *q++;
+ } else
+ *pb++ = *sptr++;
+ }
+ t = patbeg + patlen;
+ if (patlen == 0 || *t == 0 || *(t-1) == 0)
+ goto done;
+ if (pb > buf + bufsz)
+ FATAL("gsub result1 %.30s too big; can't happen", buf);
+ mflag = 1;
+ }
+ } while (pmatch(pfa,t));
+ sptr = t;
+ adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
+ while ((*pb++ = *sptr++) != 0)
+ ;
+ done: if (pb > buf + bufsz)
+ FATAL("gsub result2 %.30s too big; can't happen", buf);
+ *pb = '\0';
+ setsval(x, buf); /* BUG: should be able to avoid copy + free */
+ pfa->initstat = tempstat;
+ }
+ tempfree(x);
+ tempfree(y);
+ x = gettemp();
+ x->tval = NUM;
+ x->fval = num;
+ free(buf);
+ return(x);
+}
+
+void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
+{ /* sptr[0] == '\\' */
+ char *pb = *pb_ptr, *sptr = *sptr_ptr;
+
+ if (sptr[1] == '\\') {
+ if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
+ *pb++ = '\\';
+ *pb++ = '&';
+ sptr += 4;
+ } else if (sptr[2] == '&') { /* \\& -> \ + matched */
+ *pb++ = '\\';
+ sptr += 2;
+ } else { /* \\x -> \\x */
+ *pb++ = *sptr++;
+ *pb++ = *sptr++;
+ }
+ } else if (sptr[1] == '&') { /* literal & */
+ sptr++;
+ *pb++ = *sptr++;
+ } else /* literal \ */
+ *pb++ = *sptr++;
+
+ *pb_ptr = pb;
+ *sptr_ptr = sptr;
+}
diff --git a/utils/awk/tran.c b/utils/awk/tran.c
new file mode 100644
index 00000000..8e0faf0d
--- /dev/null
+++ b/utils/awk/tran.c
@@ -0,0 +1,437 @@
+/****************************************************************
+Copyright (C) Lucent Technologies 1997
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name Lucent Technologies or any of
+its entities not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+#define DEBUG
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "awk.h"
+#include "ytab.h"
+
+#define FULLTAB 2 /* rehash when table gets this x full */
+#define GROWTAB 4 /* grow table by this factor */
+
+Array *symtab; /* main symbol table */
+
+char **FS; /* initial field sep */
+char **RS; /* initial record sep */
+char **OFS; /* output field sep */
+char **ORS; /* output record sep */
+char **OFMT; /* output format for numbers */
+char **CONVFMT; /* format for conversions in getsval */
+Awkfloat *NF; /* number of fields in current record */
+Awkfloat *NR; /* number of current record */
+Awkfloat *FNR; /* number of current record in current file */
+char **FILENAME; /* current filename argument */
+Awkfloat *ARGC; /* number of arguments from command line */
+char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
+Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
+Awkfloat *RLENGTH; /* length of same */
+
+Cell *nrloc; /* NR */
+Cell *nfloc; /* NF */
+Cell *fnrloc; /* FNR */
+Array *ARGVtab; /* symbol table containing ARGV[...] */
+Array *ENVtab; /* symbol table containing ENVIRON[...] */
+Cell *rstartloc; /* RSTART */
+Cell *rlengthloc; /* RLENGTH */
+Cell *symtabloc; /* SYMTAB */
+
+Cell *nullloc; /* a guaranteed empty cell */
+Node *nullnode; /* zero&null, converted into a node for comparisons */
+Cell *literal0;
+
+extern Cell **fldtab;
+
+void syminit(void) /* initialize symbol table with builtin vars */
+{
+ literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
+ /* this is used for if(x)... tests: */
+ nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
+ nullnode = celltonode(nullloc, CCON);
+
+ FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
+ RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
+ OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
+ ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
+ OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
+ CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
+ FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
+ nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
+ NF = &nfloc->fval;
+ nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
+ NR = &nrloc->fval;
+ fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
+ FNR = &fnrloc->fval;
+ SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
+ rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
+ RSTART = &rstartloc->fval;
+ rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
+ RLENGTH = &rlengthloc->fval;
+ symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
+ symtabloc->sval = (char *) symtab;
+}
+
+void arginit(int ac, char **av) /* set up ARGV and ARGC */
+{
+ Cell *cp;
+ int i;
+ char temp[50];
+
+ ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
+ cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
+ ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
+ cp->sval = (char *) ARGVtab;
+ for (i = 0; i < ac; i++) {
+ sprintf(temp, "%d", i);
+ if (is_number(*av))
+ setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
+ else
+ setsymtab(temp, *av, 0.0, STR, ARGVtab);
+ av++;
+ }
+}
+
+void envinit(char **envp) /* set up ENVIRON variable */
+{
+ Cell *cp;
+ char *p;
+
+ cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
+ ENVtab = makesymtab(NSYMTAB);
+ cp->sval = (char *) ENVtab;
+ for ( ; *envp; envp++) {
+ if ((p = strchr(*envp, '=')) == NULL)
+ continue;
+ if( p == *envp ) /* no left hand side name in env string */
+ continue;
+ *p++ = 0; /* split into two strings at = */
+ if (is_number(p))
+ setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
+ else
+ setsymtab(*envp, p, 0.0, STR, ENVtab);
+ p[-1] = '='; /* restore in case env is passed down to a shell */
+ }
+}
+
+Array *makesymtab(int n) /* make a new symbol table */
+{
+ Array *ap;
+ Cell **tp;
+
+ ap = (Array *) malloc(sizeof(Array));
+ tp = (Cell **) calloc(n, sizeof(Cell *));
+ if (ap == NULL || tp == NULL)
+ FATAL("out of space in makesymtab");
+ ap->nelem = 0;
+ ap->size = n;
+ ap->tab = tp;
+ return(ap);
+}
+
+void freesymtab(Cell *ap) /* free a symbol table */
+{
+ Cell *cp, *temp;
+ Array *tp;
+ int i;
+
+ if (!isarr(ap))
+ return;
+ tp = (Array *) ap->sval;
+ if (tp == NULL)
+ return;
+ for (i = 0; i < tp->size; i++) {
+ for (cp = tp->tab[i]; cp != NULL; cp = temp) {
+ xfree(cp->nval);
+ if (freeable(cp))
+ xfree(cp->sval);
+ temp = cp->cnext; /* avoids freeing then using */
+ free(cp);
+ }
+ tp->tab[i] = 0;
+ }
+ free(tp->tab);
+ free(tp);
+}
+
+void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
+{
+ Array *tp;
+ Cell *p, *prev = NULL;
+ int h;
+
+ tp = (Array *) ap->sval;
+ h = hash(s, tp->size);
+ for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
+ if (strcmp(s, p->nval) == 0) {
+ if (prev == NULL) /* 1st one */
+ tp->tab[h] = p->cnext;
+ else /* middle somewhere */
+ prev->cnext = p->cnext;
+ if (freeable(p))
+ xfree(p->sval);
+ free(p->nval);
+ free(p);
+ tp->nelem--;
+ return;
+ }
+}
+
+Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
+{
+ int h;
+ Cell *p;
+
+ if (n != NULL && (p = lookup(n, tp)) != NULL) {
+ dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
+ p, p->nval, p->sval, p->fval, p->tval) );
+ return(p);
+ }
+ p = (Cell *) malloc(sizeof(Cell));
+ if (p == NULL)
+ FATAL("out of space for symbol table at %s", n);
+ p->nval = tostring(n);
+ p->sval = s ? tostring(s) : tostring("");
+ p->fval = f;
+ p->tval = t;
+ p->csub = CUNK;
+ p->ctype = OCELL;
+ tp->nelem++;
+ if (tp->nelem > FULLTAB * tp->size)
+ rehash(tp);
+ h = hash(n, tp->size);
+ p->cnext = tp->tab[h];
+ tp->tab[h] = p;
+ dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
+ p, p->nval, p->sval, p->fval, p->tval) );
+ return(p);
+}
+
+int hash(char *s, int n) /* form hash value for string s */
+{
+ unsigned hashval;
+
+ for (hashval = 0; *s != '\0'; s++)
+ hashval = (*s + 31 * hashval);
+ return hashval % n;
+}
+
+void rehash(Array *tp) /* rehash items in small table into big one */
+{
+ int i, nh, nsz;
+ Cell *cp, *op, **np;
+
+ nsz = GROWTAB * tp->size;
+ np = (Cell **) calloc(nsz, sizeof(Cell *));
+ if (np == NULL) /* can't do it, but can keep running. */
+ return; /* someone else will run out later. */
+ for (i = 0; i < tp->size; i++) {
+ for (cp = tp->tab[i]; cp; cp = op) {
+ op = cp->cnext;
+ nh = hash(cp->nval, nsz);
+ cp->cnext = np[nh];
+ np[nh] = cp;
+ }
+ }
+ free(tp->tab);
+ tp->tab = np;
+ tp->size = nsz;
+}
+
+Cell *lookup(char *s, Array *tp) /* look for s in tp */
+{
+ Cell *p;
+ int h;
+
+ h = hash(s, tp->size);
+ for (p = tp->tab[h]; p != NULL; p = p->cnext)
+ if (strcmp(s, p->nval) == 0)
+ return(p); /* found it */
+ return(NULL); /* not found */
+}
+
+Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
+{
+ int fldno;
+
+ if ((vp->tval & (NUM | STR)) == 0)
+ funnyvar(vp, "assign to");
+ if (isfld(vp)) {
+ donerec = 0; /* mark $0 invalid */
+ fldno = atoi(vp->nval);
+ if (fldno > *NF)
+ newfld(fldno);
+ dprintf( ("setting field %d to %g\n", fldno, f) );
+ } else if (isrec(vp)) {
+ donefld = 0; /* mark $1... invalid */
+ donerec = 1;
+ }
+ if (freeable(vp))
+ xfree(vp->sval); /* free any previous string */
+ vp->tval &= ~STR; /* mark string invalid */
+ vp->tval |= NUM; /* mark number ok */
+ dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
+ return vp->fval = f;
+}
+
+void funnyvar(Cell *vp, char *rw)
+{
+ if (isarr(vp))
+ FATAL("can't %s %s; it's an array name.", rw, vp->nval);
+ if (vp->tval & FCN)
+ FATAL("can't %s %s; it's a function.", rw, vp->nval);
+ WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
+ vp, vp->nval, vp->sval, vp->fval, vp->tval);
+}
+
+char *setsval(Cell *vp, char *s) /* set string val of a Cell */
+{
+ char *t;
+ int fldno;
+
+ dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
+ if ((vp->tval & (NUM | STR)) == 0)
+ funnyvar(vp, "assign to");
+ if (isfld(vp)) {
+ donerec = 0; /* mark $0 invalid */
+ fldno = atoi(vp->nval);
+ if (fldno > *NF)
+ newfld(fldno);
+ dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
+ } else if (isrec(vp)) {
+ donefld = 0; /* mark $1... invalid */
+ donerec = 1;
+ }
+ t = tostring(s); /* in case it's self-assign */
+ vp->tval &= ~NUM;
+ vp->tval |= STR;
+ if (freeable(vp))
+ xfree(vp->sval);
+ vp->tval &= ~DONTFREE;
+ dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
+ return(vp->sval = t);
+}
+
+Awkfloat getfval(Cell *vp) /* get float val of a Cell */
+{
+ if ((vp->tval & (NUM | STR)) == 0)
+ funnyvar(vp, "read value of");
+ if (isfld(vp) && donefld == 0)
+ fldbld();
+ else if (isrec(vp) && donerec == 0)
+ recbld();
+ if (!isnum(vp)) { /* not a number */
+ vp->fval = atof(vp->sval); /* best guess */
+ if (is_number(vp->sval) && !(vp->tval&CON))
+ vp->tval |= NUM; /* make NUM only sparingly */
+ }
+ dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
+ return(vp->fval);
+}
+
+char *getsval(Cell *vp) /* get string val of a Cell */
+{
+ char s[100]; /* BUG: unchecked */
+ double dtemp;
+
+ if ((vp->tval & (NUM | STR)) == 0)
+ funnyvar(vp, "read value of");
+ if (isfld(vp) && donefld == 0)
+ fldbld();
+ else if (isrec(vp) && donerec == 0)
+ recbld();
+ if (isstr(vp) == 0) {
+ if (freeable(vp))
+ xfree(vp->sval);
+ if (modf(vp->fval, &dtemp) == 0) /* it's integral */
+ sprintf(s, "%.30g", vp->fval);
+ else
+ sprintf(s, *CONVFMT, vp->fval);
+ vp->sval = tostring(s);
+ vp->tval &= ~DONTFREE;
+ vp->tval |= STR;
+ }
+ dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
+ return(vp->sval);
+}
+
+char *tostring(char *s) /* make a copy of string s */
+{
+ char *p;
+
+ p = (char *) malloc(strlen(s)+1);
+ if (p == NULL)
+ FATAL("out of space in tostring on %s", s);
+ strcpy(p, s);
+ return(p);
+}
+
+char *qstring(char *is, int delim) /* collect string up to next delim */
+{
+ char *os = is;
+ int c, n;
+ uschar *s = (uschar *) is;
+ uschar *buf, *bp;
+
+ if ((buf = (uschar *) malloc(strlen(s)+3)) == NULL)
+ FATAL( "out of space in qstring(%s)", s);
+ for (bp = buf; (c = *s) != delim; s++) {
+ if (c == '\n')
+ SYNTAX( "newline in string %.20s...", os );
+ else if (c != '\\')
+ *bp++ = c;
+ else { /* \something */
+ c = *++s;
+ if (c == 0) { /* \ at end */
+ *bp++ = '\\';
+ break; /* for loop */
+ }
+ switch (c) {
+ case '\\': *bp++ = '\\'; break;
+ case 'n': *bp++ = '\n'; break;
+ case 't': *bp++ = '\t'; break;
+ case 'b': *bp++ = '\b'; break;
+ case 'f': *bp++ = '\f'; break;
+ case 'r': *bp++ = '\r'; break;
+ default:
+ if (!isdigit(c)) {
+ *bp++ = c;
+ break;
+ }
+ n = c - '0';
+ if (isdigit(s[1])) {
+ n = 8 * n + *++s - '0';
+ if (isdigit(s[1]))
+ n = 8 * n + *++s - '0';
+ }
+ *bp++ = n;
+ break;
+ }
+ }
+ }
+ *bp++ = 0;
+ return (char *) buf;
+}
diff --git a/utils/awk/ytab.c b/utils/awk/ytab.c
new file mode 100644
index 00000000..2a6a938b
--- /dev/null
+++ b/utils/awk/ytab.c
@@ -0,0 +1,1623 @@
+
+#line 26 "/n/bopp/v7/bwk/awk/awkgram.y"
+#include <stdio.h>
+#include <string.h>
+#include "awk.h"
+
+void checkdup(Node *list, Cell *item);
+int yywrap(void) { return(1); }
+
+Node *beginloc = 0;
+Node *endloc = 0;
+int infunc = 0; /* = 1 if in arglist or body of func */
+int inloop = 0; /* = 1 if in while, for, do */
+char *curfname = 0; /* current function name */
+Node *arglist = 0; /* list of args for current function */
+
+#line 41 "/n/bopp/v7/bwk/awk/awkgram.y"
+typedef union {
+ Node *p;
+ Cell *cp;
+ int i;
+ char *s;
+} YYSTYPE;
+extern int yyerrflag;
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 150
+#endif
+YYSTYPE yylval;
+YYSTYPE yyval;
+#define FIRSTTOKEN 57346
+#define PROGRAM 57347
+#define PASTAT 57348
+#define PASTAT2 57349
+#define XBEGIN 57350
+#define XEND 57351
+#define NL 57352
+#define ARRAY 57353
+#define MATCH 57354
+#define NOTMATCH 57355
+#define MATCHOP 57356
+#define FINAL 57357
+#define DOT 57358
+#define ALL 57359
+#define CCL 57360
+#define NCCL 57361
+#define CHAR 57362
+#define OR 57363
+#define STAR 57364
+#define QUEST 57365
+#define PLUS 57366
+#define AND 57367
+#define BOR 57368
+#define APPEND 57369
+#define EQ 57370
+#define GE 57371
+#define GT 57372
+#define LE 57373
+#define LT 57374
+#define NE 57375
+#define IN 57376
+#define ARG 57377
+#define BLTIN 57378
+#define BREAK 57379
+#define CLOSE 57380
+#define CONTINUE 57381
+#define DELETE 57382
+#define DO 57383
+#define EXIT 57384
+#define FOR 57385
+#define FUNC 57386
+#define SUB 57387
+#define GSUB 57388
+#define IF 57389
+#define INDEX 57390
+#define LSUBSTR 57391
+#define MATCHFCN 57392
+#define NEXT 57393
+#define NEXTFILE 57394
+#define ADD 57395
+#define MINUS 57396
+#define MULT 57397
+#define DIVIDE 57398
+#define MOD 57399
+#define ASSIGN 57400
+#define ASGNOP 57401
+#define ADDEQ 57402
+#define SUBEQ 57403
+#define MULTEQ 57404
+#define DIVEQ 57405
+#define MODEQ 57406
+#define POWEQ 57407
+#define PRINT 57408
+#define PRINTF 57409
+#define SPRINTF 57410
+#define ELSE 57411
+#define INTEST 57412
+#define CONDEXPR 57413
+#define POSTINCR 57414
+#define PREINCR 57415
+#define POSTDECR 57416
+#define PREDECR 57417
+#define VAR 57418
+#define IVAR 57419
+#define VARNF 57420
+#define CALL 57421
+#define NUMBER 57422
+#define STRING 57423
+#define REGEXPR 57424
+#define GETLINE 57425
+#define RETURN 57426
+#define SPLIT 57427
+#define SUBSTR 57428
+#define WHILE 57429
+#define CAT 57430
+#define NOT 57431
+#define UMINUS 57432
+#define POWER 57433
+#define DECR 57434
+#define INCR 57435
+#define INDIRECT 57436
+#define LASTTOKEN 57437
+#define YYEOFCODE 1
+#define YYERRCODE 2
+
+#line 445 "/n/bopp/v7/bwk/awk/awkgram.y"
+
+
+void setfname(Cell *p)
+{
+ if (isarr(p))
+ SYNTAX("%s is an array, not a function", p->nval);
+ else if (isfcn(p))
+ SYNTAX("you can't define function %s more than once", p->nval);
+ curfname = p->nval;
+}
+
+int constnode(Node *p)
+{
+ return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON;
+}
+
+char *strnode(Node *p)
+{
+ return ((Cell *)(p->narg[0]))->sval;
+}
+
+Node *notnull(Node *n)
+{
+ switch (n->nobj) {
+ case LE: case LT: case EQ: case NE: case GT: case GE:
+ case BOR: case AND: case NOT:
+ return n;
+ default:
+ return op2(NE, n, nullnode);
+ }
+}
+
+void checkdup(Node *vl, Cell *cp) /* check if name already in list */
+{
+ char *s = cp->nval;
+ for ( ; vl; vl = vl->nnext) {
+ if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) {
+ SYNTAX("duplicate argument %s", s);
+ break;
+ }
+ }
+}
+short yyexca[] =
+{-1, 0,
+ 1, 28,
+ 8, 28,
+ 9, 28,
+ 12, 28,
+ 13, 28,
+ 16, 28,
+ 45, 28,
+ 46, 28,
+ 48, 28,
+ 54, 28,
+ 55, 28,
+ 56, 28,
+ 58, 28,
+ 60, 28,
+ 78, 28,
+ 86, 28,
+ 87, 28,
+ 88, 28,
+ 89, 28,
+ 90, 28,
+ 91, 28,
+ 95, 28,
+ 97, 28,
+ 98, 28,
+ 101, 28,
+ 102, 28,
+ 105, 28,
+ 108, 28,
+ 109, 28,
+ 110, 28,
+ -2, 0,
+-1, 1,
+ 1, -1,
+ -2, 0,
+-1, 157,
+ 15, 30,
+ -2, 0,
+-1, 176,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 63,
+-1, 177,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 64,
+-1, 178,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 65,
+-1, 179,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 66,
+-1, 180,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 67,
+-1, 181,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 68,
+-1, 183,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 70,
+-1, 289,
+ 24, 0,
+ 44, 0,
+ -2, 53,
+-1, 333,
+ 17, 30,
+ -2, 0,
+-1, 355,
+ 17, 30,
+ -2, 0,
+};
+#define YYNPROD 185
+#define YYPRIVATE 57344
+#define YYLAST 4177
+short yyact[] =
+{
+ 17, 277, 138, 66, 243, 228, 253, 54, 24, 43,
+ 125, 112, 200, 43, 103, 104, 100, 139, 102, 155,
+ 308, 185, 215, 249, 100, 253, 100, 100, 100, 107,
+ 105, 100, 122, 123, 124, 223, 107, 206, 43, 82,
+ 162, 43, 83, 103, 104, 10, 113, 314, 9, 252,
+ 42, 22, 44, 244, 42, 22, 44, 103, 104, 134,
+ 142, 113, 146, 190, 278, 352, 149, 150, 152, 153,
+ 148, 276, 316, 163, 23, 100, 351, 350, 23, 42,
+ 62, 44, 42, 22, 44, 11, 156, 168, 169, 85,
+ 253, 51, 321, 79, 80, 232, 190, 86, 135, 133,
+ 100, 318, 182, 320, 269, 258, 23, 100, 100, 100,
+ 100, 100, 100, 100, 108, 109, 110, 111, 233, 275,
+ 112, 234, 190, 110, 111, 43, 100, 112, 335, 190,
+ 190, 11, 203, 205, 190, 324, 278, 190, 190, 212,
+ 284, 190, 211, 265, 260, 190, 100, 259, 221, 3,
+ 141, 188, 100, 16, 226, 140, 331, 6, 156, 141,
+ 219, 230, 7, 100, 310, 6, 42, 170, 44, 167,
+ 7, 158, 100, 157, 100, 131, 100, 100, 100, 100,
+ 100, 100, 100, 130, 100, 48, 251, 100, 100, 129,
+ 49, 128, 236, 127, 100, 126, 120, 119, 52, 16,
+ 190, 19, 100, 312, 141, 274, 218, 100, 143, 100,
+ 100, 100, 4, 154, 100, 100, 217, 271, 144, 132,
+ 317, 50, 347, 361, 364, 270, 1, 115, 72, 40,
+ 224, 5, 100, 100, 100, 100, 163, 58, 163, 163,
+ 163, 163, 20, 67, 163, 222, 100, 293, 61, 288,
+ 294, 60, 238, 248, 81, 100, 100, 292, 96, 8,
+ 239, 159, 160, 2, 0, 0, 114, 0, 116, 117,
+ 118, 300, 301, 121, 164, 0, 282, 0, 285, 286,
+ 287, 289, 0, 100, 291, 0, 100, 100, 100, 0,
+ 100, 0, 100, 156, 0, 309, 0, 100, 0, 100,
+ 100, 0, 0, 100, 0, 100, 100, 100, 0, 0,
+ 0, 0, 0, 334, 313, 165, 163, 96, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 341, 156, 342,
+ 333, 0, 340, 100, 0, 0, 0, 230, 100, 346,
+ 100, 0, 116, 0, 100, 100, 348, 0, 356, 96,
+ 194, 195, 196, 197, 198, 199, 337, 359, 0, 230,
+ 0, 360, 362, 156, 0, 355, 0, 0, 207, 0,
+ 0, 0, 238, 0, 0, 238, 238, 238, 0, 238,
+ 239, 238, 0, 239, 239, 239, 0, 239, 96, 239,
+ 0, 0, 21, 0, 96, 0, 0, 0, 338, 0,
+ 0, 0, 0, 0, 257, 242, 0, 0, 55, 0,
+ 0, 0, 0, 0, 96, 0, 96, 0, 96, 96,
+ 96, 96, 96, 96, 96, 0, 96, 238, 0, 96,
+ 96, 0, 0, 0, 0, 239, 256, 164, 0, 164,
+ 164, 164, 164, 0, 96, 164, 0, 0, 0, 261,
+ 0, 96, 96, 96, 0, 0, 96, 96, 0, 0,
+ 0, 0, 0, 137, 0, 0, 166, 0, 0, 0,
+ 147, 0, 0, 0, 96, 279, 280, 281, 165, 0,
+ 165, 165, 165, 165, 0, 0, 165, 184, 96, 0,
+ 0, 0, 0, 0, 0, 0, 0, 96, 96, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 74, 0,
+ 189, 191, 0, 15, 0, 0, 0, 164, 0, 0,
+ 0, 0, 0, 0, 0, 242, 0, 106, 242, 242,
+ 242, 0, 242, 0, 242, 0, 0, 0, 0, 96,
+ 0, 96, 96, 137, 0, 96, 0, 96, 96, 96,
+ 229, 0, 0, 220, 0, 0, 0, 137, 165, 15,
+ 0, 15, 0, 227, 0, 235, 0, 0, 145, 0,
+ 0, 0, 0, 0, 151, 96, 0, 137, 137, 0,
+ 242, 0, 96, 0, 0, 0, 96, 96, 0, 0,
+ 0, 0, 0, 171, 173, 175, 176, 177, 178, 179,
+ 180, 181, 183, 0, 0, 0, 0, 0, 0, 0,
+ 186, 187, 0, 262, 263, 264, 0, 266, 267, 268,
+ 0, 0, 201, 0, 0, 0, 0, 0, 201, 201,
+ 0, 273, 0, 0, 290, 208, 209, 210, 201, 213,
+ 214, 189, 0, 0, 0, 297, 0, 0, 0, 101,
+ 0, 0, 0, 295, 0, 0, 0, 303, 0, 0,
+ 240, 0, 0, 0, 0, 0, 0, 231, 0, 311,
+ 106, 98, 97, 0, 0, 0, 245, 0, 0, 137,
+ 241, 43, 28, 0, 30, 0, 0, 0, 0, 0,
+ 0, 46, 47, 0, 34, 0, 35, 0, 254, 0,
+ 255, 0, 0, 0, 0, 0, 0, 336, 323, 326,
+ 328, 329, 0, 0, 38, 0, 0, 0, 189, 0,
+ 0, 0, 42, 22, 44, 29, 36, 39, 0, 237,
+ 315, 33, 0, 37, 41, 0, 0, 27, 26, 0,
+ 0, 99, 0, 0, 31, 32, 23, 0, 0, 0,
+ 0, 0, 0, 201, 0, 0, 357, 137, 0, 296,
+ 0, 0, 0, 0, 0, 0, 298, 0, 0, 0,
+ 363, 299, 302, 365, 0, 304, 305, 306, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 106, 0, 0, 0, 0, 0, 75, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 16, 18,
+ 0, 68, 45, 0, 358, 0, 0, 0, 332, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 339, 0, 0, 0, 0, 0, 343, 0,
+ 344, 43, 28, 56, 30, 57, 73, 69, 59, 70,
+ 0, 46, 47, 71, 34, 0, 35, 63, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 75, 0, 0,
+ 0, 0, 77, 78, 38, 53, 0, 16, 18, 0,
+ 68, 45, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 33, 65, 37, 41, 76, 0, 27, 26, 0,
+ 0, 25, 0, 0, 31, 32, 23, 0, 0, 0,
+ 43, 28, 56, 30, 57, 73, 69, 59, 70, 0,
+ 46, 47, 71, 34, 0, 35, 63, 64, 0, 0,
+ 0, 0, 0, 0, 75, 0, 0, 0, 0, 0,
+ 0, 77, 78, 38, 16, 18, 0, 68, 45, 0,
+ 307, 42, 22, 44, 29, 36, 39, 0, 0, 0,
+ 33, 65, 37, 41, 76, 0, 27, 26, 0, 0,
+ 25, 0, 0, 31, 32, 23, 0, 43, 28, 56,
+ 30, 57, 73, 69, 59, 70, 0, 46, 47, 71,
+ 34, 0, 35, 63, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 75, 0, 0, 0, 0, 77, 78,
+ 38, 272, 0, 16, 18, 0, 68, 45, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 65, 37,
+ 41, 76, 0, 27, 26, 0, 0, 25, 0, 0,
+ 31, 32, 23, 0, 0, 0, 43, 28, 56, 30,
+ 57, 73, 69, 59, 70, 0, 46, 47, 71, 34,
+ 0, 35, 63, 64, 0, 0, 0, 0, 0, 0,
+ 75, 0, 0, 0, 0, 0, 0, 77, 78, 38,
+ 16, 18, 0, 68, 45, 0, 247, 42, 22, 44,
+ 29, 36, 39, 0, 0, 0, 33, 65, 37, 41,
+ 76, 0, 27, 26, 0, 0, 25, 0, 0, 31,
+ 32, 23, 0, 43, 28, 56, 30, 57, 73, 69,
+ 59, 70, 0, 46, 47, 71, 34, 0, 35, 63,
+ 64, 0, 0, 0, 0, 0, 0, 75, 0, 0,
+ 0, 0, 0, 0, 77, 78, 38, 16, 18, 0,
+ 68, 45, 0, 246, 42, 22, 44, 29, 36, 39,
+ 0, 0, 0, 33, 65, 37, 41, 76, 0, 27,
+ 26, 0, 0, 25, 0, 0, 31, 32, 23, 0,
+ 43, 28, 56, 30, 57, 73, 69, 59, 70, 0,
+ 46, 47, 71, 34, 0, 35, 63, 64, 0, 0,
+ 0, 0, 0, 0, 75, 0, 0, 0, 0, 0,
+ 0, 77, 78, 38, 16, 18, 0, 68, 45, 0,
+ 225, 42, 22, 44, 29, 36, 39, 0, 0, 0,
+ 33, 65, 37, 41, 76, 0, 27, 26, 0, 0,
+ 25, 0, 0, 31, 32, 23, 0, 43, 28, 56,
+ 30, 57, 73, 69, 59, 70, 0, 46, 47, 71,
+ 34, 0, 35, 63, 64, 0, 0, 0, 0, 0,
+ 0, 75, 0, 0, 0, 0, 0, 0, 77, 78,
+ 38, 16, 18, 0, 68, 45, 0, 216, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 65, 37,
+ 41, 76, 0, 27, 26, 0, 0, 25, 0, 0,
+ 31, 32, 23, 0, 43, 28, 56, 30, 57, 73,
+ 69, 59, 70, 0, 46, 47, 71, 34, 0, 35,
+ 63, 64, 0, 0, 0, 0, 0, 0, 75, 0,
+ 0, 0, 0, 0, 0, 77, 78, 38, 16, 18,
+ 0, 68, 45, 0, 136, 42, 22, 44, 29, 36,
+ 39, 0, 0, 0, 33, 65, 37, 41, 76, 0,
+ 27, 26, 0, 0, 25, 0, 0, 31, 32, 23,
+ 0, 43, 28, 56, 30, 57, 73, 69, 59, 70,
+ 0, 46, 47, 71, 34, 0, 35, 63, 64, 0,
+ 0, 0, 0, 0, 0, 75, 0, 0, 0, 0,
+ 0, 0, 77, 78, 38, 16, 18, 0, 68, 45,
+ 0, 0, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 33, 65, 37, 41, 76, 0, 27, 26, 0,
+ 0, 25, 0, 0, 31, 32, 23, 0, 43, 28,
+ 56, 30, 57, 73, 69, 59, 70, 0, 46, 47,
+ 71, 34, 0, 35, 63, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 77,
+ 78, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 0, 0, 33, 65,
+ 37, 41, 76, 0, 27, 26, 0, 0, 25, 0,
+ 0, 31, 32, 23, 190, 0, 101, 95, 0, 0,
+ 330, 0, 0, 0, 0, 0, 0, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 97,
+ 0, 87, 88, 89, 90, 91, 92, 94, 43, 28,
+ 0, 30, 0, 0, 0, 0, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 84, 0, 33, 0,
+ 37, 41, 0, 0, 27, 26, 0, 0, 99, 0,
+ 0, 31, 32, 23, 190, 0, 101, 95, 0, 0,
+ 327, 0, 0, 0, 0, 0, 0, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 97,
+ 0, 87, 88, 89, 90, 91, 92, 94, 43, 28,
+ 0, 30, 0, 0, 0, 0, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 84, 0, 33, 0,
+ 37, 41, 0, 0, 27, 26, 0, 0, 99, 0,
+ 0, 31, 32, 23, 190, 0, 101, 95, 0, 0,
+ 325, 0, 0, 0, 0, 0, 0, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 97,
+ 0, 87, 88, 89, 90, 91, 92, 94, 43, 28,
+ 0, 30, 0, 0, 0, 0, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 84, 0, 33, 0,
+ 37, 41, 0, 0, 27, 26, 0, 0, 99, 0,
+ 0, 31, 32, 23, 141, 0, 0, 101, 95, 140,
+ 0, 0, 0, 0, 0, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 0, 0, 99,
+ 0, 0, 31, 32, 23, 190, 0, 101, 95, 0,
+ 0, 192, 0, 0, 0, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 101, 95, 99,
+ 0, 354, 31, 32, 23, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 101, 95, 99,
+ 0, 353, 31, 32, 23, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 101, 95, 99,
+ 0, 349, 31, 32, 23, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 0, 0, 99,
+ 0, 0, 31, 32, 23, 101, 95, 345, 0, 0,
+ 0, 0, 0, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 101, 95, 99, 0, 322,
+ 31, 32, 23, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 101, 95, 99, 0, 319,
+ 31, 32, 23, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 101, 95, 99, 0, 278,
+ 31, 32, 23, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 0, 190, 99, 101, 95,
+ 31, 32, 23, 0, 0, 0, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 192, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 250,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 0, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 101, 95, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 93, 0,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 0,
+ 0, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 75, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 18, 0, 0, 45, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 0, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 0, 0, 99,
+ 0, 0, 31, 32, 23, 43, 28, 0, 30, 0,
+ 73, 0, 0, 0, 0, 46, 47, 0, 34, 0,
+ 35, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 77, 78, 38, 0,
+ 0, 101, 0, 0, 0, 0, 42, 22, 44, 29,
+ 36, 39, 240, 0, 0, 33, 0, 37, 41, 0,
+ 0, 27, 26, 98, 97, 25, 0, 0, 31, 32,
+ 23, 0, 241, 43, 28, 0, 30, 0, 0, 0,
+ 0, 0, 0, 46, 47, 0, 34, 0, 35, 0,
+ 0, 0, 0, 0, 12, 13, 0, 0, 16, 18,
+ 0, 0, 45, 0, 0, 0, 38, 0, 0, 0,
+ 0, 0, 0, 0, 42, 22, 44, 29, 36, 39,
+ 0, 237, 0, 33, 0, 37, 41, 0, 0, 27,
+ 26, 43, 28, 99, 30, 0, 31, 32, 23, 0,
+ 14, 46, 47, 0, 34, 0, 35, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 38, 0, 0, 101, 0, 0,
+ 0, 0, 42, 22, 44, 29, 36, 39, 240, 0,
+ 0, 33, 0, 37, 41, 0, 0, 27, 26, 98,
+ 0, 25, 0, 0, 31, 32, 23, 0, 241, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 141, 0, 0, 18, 0, 140, 45, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 253, 0, 33,
+ 18, 37, 41, 45, 0, 27, 26, 43, 28, 99,
+ 30, 0, 31, 32, 23, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 43, 28, 0, 30, 0, 0, 0, 0,
+ 38, 0, 46, 47, 0, 34, 0, 35, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 38, 0, 25, 101, 0,
+ 31, 32, 23, 42, 22, 44, 29, 36, 39, 240,
+ 0, 0, 33, 0, 37, 41, 0, 0, 27, 26,
+ 0, 0, 25, 0, 0, 31, 32, 23, 0, 241,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 174, 0, 0, 283, 0, 0, 45,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 172, 0,
+ 33, 283, 37, 41, 45, 0, 27, 26, 43, 28,
+ 99, 30, 0, 31, 32, 23, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 43, 28, 0, 30, 0, 0, 0,
+ 0, 38, 0, 46, 47, 0, 34, 0, 35, 42,
+ 22, 44, 29, 36, 39, 0, 253, 0, 33, 283,
+ 37, 41, 45, 0, 27, 26, 38, 0, 25, 0,
+ 0, 31, 32, 23, 42, 22, 44, 29, 36, 39,
+ 0, 0, 0, 33, 18, 37, 41, 45, 204, 27,
+ 26, 43, 28, 25, 30, 0, 31, 32, 23, 0,
+ 0, 46, 47, 0, 34, 0, 35, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 43, 28, 0, 30,
+ 0, 0, 0, 0, 38, 0, 46, 47, 0, 34,
+ 0, 35, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 33, 18, 37, 41, 45, 202, 27, 26, 38,
+ 0, 25, 0, 0, 31, 32, 23, 42, 22, 44,
+ 29, 36, 39, 0, 174, 0, 33, 18, 37, 41,
+ 45, 0, 27, 26, 43, 28, 25, 30, 0, 31,
+ 32, 23, 0, 0, 46, 47, 0, 34, 0, 35,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 28, 0, 30, 0, 0, 0, 0, 38, 0, 46,
+ 47, 0, 34, 0, 35, 42, 22, 44, 29, 36,
+ 39, 0, 172, 0, 33, 18, 37, 41, 45, 0,
+ 27, 26, 38, 0, 25, 0, 0, 31, 32, 23,
+ 42, 22, 44, 29, 36, 39, 0, 0, 0, 33,
+ 18, 37, 41, 45, 0, 27, 26, 43, 28, 25,
+ 30, 0, 31, 32, 23, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 43, 28, 0, 30, 0, 0, 0, 0,
+ 38, 0, 46, 47, 0, 34, 0, 35, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 283, 37,
+ 41, 45, 0, 27, 26, 38, 0, 25, 0, 0,
+ 31, 32, 23, 42, 22, 44, 29, 36, 39, 0,
+ 0, 0, 33, 101, 37, 41, 0, 0, 27, 26,
+ 43, 28, 25, 30, 0, 31, 32, 23, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 43, 28, 0, 30, 0,
+ 0, 0, 0, 38, 0, 46, 47, 0, 34, 0,
+ 35, 42, 22, 44, 29, 36, 39, 0, 0, 193,
+ 33, 161, 37, 41, 45, 0, 27, 26, 38, 0,
+ 25, 0, 0, 31, 32, 23, 42, 22, 44, 29,
+ 36, 39, 0, 0, 0, 33, 101, 37, 41, 45,
+ 0, 27, 26, 43, 28, 99, 30, 0, 31, 32,
+ 23, 0, 0, 46, 47, 0, 34, 0, 35, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 43, 28,
+ 0, 30, 0, 0, 0, 0, 38, 0, 46, 47,
+ 0, 34, 0, 35, 42, 22, 44, 29, 36, 39,
+ 0, 0, 0, 33, 101, 37, 41, 0, 0, 27,
+ 26, 38, 0, 25, 0, 0, 31, 32, 23, 42,
+ 22, 44, 29, 36, 39, 0, 0, 0, 33, 101,
+ 37, 41, 0, 0, 27, 26, 43, 28, 25, 30,
+ 0, 31, 32, 23, 0, 0, 46, 47, 0, 34,
+ 0, 35, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 43, 28, 0, 30, 0, 0, 0, 0, 38,
+ 0, 46, 47, 0, 34, 0, 35, 42, 22, 44,
+ 29, 36, 39, 0, 0, 0, 33, 0, 37, 41,
+ 0, 0, 27, 26, 38, 0, 99, 0, 0, 31,
+ 32, 23, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 0, 0, 37, 41, 0, 0, 27, 26, 0,
+ 0, 99, 0, 0, 31, 32, 23
+};
+short yypact[] =
+{
+ 147,-1000,-1000,-1000,3266, 175,-1000,-1000, 155,-1000,
+ 187, 865, 141, 141, -47,2905,-1000, -51,3817,-1000,
+ 13, 42,-1000,4041,-1000,3983,4041,4041, 184, 183,
+4041, -36, -36, -32, 182, 180,-1000, 178, 176,-1000,
+ 170, 162,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
+3266, 865,3817,-1000,1336,-1000, 140, 140, 198,3392,
+-1000,1403, 865, 140, 140,3392, 140,-1000, 194,-1000,
+ 160, 158,3958, -7,2905,-1000, 156,-1000,-1000, 865,
+ 865, 154,-1000,-1000,3817,3792,3734,3817,3817,3817,
+3817,3817,3817,3817, -7, -74, 13,-1000,-1000,4041,
+ -94,3817,3817,-1000,-1000, 134,1904,3900,4041,4041,
+4041,4041,4041,3817,-1000,-1000, -96, -96, -96,3709,
+3651, 13,-1000,-1000, -5,4041,3817,3817,3817,3817,
+3817,3817, -70,-1000,1269, 141,-1000,-1000,-1000, 196,
+ 194,-1000,-1000,-1000,1403,1804,-1000, -44,1202,-1000,
+-1000,1804,-1000,-1000,1403,-1000, 196,3140,3817, 81,
+ 189,3817,3208, -65,-1000, 13, 34,3817,1135,1068,
+ -63,2815,-1000,2995,-1000,3074,4066,4066,4066,4066,
+4066,4066,-1000,4066,-1000, -36,2725,2905, 5,3417,
+-1000,3417,-1000,4041, -96, 20, 20, -96, -96, -96,
+ 85,2905,-1000, 130,-1000, 127,4041, 13,2635,2635,
+2635, 126, 189,2635,2635, 88,-1000, 865,-1000,-1000,
+-1000,-1000,1001,-1000, 195,-1000,-1000,-1000, 104, 27,
+-1000,2542,4041,4041,4041,3626, 123,3875,3568,3543,
+3875, -7, 13,3875,3817,2542,-1000,-1000, 119,-1000,
+3817,-1000, -7,-1000,2905,2905, 13,3417,-1000,-1000,
+-1000, 13,3417,3417, 80,-1000,3417,3417,3417,-1000,
+ 932, -79,-1000,-1000,-1000, 149, -7, 193,-1000, 13,
+ 13, 13,3208,3817, 3, 636,3334,3485,-1000,4066,
+-1000,3208, 52, 193, 193, 15,2905,-1000,2905,2452,
+ 86, 75,2362, 118,1703,1603,1503,-1000, 143,3817,
+ 194, 47,-1000, 111, -7,3875,-1000, 141,-1000,-1000,
+-1000,-1000,-1000,3417,-1000,-1000, -4,-1000, -4,3417,
+-1000,3817,2272,3140, 193, 3,-1000,3208, 865,2174,
+ 60, 59, 48,2084,1994, 194, 47,1403, 796,-1000,
+-1000,-1000,-1000,-1000, 140,3140, 193,-1000,-1000,-1000,
+ 47,1403, 193,-1000,1403,-1000
+};
+short yypgo[] =
+{
+ 0, 263, 508, 40, 30, 262, 12, 261, 242, 201,
+ 45, 48, 259, 8, 3, 5, 408, 7, 0, 392,
+ 254, 253, 251, 248, 245, 243, 237, 2, 231, 212,
+ 80, 230, 1, 404, 17, 19, 97, 89, 229, 228,
+ 226, 224, 223, 222, 220, 219, 218, 217, 213
+};
+short yyr1[] =
+{
+ 0, 40, 40, 36, 36, 37, 37, 33, 33, 26,
+ 26, 24, 24, 41, 22, 42, 22, 43, 22, 20,
+ 20, 23, 30, 30, 34, 34, 35, 35, 29, 29,
+ 15, 15, 1, 1, 10, 11, 11, 11, 11, 11,
+ 11, 11, 44, 11, 12, 12, 6, 6, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 4, 4,
+ 5, 5, 7, 7, 7, 39, 39, 28, 28, 28,
+ 28, 31, 31, 9, 9, 45, 13, 32, 32, 14,
+ 14, 14, 14, 14, 14, 14, 14, 27, 27, 16,
+ 16, 46, 47, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 48, 16, 16, 17, 17,
+ 38, 38, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 18, 18, 18, 18, 21, 21,
+ 21, 19, 19, 19, 25
+};
+short yyr2[] =
+{
+ 0, 1, 1, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 0, 12, 0, 10, 0, 8, 1,
+ 1, 4, 1, 2, 1, 2, 0, 1, 0, 1,
+ 0, 1, 1, 3, 1, 1, 4, 3, 6, 3,
+ 4, 4, 0, 9, 1, 3, 1, 3, 3, 5,
+ 3, 3, 3, 3, 3, 5, 2, 1, 1, 3,
+ 5, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 5, 4, 3, 2, 1, 1, 3, 3,
+ 1, 3, 0, 1, 3, 1, 1, 1, 1, 2,
+ 2, 1, 2, 1, 2, 0, 4, 1, 2, 4,
+ 4, 4, 2, 5, 2, 1, 1, 1, 2, 2,
+ 2, 0, 0, 9, 3, 2, 1, 4, 2, 3,
+ 2, 2, 3, 2, 2, 0, 3, 2, 1, 2,
+ 1, 1, 4, 3, 3, 3, 3, 3, 3, 2,
+ 2, 2, 3, 4, 1, 3, 4, 2, 2, 2,
+ 2, 2, 4, 3, 2, 1, 6, 6, 3, 6,
+ 6, 1, 8, 8, 6, 4, 1, 6, 6, 8,
+ 8, 8, 6, 1, 1, 4, 1, 2, 0, 1,
+ 3, 1, 1, 1, 4
+};
+short yychk[] =
+{
+-1000, -40, -1, 2, -29, -28, 10, 15, -12, -11,
+ -10, -30, 8, 9, 54, -2, 12, -18, 13, -9,
+ -8, -19, 87, 110, -13, 105, 102, 101, 46, 89,
+ 48, 108, 109, 95, 58, 60, 90, 97, 78, 91,
+ -38, 98, 86, 45, 88, 16, 55, 56, 10, 15,
+ -29, -30, 11, 10, -17, -16, 47, 49, -26, 52,
+ -22, -23, -30, 61, 62, 96, -14, -25, 15, 51,
+ 53, 57, -39, 50, -2, 2, 99, 76, 77, -30,
+ -30, -20, 86, 89, 93, -37, -36, 38, 39, 40,
+ 41, 42, 43, 24, 44, 14, -8, 36, 35, 105,
+ -18, 13, 69, 108, 109, -4, -2, 16, 101, 102,
+ 103, 104, 107, 19, -8, -9, -8, -8, -8, 13,
+ 13, -8, -18, -18, -18, 42, 13, 13, 13, 13,
+ 13, 13, -45, -11, -17, -10, 18, -16, -27, -34,
+ 15, 10, -27, 10, -46, -2, -27, -16, -17, -27,
+ -27, -2, -27, -27, -48, -35, -34, 13, 13, -7,
+ -5, 13, -3, -18, -9, -8, -19, 13, -17, -17,
+ 13, -2, 10, -2, 10, -2, -2, -2, -2, -2,
+ -2, -2, -13, -2, -19, 95, -2, -2, 17, -33,
+ 11, -33, 17, 69, -8, -8, -8, -8, -8, -8,
+ -6, -2, 17, -6, 17, -6, 42, -8, -2, -2,
+ -2, -6, -13, -2, -2, 92, 18, -30, 10, -35,
+ -16, -27, -24, 79, -31, 18, -27, -16, -15, -19,
+ -14, -2, 14, 37, 40, -33, -4, 93, -37, -36,
+ 24, 44, -8, 69, 19, -2, 18, 18, -21, 86,
+ 94, -18, 44, 10, -2, -2, -8, -33, 20, 17,
+ 17, -8, -33, -33, -33, 17, -33, -33, -33, 16,
+ -17, -47, 10, -16, 10, 15, 44, -32, 17, -8,
+ -8, -8, -3, 13, 17, -3, -3, -3, -13, -3,
+ -19, -3, -6, -32, -32, -33, -2, -19, -2, -2,
+ -13, -13, -2, -19, -2, -2, -2, 18, 99, -35,
+ 15, -19, 10, -4, 44, 94, 20, -44, 86, 17,
+ 17, 17, 17, -33, 17, 17, -33, 17, -33, -33,
+ 17, 13, -2, -35, -32, 17, -19, -3, -30, -2,
+ -13, -18, -18, -2, -2, 15, -15, -43, -17, 17,
+ 17, 17, 17, 17, 17, -35, -32, -16, 18, -27,
+ -15, -42, -32, -16, -41, -16
+};
+short yydef[] =
+{
+ -2, -2, 1, 2, 32, 29, 87, 88, 28, 44,
+ 35, 0, 0, 0, 0, 34, 22, 173, 0, 76,
+ 77, 174, 176, 0, 93, 0, 0, 0, 144, 0,
+ 0, 0, 0, 155, 0, 0, 161, 0, 0, 166,
+ 0, 0, 181, 182, 183, 95, 130, 131, 89, 90,
+ 33, 0, 0, 23, 0, 128, 0, 0, 111, 0,
+ 116, 0, 0, 0, 0, 0, 0, 125, 26, 9,
+ 0, 0, 82, 0, 105, 106, 0, 85, 86, 0,
+ 0, 0, 19, 20, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 75, 5, 3, 0,
+ 173, 0, 0, 150, 151, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 177, 94, 141, 139, 140, 0,
+ 0, 147, 148, 149, 154, 0, 0, 0, 0, 0,
+ 0, 0, 0, 45, 0, 37, 39, 129, 109, 107,
+ 26, 24, 110, 10, 0, 0, 115, 118, 0, 120,
+ 121, 0, 123, 124, 0, 127, 27, -2, 0, 102,
+ 83, 0, 80, 173, 57, 58, 104, 0, 0, 0,
+ 178, 0, 6, 61, 4, 62, -2, -2, -2, -2,
+ -2, -2, 69, -2, 71, 74, 0, 59, 0, 0,
+ 7, 0, 158, 0, 136, 133, 134, 135, 137, 138,
+ 0, 46, 142, 0, 145, 0, 0, 153, 0, 0,
+ 0, 0, 93, 0, 0, 0, 36, 0, 25, 108,
+ 112, 114, 0, 11, 119, 91, 122, 126, 0, 174,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 56, 0, 0, 0, 40, 41, 0, 179,
+ 0, 73, 0, 8, 79, 78, 132, 0, 175, 143,
+ 146, 152, 0, 0, 0, 165, 0, 0, 0, 96,
+ 0, 0, 12, 117, 92, 26, 0, 21, 97, 99,
+ 100, 101, 81, 0, 84, 0, 50, 51, 52, -2,
+ 54, 48, 0, 184, 42, 0, 60, 72, 47, 0,
+ 93, 93, 0, 0, 0, 0, 0, 38, 0, 0,
+ 26, 0, 98, 0, 0, 0, 103, 0, 180, 156,
+ 157, 159, 160, 0, 164, 167, 0, 168, 0, 0,
+ 172, 0, 0, -2, 17, 0, 55, 49, 0, 0,
+ 93, 0, 0, 0, 0, 26, 0, 0, 0, 162,
+ 163, 169, 170, 171, 0, -2, 15, 18, 43, 113,
+ 0, 0, 13, 16, 0, 14
+};
+short yytok1[] =
+{
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 104, 0, 0,
+ 13, 17, 103, 101, 11, 102, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 94, 15,
+ 0, 0, 0, 93, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 19, 0, 20, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 12, 14, 18
+};
+short yytok2[] =
+{
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 95, 96, 97, 98, 99, 100, 105, 106, 107,
+ 108, 109, 110, 111
+};
+long yytok3[] =
+{
+ 0
+};
+#define YYFLAG -1000
+#define YYERROR goto yyerrlab
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+
+#ifdef yydebug
+#include "y.debug"
+#else
+#define yydebug 0
+char* yytoknames[1]; /* for debugging */
+char* yystates[1]; /* for debugging */
+#endif
+
+/* parser for yacc output */
+
+int yynerrs = 0; /* number of errors */
+int yyerrflag = 0; /* error recovery flag */
+
+extern int fprint(int, char*, ...);
+extern int sprint(char*, char*, ...);
+
+char*
+yytokname(int yyc)
+{
+ static char x[10];
+
+ if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
+ if(yytoknames[yyc-1])
+ return yytoknames[yyc-1];
+ sprintf(x, "<%d>", yyc);
+ return x;
+}
+
+char*
+yystatname(int yys)
+{
+ static char x[10];
+
+ if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
+ if(yystates[yys])
+ return yystates[yys];
+ sprintf(x, "<%d>\n", yys);
+ return x;
+}
+
+long
+yylex1(void)
+{
+ long yychar;
+ long *t3p;
+ int c;
+
+ yychar = yylex();
+ if(yychar <= 0) {
+ c = yytok1[0];
+ goto out;
+ }
+ if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
+ c = yytok1[yychar];
+ goto out;
+ }
+ if(yychar >= YYPRIVATE)
+ if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
+ c = yytok2[yychar-YYPRIVATE];
+ goto out;
+ }
+ for(t3p=yytok3;; t3p+=2) {
+ c = t3p[0];
+ if(c == yychar) {
+ c = t3p[1];
+ goto out;
+ }
+ if(c == 0)
+ break;
+ }
+ c = 0;
+
+out:
+ if(c == 0)
+ c = yytok2[1]; /* unknown char */
+ if(yydebug >= 3)
+ printf("lex %.4lX %s\n", yychar, yytokname(c));
+ return c;
+}
+
+int
+yyparse(void)
+{
+ struct
+ {
+ YYSTYPE yyv;
+ int yys;
+ } yys[YYMAXDEPTH], *yyp, *yypt;
+ short *yyxi;
+ int yyj, yym, yystate, yyn, yyg;
+ YYSTYPE save1, save2;
+ int save3, save4;
+ long yychar;
+
+ save1 = yylval;
+ save2 = yyval;
+ save3 = yynerrs;
+ save4 = yyerrflag;
+
+ yystate = 0;
+ yychar = -1;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yyp = &yys[-1];
+ goto yystack;
+
+ret0:
+ yyn = 0;
+ goto ret;
+
+ret1:
+ yyn = 1;
+ goto ret;
+
+ret:
+ yylval = save1;
+ yyval = save2;
+ yynerrs = save3;
+ yyerrflag = save4;
+ return yyn;
+
+yystack:
+ /* put a state and value onto the stack */
+ if(yydebug >= 4)
+ printf("char %s in %s", yytokname(yychar), yystatname(yystate));
+
+ yyp++;
+ if(yyp >= &yys[YYMAXDEPTH]) {
+ yyerror("yacc stack overflow");
+ goto ret1;
+ }
+ yyp->yys = yystate;
+ yyp->yyv = yyval;
+
+yynewstate:
+ yyn = yypact[yystate];
+ if(yyn <= YYFLAG)
+ goto yydefault; /* simple state */
+ if(yychar < 0)
+ yychar = yylex1();
+ yyn += yychar;
+ if(yyn < 0 || yyn >= YYLAST)
+ goto yydefault;
+ yyn = yyact[yyn];
+ if(yychk[yyn] == yychar) { /* valid shift */
+ yychar = -1;
+ yyval = yylval;
+ yystate = yyn;
+ if(yyerrflag > 0)
+ yyerrflag--;
+ goto yystack;
+ }
+
+yydefault:
+ /* default state action */
+ yyn = yydef[yystate];
+ if(yyn == -2) {
+ if(yychar < 0)
+ yychar = yylex1();
+
+ /* look through exception table */
+ for(yyxi=yyexca;; yyxi+=2)
+ if(yyxi[0] == -1 && yyxi[1] == yystate)
+ break;
+ for(yyxi += 2;; yyxi += 2) {
+ yyn = yyxi[0];
+ if(yyn < 0 || yyn == yychar)
+ break;
+ }
+ yyn = yyxi[1];
+ if(yyn < 0)
+ goto ret0;
+ }
+ if(yyn == 0) {
+ /* error ... attempt to resume parsing */
+ switch(yyerrflag) {
+ case 0: /* brand new error */
+ yyerror("syntax error");
+ if(yydebug >= 1) {
+ printf("%s", yystatname(yystate));
+ printf("saw %s\n", yytokname(yychar));
+ }
+yyerrlab:
+ yynerrs++;
+
+ case 1:
+ case 2: /* incompletely recovered error ... try again */
+ yyerrflag = 3;
+
+ /* find a state where "error" is a legal shift action */
+ while(yyp >= yys) {
+ yyn = yypact[yyp->yys] + YYERRCODE;
+ if(yyn >= 0 && yyn < YYLAST) {
+ yystate = yyact[yyn]; /* simulate a shift of "error" */
+ if(yychk[yystate] == YYERRCODE)
+ goto yystack;
+ }
+
+ /* the current yyp has no shift onn "error", pop stack */
+ if(yydebug >= 2)
+ printf("error recovery pops state %d, uncovers %d\n",
+ yyp->yys, (yyp-1)->yys );
+ yyp--;
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1;
+
+ case 3: /* no shift yet; clobber input char */
+ if(yydebug >= YYEOFCODE)
+ printf("error recovery discards %s\n", yytokname(yychar));
+ if(yychar == YYEOFCODE)
+ goto ret1;
+ yychar = -1;
+ goto yynewstate; /* try again in the same state */
+ }
+ }
+
+ /* reduction by production yyn */
+ if(yydebug >= 2)
+ printf("reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+ yypt = yyp;
+ yyp -= yyr2[yyn];
+ yyval = (yyp+1)->yyv;
+ yym = yyn;
+
+ /* consult goto table to find next state */
+ yyn = yyr1[yyn];
+ yyg = yypgo[yyn];
+ yyj = yyg + yyp->yys + 1;
+
+ if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+ yystate = yyact[yyg];
+ switch(yym) {
+
+case 1:
+#line 98 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (errorflag==0)
+ winner = (Node *)stat3(PROGRAM, beginloc, yypt[-0].yyv.p, endloc); } break;
+case 2:
+#line 100 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyclearin; bracecheck(); SYNTAX("bailing out"); } break;
+case 13:
+#line 124 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 14:
+#line 125 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat4(FOR, yypt[-9].yyv.p, notnull(yypt[-6].yyv.p), yypt[-3].yyv.p, yypt[-0].yyv.p); } break;
+case 15:
+#line 126 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 16:
+#line 127 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat4(FOR, yypt[-7].yyv.p, NIL, yypt[-3].yyv.p, yypt[-0].yyv.p); } break;
+case 17:
+#line 128 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 18:
+#line 129 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat3(IN, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-0].yyv.p); } break;
+case 19:
+#line 133 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ setfname(yypt[-0].yyv.cp); } break;
+case 20:
+#line 134 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ setfname(yypt[-0].yyv.cp); } break;
+case 21:
+#line 138 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = notnull(yypt[-1].yyv.p); } break;
+case 26:
+#line 150 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.i = 0; } break;
+case 28:
+#line 155 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.i = 0; } break;
+case 30:
+#line 161 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = 0; } break;
+case 32:
+#line 166 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = 0; } break;
+case 33:
+#line 167 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 34:
+#line 171 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = notnull(yypt[-0].yyv.p); } break;
+case 35:
+#line 175 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(PASTAT, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break;
+case 36:
+#line 176 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(PASTAT, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 37:
+#line 177 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = pa2stat(yypt[-2].yyv.p, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break;
+case 38:
+#line 178 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = pa2stat(yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 39:
+#line 179 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(PASTAT, NIL, yypt[-1].yyv.p); } break;
+case 40:
+#line 181 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ beginloc = linkum(beginloc, yypt[-1].yyv.p); yyval.p = 0; } break;
+case 41:
+#line 183 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ endloc = linkum(endloc, yypt[-1].yyv.p); yyval.p = 0; } break;
+case 42:
+#line 184 "/n/bopp/v7/bwk/awk/awkgram.y"
+{infunc++;} break;
+case 43:
+#line 185 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ infunc--; curfname=0; defn((Cell *)yypt[-7].yyv.p, yypt[-5].yyv.p, yypt[-1].yyv.p); yyval.p = 0; } break;
+case 45:
+#line 190 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 47:
+#line 195 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 48:
+#line 199 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 49:
+#line 201 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 50:
+#line 203 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 51:
+#line 205 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 52:
+#line 206 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break;
+case 53:
+#line 208 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-0].yyv.p))
+ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0));
+ else
+ yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 54:
+#line 212 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 55:
+#line 213 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 56:
+#line 214 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 59:
+#line 220 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 60:
+#line 222 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 61:
+#line 224 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 62:
+#line 226 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 63:
+#line 227 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 64:
+#line 228 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 65:
+#line 229 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 66:
+#line 230 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 67:
+#line 231 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 68:
+#line 232 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 69:
+#line 233 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break;
+case 70:
+#line 235 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-0].yyv.p))
+ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0));
+ else
+ yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 71:
+#line 239 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 72:
+#line 240 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 73:
+#line 241 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("cmd | getline is unsafe");
+ else yyval.p = op3(GETLINE, yypt[-0].yyv.p, itonp(yypt[-2].yyv.i), yypt[-3].yyv.p); } break;
+case 74:
+#line 244 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("cmd | getline is unsafe");
+ else yyval.p = op3(GETLINE, (Node*)0, itonp(yypt[-1].yyv.i), yypt[-2].yyv.p); } break;
+case 75:
+#line 247 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 78:
+#line 253 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 79:
+#line 254 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 81:
+#line 259 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 82:
+#line 263 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = rectonode(); } break;
+case 84:
+#line 265 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 93:
+#line 282 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(MATCH, NIL, rectonode(), (Node*)makedfa(yypt[-0].yyv.s, 0)); } break;
+case 94:
+#line 283 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break;
+case 95:
+#line 287 "/n/bopp/v7/bwk/awk/awkgram.y"
+{startreg();} break;
+case 96:
+#line 287 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.s = yypt[-1].yyv.s; } break;
+case 99:
+#line 295 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("print | is unsafe");
+ else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 100:
+#line 298 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("print >> is unsafe");
+ else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 101:
+#line 301 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("print > is unsafe");
+ else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 102:
+#line 304 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat3(yypt[-1].yyv.i, yypt[-0].yyv.p, NIL, NIL); } break;
+case 103:
+#line 305 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(DELETE, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break;
+case 104:
+#line 306 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(DELETE, makearr(yypt[-0].yyv.p), 0); } break;
+case 105:
+#line 307 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = exptostat(yypt[-0].yyv.p); } break;
+case 106:
+#line 308 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyclearin; SYNTAX("illegal statement"); } break;
+case 109:
+#line 317 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (!inloop) SYNTAX("break illegal outside of loops");
+ yyval.p = stat1(BREAK, NIL); } break;
+case 110:
+#line 319 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (!inloop) SYNTAX("continue illegal outside of loops");
+ yyval.p = stat1(CONTINUE, NIL); } break;
+case 111:
+#line 321 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 112:
+#line 321 "/n/bopp/v7/bwk/awk/awkgram.y"
+{--inloop;} break;
+case 113:
+#line 322 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(DO, yypt[-6].yyv.p, notnull(yypt[-2].yyv.p)); } break;
+case 114:
+#line 323 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(EXIT, yypt[-1].yyv.p); } break;
+case 115:
+#line 324 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(EXIT, NIL); } break;
+case 117:
+#line 326 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat3(IF, yypt[-3].yyv.p, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 118:
+#line 327 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat3(IF, yypt[-1].yyv.p, yypt[-0].yyv.p, NIL); } break;
+case 119:
+#line 328 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 120:
+#line 329 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (infunc)
+ SYNTAX("next is illegal inside a function");
+ yyval.p = stat1(NEXT, NIL); } break;
+case 121:
+#line 332 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (infunc)
+ SYNTAX("nextfile is illegal inside a function");
+ yyval.p = stat1(NEXTFILE, NIL); } break;
+case 122:
+#line 335 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(RETURN, yypt[-1].yyv.p); } break;
+case 123:
+#line 336 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(RETURN, NIL); } break;
+case 125:
+#line 338 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 126:
+#line 338 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat2(WHILE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 127:
+#line 339 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = 0; } break;
+case 129:
+#line 344 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 132:
+#line 352 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(DIVEQ, yypt[-3].yyv.p, yypt[-0].yyv.p); } break;
+case 133:
+#line 353 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(ADD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 134:
+#line 354 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(MINUS, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 135:
+#line 355 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(MULT, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 136:
+#line 356 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(DIVIDE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 137:
+#line 357 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(MOD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 138:
+#line 358 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(POWER, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 139:
+#line 359 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(UMINUS, yypt[-0].yyv.p); } break;
+case 140:
+#line 360 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-0].yyv.p; } break;
+case 141:
+#line 361 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break;
+case 142:
+#line 362 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BLTIN, itonp(yypt[-2].yyv.i), rectonode()); } break;
+case 143:
+#line 363 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BLTIN, itonp(yypt[-3].yyv.i), yypt[-1].yyv.p); } break;
+case 144:
+#line 364 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BLTIN, itonp(yypt[-0].yyv.i), rectonode()); } break;
+case 145:
+#line 365 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CALL, celltonode(yypt[-2].yyv.cp,CVAR), NIL); } break;
+case 146:
+#line 366 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CALL, celltonode(yypt[-3].yyv.cp,CVAR), yypt[-1].yyv.p); } break;
+case 147:
+#line 367 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(CLOSE, yypt[-0].yyv.p); } break;
+case 148:
+#line 368 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(PREDECR, yypt[-0].yyv.p); } break;
+case 149:
+#line 369 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(PREINCR, yypt[-0].yyv.p); } break;
+case 150:
+#line 370 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(POSTDECR, yypt[-1].yyv.p); } break;
+case 151:
+#line 371 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(POSTINCR, yypt[-1].yyv.p); } break;
+case 152:
+#line 372 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 153:
+#line 373 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, NIL, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 154:
+#line 374 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, yypt[-0].yyv.p, NIL, NIL); } break;
+case 155:
+#line 375 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, NIL, NIL, NIL); } break;
+case 156:
+#line 377 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INDEX, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 157:
+#line 379 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ SYNTAX("index() doesn't permit regular expressions");
+ yyval.p = op2(INDEX, yypt[-3].yyv.p, (Node*)yypt[-1].yyv.s); } break;
+case 158:
+#line 381 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 159:
+#line 383 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(yypt[-1].yyv.s, 1)); } break;
+case 160:
+#line 385 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-1].yyv.p))
+ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(strnode(yypt[-1].yyv.p), 1));
+ else
+ yyval.p = op3(MATCHFCN, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 161:
+#line 389 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break;
+case 162:
+#line 391 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p, (Node*)STRING); } break;
+case 163:
+#line 393 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), (Node*)makedfa(yypt[-1].yyv.s, 1), (Node *)REGEXPR); } break;
+case 164:
+#line 395 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(SPLIT, yypt[-3].yyv.p, makearr(yypt[-1].yyv.p), NIL, (Node*)STRING); } break;
+case 165:
+#line 396 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(yypt[-3].yyv.i, yypt[-1].yyv.p); } break;
+case 166:
+#line 397 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break;
+case 167:
+#line 399 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(yypt[-3].yyv.s, 1), yypt[-1].yyv.p, rectonode()); } break;
+case 168:
+#line 401 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-3].yyv.p))
+ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-3].yyv.p), 1), yypt[-1].yyv.p, rectonode());
+ else
+ yyval.p = op4(yypt[-5].yyv.i, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p, rectonode()); } break;
+case 169:
+#line 406 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(yypt[-5].yyv.s, 1), yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 170:
+#line 408 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-5].yyv.p))
+ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-5].yyv.p), 1), yypt[-3].yyv.p, yypt[-1].yyv.p);
+ else
+ yyval.p = op4(yypt[-7].yyv.i, (Node *)1, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 171:
+#line 413 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(SUBSTR, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 172:
+#line 415 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(SUBSTR, yypt[-3].yyv.p, yypt[-1].yyv.p, NIL); } break;
+case 175:
+#line 421 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(ARRAY, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break;
+case 176:
+#line 422 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(INDIRECT, celltonode(yypt[-0].yyv.cp, CVAR)); } break;
+case 177:
+#line 423 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(INDIRECT, yypt[-0].yyv.p); } break;
+case 178:
+#line 427 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ arglist = yyval.p = 0; } break;
+case 179:
+#line 428 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ arglist = yyval.p = celltonode(yypt[-0].yyv.cp,CVAR); } break;
+case 180:
+#line 429 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ checkdup(yypt[-2].yyv.p, yypt[-0].yyv.cp);
+ arglist = yyval.p = linkum(yypt[-2].yyv.p,celltonode(yypt[-0].yyv.cp,CVAR)); } break;
+case 181:
+#line 435 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = celltonode(yypt[-0].yyv.cp, CVAR); } break;
+case 182:
+#line 436 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(ARG, itonp(yypt[-0].yyv.i)); } break;
+case 183:
+#line 437 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(VARNF, (Node *) yypt[-0].yyv.cp); } break;
+case 184:
+#line 442 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = notnull(yypt[-1].yyv.p); } break;
+ }
+ goto yystack; /* stack new state and value */
+}
diff --git a/utils/awk/ytab.h b/utils/awk/ytab.h
new file mode 100644
index 00000000..d18ddfdb
--- /dev/null
+++ b/utils/awk/ytab.h
@@ -0,0 +1,100 @@
+
+typedef union {
+ Node *p;
+ Cell *cp;
+ int i;
+ char *s;
+} YYSTYPE;
+extern YYSTYPE yylval;
+#define FIRSTTOKEN 57346
+#define PROGRAM 57347
+#define PASTAT 57348
+#define PASTAT2 57349
+#define XBEGIN 57350
+#define XEND 57351
+#define NL 57352
+#define ARRAY 57353
+#define MATCH 57354
+#define NOTMATCH 57355
+#define MATCHOP 57356
+#define FINAL 57357
+#define DOT 57358
+#define ALL 57359
+#define CCL 57360
+#define NCCL 57361
+#define CHAR 57362
+#define OR 57363
+#define STAR 57364
+#define QUEST 57365
+#define PLUS 57366
+#define AND 57367
+#define BOR 57368
+#define APPEND 57369
+#define EQ 57370
+#define GE 57371
+#define GT 57372
+#define LE 57373
+#define LT 57374
+#define NE 57375
+#define IN 57376
+#define ARG 57377
+#define BLTIN 57378
+#define BREAK 57379
+#define CLOSE 57380
+#define CONTINUE 57381
+#define DELETE 57382
+#define DO 57383
+#define EXIT 57384
+#define FOR 57385
+#define FUNC 57386
+#define SUB 57387
+#define GSUB 57388
+#define IF 57389
+#define INDEX 57390
+#define LSUBSTR 57391
+#define MATCHFCN 57392
+#define NEXT 57393
+#define NEXTFILE 57394
+#define ADD 57395
+#define MINUS 57396
+#define MULT 57397
+#define DIVIDE 57398
+#define MOD 57399
+#define ASSIGN 57400
+#define ASGNOP 57401
+#define ADDEQ 57402
+#define SUBEQ 57403
+#define MULTEQ 57404
+#define DIVEQ 57405
+#define MODEQ 57406
+#define POWEQ 57407
+#define PRINT 57408
+#define PRINTF 57409
+#define SPRINTF 57410
+#define ELSE 57411
+#define INTEST 57412
+#define CONDEXPR 57413
+#define POSTINCR 57414
+#define PREINCR 57415
+#define POSTDECR 57416
+#define PREDECR 57417
+#define VAR 57418
+#define IVAR 57419
+#define VARNF 57420
+#define CALL 57421
+#define NUMBER 57422
+#define STRING 57423
+#define REGEXPR 57424
+#define GETLINE 57425
+#define RETURN 57426
+#define SPLIT 57427
+#define SUBSTR 57428
+#define WHILE 57429
+#define CAT 57430
+#define NOT 57431
+#define UMINUS 57432
+#define POWER 57433
+#define DECR 57434
+#define INCR 57435
+#define INDIRECT 57436
+#define LASTTOKEN 57437
diff --git a/utils/awk/ytabc.bak b/utils/awk/ytabc.bak
new file mode 100644
index 00000000..2a6a938b
--- /dev/null
+++ b/utils/awk/ytabc.bak
@@ -0,0 +1,1623 @@
+
+#line 26 "/n/bopp/v7/bwk/awk/awkgram.y"
+#include <stdio.h>
+#include <string.h>
+#include "awk.h"
+
+void checkdup(Node *list, Cell *item);
+int yywrap(void) { return(1); }
+
+Node *beginloc = 0;
+Node *endloc = 0;
+int infunc = 0; /* = 1 if in arglist or body of func */
+int inloop = 0; /* = 1 if in while, for, do */
+char *curfname = 0; /* current function name */
+Node *arglist = 0; /* list of args for current function */
+
+#line 41 "/n/bopp/v7/bwk/awk/awkgram.y"
+typedef union {
+ Node *p;
+ Cell *cp;
+ int i;
+ char *s;
+} YYSTYPE;
+extern int yyerrflag;
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 150
+#endif
+YYSTYPE yylval;
+YYSTYPE yyval;
+#define FIRSTTOKEN 57346
+#define PROGRAM 57347
+#define PASTAT 57348
+#define PASTAT2 57349
+#define XBEGIN 57350
+#define XEND 57351
+#define NL 57352
+#define ARRAY 57353
+#define MATCH 57354
+#define NOTMATCH 57355
+#define MATCHOP 57356
+#define FINAL 57357
+#define DOT 57358
+#define ALL 57359
+#define CCL 57360
+#define NCCL 57361
+#define CHAR 57362
+#define OR 57363
+#define STAR 57364
+#define QUEST 57365
+#define PLUS 57366
+#define AND 57367
+#define BOR 57368
+#define APPEND 57369
+#define EQ 57370
+#define GE 57371
+#define GT 57372
+#define LE 57373
+#define LT 57374
+#define NE 57375
+#define IN 57376
+#define ARG 57377
+#define BLTIN 57378
+#define BREAK 57379
+#define CLOSE 57380
+#define CONTINUE 57381
+#define DELETE 57382
+#define DO 57383
+#define EXIT 57384
+#define FOR 57385
+#define FUNC 57386
+#define SUB 57387
+#define GSUB 57388
+#define IF 57389
+#define INDEX 57390
+#define LSUBSTR 57391
+#define MATCHFCN 57392
+#define NEXT 57393
+#define NEXTFILE 57394
+#define ADD 57395
+#define MINUS 57396
+#define MULT 57397
+#define DIVIDE 57398
+#define MOD 57399
+#define ASSIGN 57400
+#define ASGNOP 57401
+#define ADDEQ 57402
+#define SUBEQ 57403
+#define MULTEQ 57404
+#define DIVEQ 57405
+#define MODEQ 57406
+#define POWEQ 57407
+#define PRINT 57408
+#define PRINTF 57409
+#define SPRINTF 57410
+#define ELSE 57411
+#define INTEST 57412
+#define CONDEXPR 57413
+#define POSTINCR 57414
+#define PREINCR 57415
+#define POSTDECR 57416
+#define PREDECR 57417
+#define VAR 57418
+#define IVAR 57419
+#define VARNF 57420
+#define CALL 57421
+#define NUMBER 57422
+#define STRING 57423
+#define REGEXPR 57424
+#define GETLINE 57425
+#define RETURN 57426
+#define SPLIT 57427
+#define SUBSTR 57428
+#define WHILE 57429
+#define CAT 57430
+#define NOT 57431
+#define UMINUS 57432
+#define POWER 57433
+#define DECR 57434
+#define INCR 57435
+#define INDIRECT 57436
+#define LASTTOKEN 57437
+#define YYEOFCODE 1
+#define YYERRCODE 2
+
+#line 445 "/n/bopp/v7/bwk/awk/awkgram.y"
+
+
+void setfname(Cell *p)
+{
+ if (isarr(p))
+ SYNTAX("%s is an array, not a function", p->nval);
+ else if (isfcn(p))
+ SYNTAX("you can't define function %s more than once", p->nval);
+ curfname = p->nval;
+}
+
+int constnode(Node *p)
+{
+ return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON;
+}
+
+char *strnode(Node *p)
+{
+ return ((Cell *)(p->narg[0]))->sval;
+}
+
+Node *notnull(Node *n)
+{
+ switch (n->nobj) {
+ case LE: case LT: case EQ: case NE: case GT: case GE:
+ case BOR: case AND: case NOT:
+ return n;
+ default:
+ return op2(NE, n, nullnode);
+ }
+}
+
+void checkdup(Node *vl, Cell *cp) /* check if name already in list */
+{
+ char *s = cp->nval;
+ for ( ; vl; vl = vl->nnext) {
+ if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) {
+ SYNTAX("duplicate argument %s", s);
+ break;
+ }
+ }
+}
+short yyexca[] =
+{-1, 0,
+ 1, 28,
+ 8, 28,
+ 9, 28,
+ 12, 28,
+ 13, 28,
+ 16, 28,
+ 45, 28,
+ 46, 28,
+ 48, 28,
+ 54, 28,
+ 55, 28,
+ 56, 28,
+ 58, 28,
+ 60, 28,
+ 78, 28,
+ 86, 28,
+ 87, 28,
+ 88, 28,
+ 89, 28,
+ 90, 28,
+ 91, 28,
+ 95, 28,
+ 97, 28,
+ 98, 28,
+ 101, 28,
+ 102, 28,
+ 105, 28,
+ 108, 28,
+ 109, 28,
+ 110, 28,
+ -2, 0,
+-1, 1,
+ 1, -1,
+ -2, 0,
+-1, 157,
+ 15, 30,
+ -2, 0,
+-1, 176,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 63,
+-1, 177,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 64,
+-1, 178,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 65,
+-1, 179,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 66,
+-1, 180,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 67,
+-1, 181,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 68,
+-1, 183,
+ 14, 0,
+ 24, 0,
+ 38, 0,
+ 39, 0,
+ 40, 0,
+ 41, 0,
+ 42, 0,
+ 43, 0,
+ 44, 0,
+ -2, 70,
+-1, 289,
+ 24, 0,
+ 44, 0,
+ -2, 53,
+-1, 333,
+ 17, 30,
+ -2, 0,
+-1, 355,
+ 17, 30,
+ -2, 0,
+};
+#define YYNPROD 185
+#define YYPRIVATE 57344
+#define YYLAST 4177
+short yyact[] =
+{
+ 17, 277, 138, 66, 243, 228, 253, 54, 24, 43,
+ 125, 112, 200, 43, 103, 104, 100, 139, 102, 155,
+ 308, 185, 215, 249, 100, 253, 100, 100, 100, 107,
+ 105, 100, 122, 123, 124, 223, 107, 206, 43, 82,
+ 162, 43, 83, 103, 104, 10, 113, 314, 9, 252,
+ 42, 22, 44, 244, 42, 22, 44, 103, 104, 134,
+ 142, 113, 146, 190, 278, 352, 149, 150, 152, 153,
+ 148, 276, 316, 163, 23, 100, 351, 350, 23, 42,
+ 62, 44, 42, 22, 44, 11, 156, 168, 169, 85,
+ 253, 51, 321, 79, 80, 232, 190, 86, 135, 133,
+ 100, 318, 182, 320, 269, 258, 23, 100, 100, 100,
+ 100, 100, 100, 100, 108, 109, 110, 111, 233, 275,
+ 112, 234, 190, 110, 111, 43, 100, 112, 335, 190,
+ 190, 11, 203, 205, 190, 324, 278, 190, 190, 212,
+ 284, 190, 211, 265, 260, 190, 100, 259, 221, 3,
+ 141, 188, 100, 16, 226, 140, 331, 6, 156, 141,
+ 219, 230, 7, 100, 310, 6, 42, 170, 44, 167,
+ 7, 158, 100, 157, 100, 131, 100, 100, 100, 100,
+ 100, 100, 100, 130, 100, 48, 251, 100, 100, 129,
+ 49, 128, 236, 127, 100, 126, 120, 119, 52, 16,
+ 190, 19, 100, 312, 141, 274, 218, 100, 143, 100,
+ 100, 100, 4, 154, 100, 100, 217, 271, 144, 132,
+ 317, 50, 347, 361, 364, 270, 1, 115, 72, 40,
+ 224, 5, 100, 100, 100, 100, 163, 58, 163, 163,
+ 163, 163, 20, 67, 163, 222, 100, 293, 61, 288,
+ 294, 60, 238, 248, 81, 100, 100, 292, 96, 8,
+ 239, 159, 160, 2, 0, 0, 114, 0, 116, 117,
+ 118, 300, 301, 121, 164, 0, 282, 0, 285, 286,
+ 287, 289, 0, 100, 291, 0, 100, 100, 100, 0,
+ 100, 0, 100, 156, 0, 309, 0, 100, 0, 100,
+ 100, 0, 0, 100, 0, 100, 100, 100, 0, 0,
+ 0, 0, 0, 334, 313, 165, 163, 96, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 341, 156, 342,
+ 333, 0, 340, 100, 0, 0, 0, 230, 100, 346,
+ 100, 0, 116, 0, 100, 100, 348, 0, 356, 96,
+ 194, 195, 196, 197, 198, 199, 337, 359, 0, 230,
+ 0, 360, 362, 156, 0, 355, 0, 0, 207, 0,
+ 0, 0, 238, 0, 0, 238, 238, 238, 0, 238,
+ 239, 238, 0, 239, 239, 239, 0, 239, 96, 239,
+ 0, 0, 21, 0, 96, 0, 0, 0, 338, 0,
+ 0, 0, 0, 0, 257, 242, 0, 0, 55, 0,
+ 0, 0, 0, 0, 96, 0, 96, 0, 96, 96,
+ 96, 96, 96, 96, 96, 0, 96, 238, 0, 96,
+ 96, 0, 0, 0, 0, 239, 256, 164, 0, 164,
+ 164, 164, 164, 0, 96, 164, 0, 0, 0, 261,
+ 0, 96, 96, 96, 0, 0, 96, 96, 0, 0,
+ 0, 0, 0, 137, 0, 0, 166, 0, 0, 0,
+ 147, 0, 0, 0, 96, 279, 280, 281, 165, 0,
+ 165, 165, 165, 165, 0, 0, 165, 184, 96, 0,
+ 0, 0, 0, 0, 0, 0, 0, 96, 96, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 74, 0,
+ 189, 191, 0, 15, 0, 0, 0, 164, 0, 0,
+ 0, 0, 0, 0, 0, 242, 0, 106, 242, 242,
+ 242, 0, 242, 0, 242, 0, 0, 0, 0, 96,
+ 0, 96, 96, 137, 0, 96, 0, 96, 96, 96,
+ 229, 0, 0, 220, 0, 0, 0, 137, 165, 15,
+ 0, 15, 0, 227, 0, 235, 0, 0, 145, 0,
+ 0, 0, 0, 0, 151, 96, 0, 137, 137, 0,
+ 242, 0, 96, 0, 0, 0, 96, 96, 0, 0,
+ 0, 0, 0, 171, 173, 175, 176, 177, 178, 179,
+ 180, 181, 183, 0, 0, 0, 0, 0, 0, 0,
+ 186, 187, 0, 262, 263, 264, 0, 266, 267, 268,
+ 0, 0, 201, 0, 0, 0, 0, 0, 201, 201,
+ 0, 273, 0, 0, 290, 208, 209, 210, 201, 213,
+ 214, 189, 0, 0, 0, 297, 0, 0, 0, 101,
+ 0, 0, 0, 295, 0, 0, 0, 303, 0, 0,
+ 240, 0, 0, 0, 0, 0, 0, 231, 0, 311,
+ 106, 98, 97, 0, 0, 0, 245, 0, 0, 137,
+ 241, 43, 28, 0, 30, 0, 0, 0, 0, 0,
+ 0, 46, 47, 0, 34, 0, 35, 0, 254, 0,
+ 255, 0, 0, 0, 0, 0, 0, 336, 323, 326,
+ 328, 329, 0, 0, 38, 0, 0, 0, 189, 0,
+ 0, 0, 42, 22, 44, 29, 36, 39, 0, 237,
+ 315, 33, 0, 37, 41, 0, 0, 27, 26, 0,
+ 0, 99, 0, 0, 31, 32, 23, 0, 0, 0,
+ 0, 0, 0, 201, 0, 0, 357, 137, 0, 296,
+ 0, 0, 0, 0, 0, 0, 298, 0, 0, 0,
+ 363, 299, 302, 365, 0, 304, 305, 306, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 106, 0, 0, 0, 0, 0, 75, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 16, 18,
+ 0, 68, 45, 0, 358, 0, 0, 0, 332, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 339, 0, 0, 0, 0, 0, 343, 0,
+ 344, 43, 28, 56, 30, 57, 73, 69, 59, 70,
+ 0, 46, 47, 71, 34, 0, 35, 63, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 75, 0, 0,
+ 0, 0, 77, 78, 38, 53, 0, 16, 18, 0,
+ 68, 45, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 33, 65, 37, 41, 76, 0, 27, 26, 0,
+ 0, 25, 0, 0, 31, 32, 23, 0, 0, 0,
+ 43, 28, 56, 30, 57, 73, 69, 59, 70, 0,
+ 46, 47, 71, 34, 0, 35, 63, 64, 0, 0,
+ 0, 0, 0, 0, 75, 0, 0, 0, 0, 0,
+ 0, 77, 78, 38, 16, 18, 0, 68, 45, 0,
+ 307, 42, 22, 44, 29, 36, 39, 0, 0, 0,
+ 33, 65, 37, 41, 76, 0, 27, 26, 0, 0,
+ 25, 0, 0, 31, 32, 23, 0, 43, 28, 56,
+ 30, 57, 73, 69, 59, 70, 0, 46, 47, 71,
+ 34, 0, 35, 63, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 75, 0, 0, 0, 0, 77, 78,
+ 38, 272, 0, 16, 18, 0, 68, 45, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 65, 37,
+ 41, 76, 0, 27, 26, 0, 0, 25, 0, 0,
+ 31, 32, 23, 0, 0, 0, 43, 28, 56, 30,
+ 57, 73, 69, 59, 70, 0, 46, 47, 71, 34,
+ 0, 35, 63, 64, 0, 0, 0, 0, 0, 0,
+ 75, 0, 0, 0, 0, 0, 0, 77, 78, 38,
+ 16, 18, 0, 68, 45, 0, 247, 42, 22, 44,
+ 29, 36, 39, 0, 0, 0, 33, 65, 37, 41,
+ 76, 0, 27, 26, 0, 0, 25, 0, 0, 31,
+ 32, 23, 0, 43, 28, 56, 30, 57, 73, 69,
+ 59, 70, 0, 46, 47, 71, 34, 0, 35, 63,
+ 64, 0, 0, 0, 0, 0, 0, 75, 0, 0,
+ 0, 0, 0, 0, 77, 78, 38, 16, 18, 0,
+ 68, 45, 0, 246, 42, 22, 44, 29, 36, 39,
+ 0, 0, 0, 33, 65, 37, 41, 76, 0, 27,
+ 26, 0, 0, 25, 0, 0, 31, 32, 23, 0,
+ 43, 28, 56, 30, 57, 73, 69, 59, 70, 0,
+ 46, 47, 71, 34, 0, 35, 63, 64, 0, 0,
+ 0, 0, 0, 0, 75, 0, 0, 0, 0, 0,
+ 0, 77, 78, 38, 16, 18, 0, 68, 45, 0,
+ 225, 42, 22, 44, 29, 36, 39, 0, 0, 0,
+ 33, 65, 37, 41, 76, 0, 27, 26, 0, 0,
+ 25, 0, 0, 31, 32, 23, 0, 43, 28, 56,
+ 30, 57, 73, 69, 59, 70, 0, 46, 47, 71,
+ 34, 0, 35, 63, 64, 0, 0, 0, 0, 0,
+ 0, 75, 0, 0, 0, 0, 0, 0, 77, 78,
+ 38, 16, 18, 0, 68, 45, 0, 216, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 65, 37,
+ 41, 76, 0, 27, 26, 0, 0, 25, 0, 0,
+ 31, 32, 23, 0, 43, 28, 56, 30, 57, 73,
+ 69, 59, 70, 0, 46, 47, 71, 34, 0, 35,
+ 63, 64, 0, 0, 0, 0, 0, 0, 75, 0,
+ 0, 0, 0, 0, 0, 77, 78, 38, 16, 18,
+ 0, 68, 45, 0, 136, 42, 22, 44, 29, 36,
+ 39, 0, 0, 0, 33, 65, 37, 41, 76, 0,
+ 27, 26, 0, 0, 25, 0, 0, 31, 32, 23,
+ 0, 43, 28, 56, 30, 57, 73, 69, 59, 70,
+ 0, 46, 47, 71, 34, 0, 35, 63, 64, 0,
+ 0, 0, 0, 0, 0, 75, 0, 0, 0, 0,
+ 0, 0, 77, 78, 38, 16, 18, 0, 68, 45,
+ 0, 0, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 33, 65, 37, 41, 76, 0, 27, 26, 0,
+ 0, 25, 0, 0, 31, 32, 23, 0, 43, 28,
+ 56, 30, 57, 73, 69, 59, 70, 0, 46, 47,
+ 71, 34, 0, 35, 63, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 77,
+ 78, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 0, 0, 33, 65,
+ 37, 41, 76, 0, 27, 26, 0, 0, 25, 0,
+ 0, 31, 32, 23, 190, 0, 101, 95, 0, 0,
+ 330, 0, 0, 0, 0, 0, 0, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 97,
+ 0, 87, 88, 89, 90, 91, 92, 94, 43, 28,
+ 0, 30, 0, 0, 0, 0, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 84, 0, 33, 0,
+ 37, 41, 0, 0, 27, 26, 0, 0, 99, 0,
+ 0, 31, 32, 23, 190, 0, 101, 95, 0, 0,
+ 327, 0, 0, 0, 0, 0, 0, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 97,
+ 0, 87, 88, 89, 90, 91, 92, 94, 43, 28,
+ 0, 30, 0, 0, 0, 0, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 84, 0, 33, 0,
+ 37, 41, 0, 0, 27, 26, 0, 0, 99, 0,
+ 0, 31, 32, 23, 190, 0, 101, 95, 0, 0,
+ 325, 0, 0, 0, 0, 0, 0, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 98, 97,
+ 0, 87, 88, 89, 90, 91, 92, 94, 43, 28,
+ 0, 30, 0, 0, 0, 0, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 0, 42,
+ 22, 44, 29, 36, 39, 0, 84, 0, 33, 0,
+ 37, 41, 0, 0, 27, 26, 0, 0, 99, 0,
+ 0, 31, 32, 23, 141, 0, 0, 101, 95, 140,
+ 0, 0, 0, 0, 0, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 0, 0, 99,
+ 0, 0, 31, 32, 23, 190, 0, 101, 95, 0,
+ 0, 192, 0, 0, 0, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 101, 95, 99,
+ 0, 354, 31, 32, 23, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 101, 95, 99,
+ 0, 353, 31, 32, 23, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 101, 95, 99,
+ 0, 349, 31, 32, 23, 0, 0, 0, 93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 98,
+ 97, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 84, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 0, 0, 99,
+ 0, 0, 31, 32, 23, 101, 95, 345, 0, 0,
+ 0, 0, 0, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 101, 95, 99, 0, 322,
+ 31, 32, 23, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 101, 95, 99, 0, 319,
+ 31, 32, 23, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 101, 95, 99, 0, 278,
+ 31, 32, 23, 0, 0, 0, 93, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 98, 97, 0,
+ 87, 88, 89, 90, 91, 92, 94, 43, 28, 0,
+ 30, 0, 0, 0, 0, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 38, 0, 0, 0, 0, 0, 0, 0, 42, 22,
+ 44, 29, 36, 39, 0, 84, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 0, 190, 99, 101, 95,
+ 31, 32, 23, 0, 0, 0, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 192, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 250,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 97, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 84, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 101, 95,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 0, 0, 87, 88, 89, 90, 91, 92, 94,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 101, 95, 0,
+ 33, 0, 37, 41, 0, 0, 27, 26, 93, 0,
+ 99, 0, 0, 31, 32, 23, 0, 0, 0, 0,
+ 0, 0, 87, 88, 89, 90, 91, 92, 94, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 75, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 38, 18, 0, 0, 45, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 0, 0, 33,
+ 0, 37, 41, 0, 0, 27, 26, 0, 0, 99,
+ 0, 0, 31, 32, 23, 43, 28, 0, 30, 0,
+ 73, 0, 0, 0, 0, 46, 47, 0, 34, 0,
+ 35, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 77, 78, 38, 0,
+ 0, 101, 0, 0, 0, 0, 42, 22, 44, 29,
+ 36, 39, 240, 0, 0, 33, 0, 37, 41, 0,
+ 0, 27, 26, 98, 97, 25, 0, 0, 31, 32,
+ 23, 0, 241, 43, 28, 0, 30, 0, 0, 0,
+ 0, 0, 0, 46, 47, 0, 34, 0, 35, 0,
+ 0, 0, 0, 0, 12, 13, 0, 0, 16, 18,
+ 0, 0, 45, 0, 0, 0, 38, 0, 0, 0,
+ 0, 0, 0, 0, 42, 22, 44, 29, 36, 39,
+ 0, 237, 0, 33, 0, 37, 41, 0, 0, 27,
+ 26, 43, 28, 99, 30, 0, 31, 32, 23, 0,
+ 14, 46, 47, 0, 34, 0, 35, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 38, 0, 0, 101, 0, 0,
+ 0, 0, 42, 22, 44, 29, 36, 39, 240, 0,
+ 0, 33, 0, 37, 41, 0, 0, 27, 26, 98,
+ 0, 25, 0, 0, 31, 32, 23, 0, 241, 43,
+ 28, 0, 30, 0, 0, 0, 0, 0, 0, 46,
+ 47, 0, 34, 0, 35, 0, 0, 0, 0, 0,
+ 0, 0, 141, 0, 0, 18, 0, 140, 45, 0,
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 42, 22, 44, 29, 36, 39, 0, 253, 0, 33,
+ 18, 37, 41, 45, 0, 27, 26, 43, 28, 99,
+ 30, 0, 31, 32, 23, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 43, 28, 0, 30, 0, 0, 0, 0,
+ 38, 0, 46, 47, 0, 34, 0, 35, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 0, 37,
+ 41, 0, 0, 27, 26, 38, 0, 25, 101, 0,
+ 31, 32, 23, 42, 22, 44, 29, 36, 39, 240,
+ 0, 0, 33, 0, 37, 41, 0, 0, 27, 26,
+ 0, 0, 25, 0, 0, 31, 32, 23, 0, 241,
+ 43, 28, 0, 30, 0, 0, 0, 0, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 174, 0, 0, 283, 0, 0, 45,
+ 0, 0, 0, 38, 0, 0, 0, 0, 0, 0,
+ 0, 42, 22, 44, 29, 36, 39, 0, 172, 0,
+ 33, 283, 37, 41, 45, 0, 27, 26, 43, 28,
+ 99, 30, 0, 31, 32, 23, 0, 0, 46, 47,
+ 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 43, 28, 0, 30, 0, 0, 0,
+ 0, 38, 0, 46, 47, 0, 34, 0, 35, 42,
+ 22, 44, 29, 36, 39, 0, 253, 0, 33, 283,
+ 37, 41, 45, 0, 27, 26, 38, 0, 25, 0,
+ 0, 31, 32, 23, 42, 22, 44, 29, 36, 39,
+ 0, 0, 0, 33, 18, 37, 41, 45, 204, 27,
+ 26, 43, 28, 25, 30, 0, 31, 32, 23, 0,
+ 0, 46, 47, 0, 34, 0, 35, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 43, 28, 0, 30,
+ 0, 0, 0, 0, 38, 0, 46, 47, 0, 34,
+ 0, 35, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 33, 18, 37, 41, 45, 202, 27, 26, 38,
+ 0, 25, 0, 0, 31, 32, 23, 42, 22, 44,
+ 29, 36, 39, 0, 174, 0, 33, 18, 37, 41,
+ 45, 0, 27, 26, 43, 28, 25, 30, 0, 31,
+ 32, 23, 0, 0, 46, 47, 0, 34, 0, 35,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 28, 0, 30, 0, 0, 0, 0, 38, 0, 46,
+ 47, 0, 34, 0, 35, 42, 22, 44, 29, 36,
+ 39, 0, 172, 0, 33, 18, 37, 41, 45, 0,
+ 27, 26, 38, 0, 25, 0, 0, 31, 32, 23,
+ 42, 22, 44, 29, 36, 39, 0, 0, 0, 33,
+ 18, 37, 41, 45, 0, 27, 26, 43, 28, 25,
+ 30, 0, 31, 32, 23, 0, 0, 46, 47, 0,
+ 34, 0, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 43, 28, 0, 30, 0, 0, 0, 0,
+ 38, 0, 46, 47, 0, 34, 0, 35, 42, 22,
+ 44, 29, 36, 39, 0, 0, 0, 33, 283, 37,
+ 41, 45, 0, 27, 26, 38, 0, 25, 0, 0,
+ 31, 32, 23, 42, 22, 44, 29, 36, 39, 0,
+ 0, 0, 33, 101, 37, 41, 0, 0, 27, 26,
+ 43, 28, 25, 30, 0, 31, 32, 23, 0, 0,
+ 46, 47, 0, 34, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 43, 28, 0, 30, 0,
+ 0, 0, 0, 38, 0, 46, 47, 0, 34, 0,
+ 35, 42, 22, 44, 29, 36, 39, 0, 0, 193,
+ 33, 161, 37, 41, 45, 0, 27, 26, 38, 0,
+ 25, 0, 0, 31, 32, 23, 42, 22, 44, 29,
+ 36, 39, 0, 0, 0, 33, 101, 37, 41, 45,
+ 0, 27, 26, 43, 28, 99, 30, 0, 31, 32,
+ 23, 0, 0, 46, 47, 0, 34, 0, 35, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 43, 28,
+ 0, 30, 0, 0, 0, 0, 38, 0, 46, 47,
+ 0, 34, 0, 35, 42, 22, 44, 29, 36, 39,
+ 0, 0, 0, 33, 101, 37, 41, 0, 0, 27,
+ 26, 38, 0, 25, 0, 0, 31, 32, 23, 42,
+ 22, 44, 29, 36, 39, 0, 0, 0, 33, 101,
+ 37, 41, 0, 0, 27, 26, 43, 28, 25, 30,
+ 0, 31, 32, 23, 0, 0, 46, 47, 0, 34,
+ 0, 35, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 43, 28, 0, 30, 0, 0, 0, 0, 38,
+ 0, 46, 47, 0, 34, 0, 35, 42, 22, 44,
+ 29, 36, 39, 0, 0, 0, 33, 0, 37, 41,
+ 0, 0, 27, 26, 38, 0, 99, 0, 0, 31,
+ 32, 23, 42, 22, 44, 29, 36, 39, 0, 0,
+ 0, 0, 0, 37, 41, 0, 0, 27, 26, 0,
+ 0, 99, 0, 0, 31, 32, 23
+};
+short yypact[] =
+{
+ 147,-1000,-1000,-1000,3266, 175,-1000,-1000, 155,-1000,
+ 187, 865, 141, 141, -47,2905,-1000, -51,3817,-1000,
+ 13, 42,-1000,4041,-1000,3983,4041,4041, 184, 183,
+4041, -36, -36, -32, 182, 180,-1000, 178, 176,-1000,
+ 170, 162,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
+3266, 865,3817,-1000,1336,-1000, 140, 140, 198,3392,
+-1000,1403, 865, 140, 140,3392, 140,-1000, 194,-1000,
+ 160, 158,3958, -7,2905,-1000, 156,-1000,-1000, 865,
+ 865, 154,-1000,-1000,3817,3792,3734,3817,3817,3817,
+3817,3817,3817,3817, -7, -74, 13,-1000,-1000,4041,
+ -94,3817,3817,-1000,-1000, 134,1904,3900,4041,4041,
+4041,4041,4041,3817,-1000,-1000, -96, -96, -96,3709,
+3651, 13,-1000,-1000, -5,4041,3817,3817,3817,3817,
+3817,3817, -70,-1000,1269, 141,-1000,-1000,-1000, 196,
+ 194,-1000,-1000,-1000,1403,1804,-1000, -44,1202,-1000,
+-1000,1804,-1000,-1000,1403,-1000, 196,3140,3817, 81,
+ 189,3817,3208, -65,-1000, 13, 34,3817,1135,1068,
+ -63,2815,-1000,2995,-1000,3074,4066,4066,4066,4066,
+4066,4066,-1000,4066,-1000, -36,2725,2905, 5,3417,
+-1000,3417,-1000,4041, -96, 20, 20, -96, -96, -96,
+ 85,2905,-1000, 130,-1000, 127,4041, 13,2635,2635,
+2635, 126, 189,2635,2635, 88,-1000, 865,-1000,-1000,
+-1000,-1000,1001,-1000, 195,-1000,-1000,-1000, 104, 27,
+-1000,2542,4041,4041,4041,3626, 123,3875,3568,3543,
+3875, -7, 13,3875,3817,2542,-1000,-1000, 119,-1000,
+3817,-1000, -7,-1000,2905,2905, 13,3417,-1000,-1000,
+-1000, 13,3417,3417, 80,-1000,3417,3417,3417,-1000,
+ 932, -79,-1000,-1000,-1000, 149, -7, 193,-1000, 13,
+ 13, 13,3208,3817, 3, 636,3334,3485,-1000,4066,
+-1000,3208, 52, 193, 193, 15,2905,-1000,2905,2452,
+ 86, 75,2362, 118,1703,1603,1503,-1000, 143,3817,
+ 194, 47,-1000, 111, -7,3875,-1000, 141,-1000,-1000,
+-1000,-1000,-1000,3417,-1000,-1000, -4,-1000, -4,3417,
+-1000,3817,2272,3140, 193, 3,-1000,3208, 865,2174,
+ 60, 59, 48,2084,1994, 194, 47,1403, 796,-1000,
+-1000,-1000,-1000,-1000, 140,3140, 193,-1000,-1000,-1000,
+ 47,1403, 193,-1000,1403,-1000
+};
+short yypgo[] =
+{
+ 0, 263, 508, 40, 30, 262, 12, 261, 242, 201,
+ 45, 48, 259, 8, 3, 5, 408, 7, 0, 392,
+ 254, 253, 251, 248, 245, 243, 237, 2, 231, 212,
+ 80, 230, 1, 404, 17, 19, 97, 89, 229, 228,
+ 226, 224, 223, 222, 220, 219, 218, 217, 213
+};
+short yyr1[] =
+{
+ 0, 40, 40, 36, 36, 37, 37, 33, 33, 26,
+ 26, 24, 24, 41, 22, 42, 22, 43, 22, 20,
+ 20, 23, 30, 30, 34, 34, 35, 35, 29, 29,
+ 15, 15, 1, 1, 10, 11, 11, 11, 11, 11,
+ 11, 11, 44, 11, 12, 12, 6, 6, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 4, 4,
+ 5, 5, 7, 7, 7, 39, 39, 28, 28, 28,
+ 28, 31, 31, 9, 9, 45, 13, 32, 32, 14,
+ 14, 14, 14, 14, 14, 14, 14, 27, 27, 16,
+ 16, 46, 47, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 48, 16, 16, 17, 17,
+ 38, 38, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 18, 18, 18, 18, 21, 21,
+ 21, 19, 19, 19, 25
+};
+short yyr2[] =
+{
+ 0, 1, 1, 1, 2, 1, 2, 1, 2, 1,
+ 2, 1, 2, 0, 12, 0, 10, 0, 8, 1,
+ 1, 4, 1, 2, 1, 2, 0, 1, 0, 1,
+ 0, 1, 1, 3, 1, 1, 4, 3, 6, 3,
+ 4, 4, 0, 9, 1, 3, 1, 3, 3, 5,
+ 3, 3, 3, 3, 3, 5, 2, 1, 1, 3,
+ 5, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 5, 4, 3, 2, 1, 1, 3, 3,
+ 1, 3, 0, 1, 3, 1, 1, 1, 1, 2,
+ 2, 1, 2, 1, 2, 0, 4, 1, 2, 4,
+ 4, 4, 2, 5, 2, 1, 1, 1, 2, 2,
+ 2, 0, 0, 9, 3, 2, 1, 4, 2, 3,
+ 2, 2, 3, 2, 2, 0, 3, 2, 1, 2,
+ 1, 1, 4, 3, 3, 3, 3, 3, 3, 2,
+ 2, 2, 3, 4, 1, 3, 4, 2, 2, 2,
+ 2, 2, 4, 3, 2, 1, 6, 6, 3, 6,
+ 6, 1, 8, 8, 6, 4, 1, 6, 6, 8,
+ 8, 8, 6, 1, 1, 4, 1, 2, 0, 1,
+ 3, 1, 1, 1, 4
+};
+short yychk[] =
+{
+-1000, -40, -1, 2, -29, -28, 10, 15, -12, -11,
+ -10, -30, 8, 9, 54, -2, 12, -18, 13, -9,
+ -8, -19, 87, 110, -13, 105, 102, 101, 46, 89,
+ 48, 108, 109, 95, 58, 60, 90, 97, 78, 91,
+ -38, 98, 86, 45, 88, 16, 55, 56, 10, 15,
+ -29, -30, 11, 10, -17, -16, 47, 49, -26, 52,
+ -22, -23, -30, 61, 62, 96, -14, -25, 15, 51,
+ 53, 57, -39, 50, -2, 2, 99, 76, 77, -30,
+ -30, -20, 86, 89, 93, -37, -36, 38, 39, 40,
+ 41, 42, 43, 24, 44, 14, -8, 36, 35, 105,
+ -18, 13, 69, 108, 109, -4, -2, 16, 101, 102,
+ 103, 104, 107, 19, -8, -9, -8, -8, -8, 13,
+ 13, -8, -18, -18, -18, 42, 13, 13, 13, 13,
+ 13, 13, -45, -11, -17, -10, 18, -16, -27, -34,
+ 15, 10, -27, 10, -46, -2, -27, -16, -17, -27,
+ -27, -2, -27, -27, -48, -35, -34, 13, 13, -7,
+ -5, 13, -3, -18, -9, -8, -19, 13, -17, -17,
+ 13, -2, 10, -2, 10, -2, -2, -2, -2, -2,
+ -2, -2, -13, -2, -19, 95, -2, -2, 17, -33,
+ 11, -33, 17, 69, -8, -8, -8, -8, -8, -8,
+ -6, -2, 17, -6, 17, -6, 42, -8, -2, -2,
+ -2, -6, -13, -2, -2, 92, 18, -30, 10, -35,
+ -16, -27, -24, 79, -31, 18, -27, -16, -15, -19,
+ -14, -2, 14, 37, 40, -33, -4, 93, -37, -36,
+ 24, 44, -8, 69, 19, -2, 18, 18, -21, 86,
+ 94, -18, 44, 10, -2, -2, -8, -33, 20, 17,
+ 17, -8, -33, -33, -33, 17, -33, -33, -33, 16,
+ -17, -47, 10, -16, 10, 15, 44, -32, 17, -8,
+ -8, -8, -3, 13, 17, -3, -3, -3, -13, -3,
+ -19, -3, -6, -32, -32, -33, -2, -19, -2, -2,
+ -13, -13, -2, -19, -2, -2, -2, 18, 99, -35,
+ 15, -19, 10, -4, 44, 94, 20, -44, 86, 17,
+ 17, 17, 17, -33, 17, 17, -33, 17, -33, -33,
+ 17, 13, -2, -35, -32, 17, -19, -3, -30, -2,
+ -13, -18, -18, -2, -2, 15, -15, -43, -17, 17,
+ 17, 17, 17, 17, 17, -35, -32, -16, 18, -27,
+ -15, -42, -32, -16, -41, -16
+};
+short yydef[] =
+{
+ -2, -2, 1, 2, 32, 29, 87, 88, 28, 44,
+ 35, 0, 0, 0, 0, 34, 22, 173, 0, 76,
+ 77, 174, 176, 0, 93, 0, 0, 0, 144, 0,
+ 0, 0, 0, 155, 0, 0, 161, 0, 0, 166,
+ 0, 0, 181, 182, 183, 95, 130, 131, 89, 90,
+ 33, 0, 0, 23, 0, 128, 0, 0, 111, 0,
+ 116, 0, 0, 0, 0, 0, 0, 125, 26, 9,
+ 0, 0, 82, 0, 105, 106, 0, 85, 86, 0,
+ 0, 0, 19, 20, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 75, 5, 3, 0,
+ 173, 0, 0, 150, 151, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 177, 94, 141, 139, 140, 0,
+ 0, 147, 148, 149, 154, 0, 0, 0, 0, 0,
+ 0, 0, 0, 45, 0, 37, 39, 129, 109, 107,
+ 26, 24, 110, 10, 0, 0, 115, 118, 0, 120,
+ 121, 0, 123, 124, 0, 127, 27, -2, 0, 102,
+ 83, 0, 80, 173, 57, 58, 104, 0, 0, 0,
+ 178, 0, 6, 61, 4, 62, -2, -2, -2, -2,
+ -2, -2, 69, -2, 71, 74, 0, 59, 0, 0,
+ 7, 0, 158, 0, 136, 133, 134, 135, 137, 138,
+ 0, 46, 142, 0, 145, 0, 0, 153, 0, 0,
+ 0, 0, 93, 0, 0, 0, 36, 0, 25, 108,
+ 112, 114, 0, 11, 119, 91, 122, 126, 0, 174,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 56, 0, 0, 0, 40, 41, 0, 179,
+ 0, 73, 0, 8, 79, 78, 132, 0, 175, 143,
+ 146, 152, 0, 0, 0, 165, 0, 0, 0, 96,
+ 0, 0, 12, 117, 92, 26, 0, 21, 97, 99,
+ 100, 101, 81, 0, 84, 0, 50, 51, 52, -2,
+ 54, 48, 0, 184, 42, 0, 60, 72, 47, 0,
+ 93, 93, 0, 0, 0, 0, 0, 38, 0, 0,
+ 26, 0, 98, 0, 0, 0, 103, 0, 180, 156,
+ 157, 159, 160, 0, 164, 167, 0, 168, 0, 0,
+ 172, 0, 0, -2, 17, 0, 55, 49, 0, 0,
+ 93, 0, 0, 0, 0, 26, 0, 0, 0, 162,
+ 163, 169, 170, 171, 0, -2, 15, 18, 43, 113,
+ 0, 0, 13, 16, 0, 14
+};
+short yytok1[] =
+{
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 104, 0, 0,
+ 13, 17, 103, 101, 11, 102, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 94, 15,
+ 0, 0, 0, 93, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 19, 0, 20, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 12, 14, 18
+};
+short yytok2[] =
+{
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 95, 96, 97, 98, 99, 100, 105, 106, 107,
+ 108, 109, 110, 111
+};
+long yytok3[] =
+{
+ 0
+};
+#define YYFLAG -1000
+#define YYERROR goto yyerrlab
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+
+#ifdef yydebug
+#include "y.debug"
+#else
+#define yydebug 0
+char* yytoknames[1]; /* for debugging */
+char* yystates[1]; /* for debugging */
+#endif
+
+/* parser for yacc output */
+
+int yynerrs = 0; /* number of errors */
+int yyerrflag = 0; /* error recovery flag */
+
+extern int fprint(int, char*, ...);
+extern int sprint(char*, char*, ...);
+
+char*
+yytokname(int yyc)
+{
+ static char x[10];
+
+ if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
+ if(yytoknames[yyc-1])
+ return yytoknames[yyc-1];
+ sprintf(x, "<%d>", yyc);
+ return x;
+}
+
+char*
+yystatname(int yys)
+{
+ static char x[10];
+
+ if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
+ if(yystates[yys])
+ return yystates[yys];
+ sprintf(x, "<%d>\n", yys);
+ return x;
+}
+
+long
+yylex1(void)
+{
+ long yychar;
+ long *t3p;
+ int c;
+
+ yychar = yylex();
+ if(yychar <= 0) {
+ c = yytok1[0];
+ goto out;
+ }
+ if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
+ c = yytok1[yychar];
+ goto out;
+ }
+ if(yychar >= YYPRIVATE)
+ if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
+ c = yytok2[yychar-YYPRIVATE];
+ goto out;
+ }
+ for(t3p=yytok3;; t3p+=2) {
+ c = t3p[0];
+ if(c == yychar) {
+ c = t3p[1];
+ goto out;
+ }
+ if(c == 0)
+ break;
+ }
+ c = 0;
+
+out:
+ if(c == 0)
+ c = yytok2[1]; /* unknown char */
+ if(yydebug >= 3)
+ printf("lex %.4lX %s\n", yychar, yytokname(c));
+ return c;
+}
+
+int
+yyparse(void)
+{
+ struct
+ {
+ YYSTYPE yyv;
+ int yys;
+ } yys[YYMAXDEPTH], *yyp, *yypt;
+ short *yyxi;
+ int yyj, yym, yystate, yyn, yyg;
+ YYSTYPE save1, save2;
+ int save3, save4;
+ long yychar;
+
+ save1 = yylval;
+ save2 = yyval;
+ save3 = yynerrs;
+ save4 = yyerrflag;
+
+ yystate = 0;
+ yychar = -1;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yyp = &yys[-1];
+ goto yystack;
+
+ret0:
+ yyn = 0;
+ goto ret;
+
+ret1:
+ yyn = 1;
+ goto ret;
+
+ret:
+ yylval = save1;
+ yyval = save2;
+ yynerrs = save3;
+ yyerrflag = save4;
+ return yyn;
+
+yystack:
+ /* put a state and value onto the stack */
+ if(yydebug >= 4)
+ printf("char %s in %s", yytokname(yychar), yystatname(yystate));
+
+ yyp++;
+ if(yyp >= &yys[YYMAXDEPTH]) {
+ yyerror("yacc stack overflow");
+ goto ret1;
+ }
+ yyp->yys = yystate;
+ yyp->yyv = yyval;
+
+yynewstate:
+ yyn = yypact[yystate];
+ if(yyn <= YYFLAG)
+ goto yydefault; /* simple state */
+ if(yychar < 0)
+ yychar = yylex1();
+ yyn += yychar;
+ if(yyn < 0 || yyn >= YYLAST)
+ goto yydefault;
+ yyn = yyact[yyn];
+ if(yychk[yyn] == yychar) { /* valid shift */
+ yychar = -1;
+ yyval = yylval;
+ yystate = yyn;
+ if(yyerrflag > 0)
+ yyerrflag--;
+ goto yystack;
+ }
+
+yydefault:
+ /* default state action */
+ yyn = yydef[yystate];
+ if(yyn == -2) {
+ if(yychar < 0)
+ yychar = yylex1();
+
+ /* look through exception table */
+ for(yyxi=yyexca;; yyxi+=2)
+ if(yyxi[0] == -1 && yyxi[1] == yystate)
+ break;
+ for(yyxi += 2;; yyxi += 2) {
+ yyn = yyxi[0];
+ if(yyn < 0 || yyn == yychar)
+ break;
+ }
+ yyn = yyxi[1];
+ if(yyn < 0)
+ goto ret0;
+ }
+ if(yyn == 0) {
+ /* error ... attempt to resume parsing */
+ switch(yyerrflag) {
+ case 0: /* brand new error */
+ yyerror("syntax error");
+ if(yydebug >= 1) {
+ printf("%s", yystatname(yystate));
+ printf("saw %s\n", yytokname(yychar));
+ }
+yyerrlab:
+ yynerrs++;
+
+ case 1:
+ case 2: /* incompletely recovered error ... try again */
+ yyerrflag = 3;
+
+ /* find a state where "error" is a legal shift action */
+ while(yyp >= yys) {
+ yyn = yypact[yyp->yys] + YYERRCODE;
+ if(yyn >= 0 && yyn < YYLAST) {
+ yystate = yyact[yyn]; /* simulate a shift of "error" */
+ if(yychk[yystate] == YYERRCODE)
+ goto yystack;
+ }
+
+ /* the current yyp has no shift onn "error", pop stack */
+ if(yydebug >= 2)
+ printf("error recovery pops state %d, uncovers %d\n",
+ yyp->yys, (yyp-1)->yys );
+ yyp--;
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1;
+
+ case 3: /* no shift yet; clobber input char */
+ if(yydebug >= YYEOFCODE)
+ printf("error recovery discards %s\n", yytokname(yychar));
+ if(yychar == YYEOFCODE)
+ goto ret1;
+ yychar = -1;
+ goto yynewstate; /* try again in the same state */
+ }
+ }
+
+ /* reduction by production yyn */
+ if(yydebug >= 2)
+ printf("reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+ yypt = yyp;
+ yyp -= yyr2[yyn];
+ yyval = (yyp+1)->yyv;
+ yym = yyn;
+
+ /* consult goto table to find next state */
+ yyn = yyr1[yyn];
+ yyg = yypgo[yyn];
+ yyj = yyg + yyp->yys + 1;
+
+ if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+ yystate = yyact[yyg];
+ switch(yym) {
+
+case 1:
+#line 98 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (errorflag==0)
+ winner = (Node *)stat3(PROGRAM, beginloc, yypt[-0].yyv.p, endloc); } break;
+case 2:
+#line 100 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyclearin; bracecheck(); SYNTAX("bailing out"); } break;
+case 13:
+#line 124 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 14:
+#line 125 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat4(FOR, yypt[-9].yyv.p, notnull(yypt[-6].yyv.p), yypt[-3].yyv.p, yypt[-0].yyv.p); } break;
+case 15:
+#line 126 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 16:
+#line 127 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat4(FOR, yypt[-7].yyv.p, NIL, yypt[-3].yyv.p, yypt[-0].yyv.p); } break;
+case 17:
+#line 128 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 18:
+#line 129 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat3(IN, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-0].yyv.p); } break;
+case 19:
+#line 133 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ setfname(yypt[-0].yyv.cp); } break;
+case 20:
+#line 134 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ setfname(yypt[-0].yyv.cp); } break;
+case 21:
+#line 138 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = notnull(yypt[-1].yyv.p); } break;
+case 26:
+#line 150 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.i = 0; } break;
+case 28:
+#line 155 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.i = 0; } break;
+case 30:
+#line 161 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = 0; } break;
+case 32:
+#line 166 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = 0; } break;
+case 33:
+#line 167 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 34:
+#line 171 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = notnull(yypt[-0].yyv.p); } break;
+case 35:
+#line 175 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(PASTAT, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break;
+case 36:
+#line 176 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(PASTAT, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 37:
+#line 177 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = pa2stat(yypt[-2].yyv.p, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break;
+case 38:
+#line 178 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = pa2stat(yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 39:
+#line 179 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(PASTAT, NIL, yypt[-1].yyv.p); } break;
+case 40:
+#line 181 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ beginloc = linkum(beginloc, yypt[-1].yyv.p); yyval.p = 0; } break;
+case 41:
+#line 183 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ endloc = linkum(endloc, yypt[-1].yyv.p); yyval.p = 0; } break;
+case 42:
+#line 184 "/n/bopp/v7/bwk/awk/awkgram.y"
+{infunc++;} break;
+case 43:
+#line 185 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ infunc--; curfname=0; defn((Cell *)yypt[-7].yyv.p, yypt[-5].yyv.p, yypt[-1].yyv.p); yyval.p = 0; } break;
+case 45:
+#line 190 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 47:
+#line 195 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 48:
+#line 199 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 49:
+#line 201 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 50:
+#line 203 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 51:
+#line 205 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 52:
+#line 206 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break;
+case 53:
+#line 208 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-0].yyv.p))
+ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0));
+ else
+ yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 54:
+#line 212 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 55:
+#line 213 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 56:
+#line 214 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 59:
+#line 220 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 60:
+#line 222 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 61:
+#line 224 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 62:
+#line 226 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break;
+case 63:
+#line 227 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 64:
+#line 228 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 65:
+#line 229 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 66:
+#line 230 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 67:
+#line 231 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 68:
+#line 232 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 69:
+#line 233 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break;
+case 70:
+#line 235 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-0].yyv.p))
+ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0));
+ else
+ yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 71:
+#line 239 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 72:
+#line 240 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break;
+case 73:
+#line 241 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("cmd | getline is unsafe");
+ else yyval.p = op3(GETLINE, yypt[-0].yyv.p, itonp(yypt[-2].yyv.i), yypt[-3].yyv.p); } break;
+case 74:
+#line 244 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("cmd | getline is unsafe");
+ else yyval.p = op3(GETLINE, (Node*)0, itonp(yypt[-1].yyv.i), yypt[-2].yyv.p); } break;
+case 75:
+#line 247 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 78:
+#line 253 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 79:
+#line 254 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 81:
+#line 259 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 82:
+#line 263 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = rectonode(); } break;
+case 84:
+#line 265 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 93:
+#line 282 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(MATCH, NIL, rectonode(), (Node*)makedfa(yypt[-0].yyv.s, 0)); } break;
+case 94:
+#line 283 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break;
+case 95:
+#line 287 "/n/bopp/v7/bwk/awk/awkgram.y"
+{startreg();} break;
+case 96:
+#line 287 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.s = yypt[-1].yyv.s; } break;
+case 99:
+#line 295 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("print | is unsafe");
+ else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 100:
+#line 298 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("print >> is unsafe");
+ else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 101:
+#line 301 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ if (safe) SYNTAX("print > is unsafe");
+ else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 102:
+#line 304 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat3(yypt[-1].yyv.i, yypt[-0].yyv.p, NIL, NIL); } break;
+case 103:
+#line 305 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(DELETE, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break;
+case 104:
+#line 306 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(DELETE, makearr(yypt[-0].yyv.p), 0); } break;
+case 105:
+#line 307 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = exptostat(yypt[-0].yyv.p); } break;
+case 106:
+#line 308 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyclearin; SYNTAX("illegal statement"); } break;
+case 109:
+#line 317 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (!inloop) SYNTAX("break illegal outside of loops");
+ yyval.p = stat1(BREAK, NIL); } break;
+case 110:
+#line 319 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (!inloop) SYNTAX("continue illegal outside of loops");
+ yyval.p = stat1(CONTINUE, NIL); } break;
+case 111:
+#line 321 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 112:
+#line 321 "/n/bopp/v7/bwk/awk/awkgram.y"
+{--inloop;} break;
+case 113:
+#line 322 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat2(DO, yypt[-6].yyv.p, notnull(yypt[-2].yyv.p)); } break;
+case 114:
+#line 323 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(EXIT, yypt[-1].yyv.p); } break;
+case 115:
+#line 324 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(EXIT, NIL); } break;
+case 117:
+#line 326 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat3(IF, yypt[-3].yyv.p, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 118:
+#line 327 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat3(IF, yypt[-1].yyv.p, yypt[-0].yyv.p, NIL); } break;
+case 119:
+#line 328 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 120:
+#line 329 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (infunc)
+ SYNTAX("next is illegal inside a function");
+ yyval.p = stat1(NEXT, NIL); } break;
+case 121:
+#line 332 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (infunc)
+ SYNTAX("nextfile is illegal inside a function");
+ yyval.p = stat1(NEXTFILE, NIL); } break;
+case 122:
+#line 335 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(RETURN, yypt[-1].yyv.p); } break;
+case 123:
+#line 336 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = stat1(RETURN, NIL); } break;
+case 125:
+#line 338 "/n/bopp/v7/bwk/awk/awkgram.y"
+{inloop++;} break;
+case 126:
+#line 338 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ --inloop; yyval.p = stat2(WHILE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 127:
+#line 339 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = 0; } break;
+case 129:
+#line 344 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = linkum(yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 132:
+#line 352 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(DIVEQ, yypt[-3].yyv.p, yypt[-0].yyv.p); } break;
+case 133:
+#line 353 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(ADD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 134:
+#line 354 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(MINUS, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 135:
+#line 355 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(MULT, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 136:
+#line 356 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(DIVIDE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 137:
+#line 357 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(MOD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 138:
+#line 358 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(POWER, yypt[-2].yyv.p, yypt[-0].yyv.p); } break;
+case 139:
+#line 359 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(UMINUS, yypt[-0].yyv.p); } break;
+case 140:
+#line 360 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-0].yyv.p; } break;
+case 141:
+#line 361 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break;
+case 142:
+#line 362 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BLTIN, itonp(yypt[-2].yyv.i), rectonode()); } break;
+case 143:
+#line 363 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BLTIN, itonp(yypt[-3].yyv.i), yypt[-1].yyv.p); } break;
+case 144:
+#line 364 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(BLTIN, itonp(yypt[-0].yyv.i), rectonode()); } break;
+case 145:
+#line 365 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CALL, celltonode(yypt[-2].yyv.cp,CVAR), NIL); } break;
+case 146:
+#line 366 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(CALL, celltonode(yypt[-3].yyv.cp,CVAR), yypt[-1].yyv.p); } break;
+case 147:
+#line 367 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(CLOSE, yypt[-0].yyv.p); } break;
+case 148:
+#line 368 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(PREDECR, yypt[-0].yyv.p); } break;
+case 149:
+#line 369 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(PREINCR, yypt[-0].yyv.p); } break;
+case 150:
+#line 370 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(POSTDECR, yypt[-1].yyv.p); } break;
+case 151:
+#line 371 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(POSTINCR, yypt[-1].yyv.p); } break;
+case 152:
+#line 372 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 153:
+#line 373 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, NIL, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break;
+case 154:
+#line 374 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, yypt[-0].yyv.p, NIL, NIL); } break;
+case 155:
+#line 375 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(GETLINE, NIL, NIL, NIL); } break;
+case 156:
+#line 377 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(INDEX, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 157:
+#line 379 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ SYNTAX("index() doesn't permit regular expressions");
+ yyval.p = op2(INDEX, yypt[-3].yyv.p, (Node*)yypt[-1].yyv.s); } break;
+case 158:
+#line 381 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = yypt[-1].yyv.p; } break;
+case 159:
+#line 383 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(yypt[-1].yyv.s, 1)); } break;
+case 160:
+#line 385 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-1].yyv.p))
+ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(strnode(yypt[-1].yyv.p), 1));
+ else
+ yyval.p = op3(MATCHFCN, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 161:
+#line 389 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break;
+case 162:
+#line 391 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p, (Node*)STRING); } break;
+case 163:
+#line 393 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), (Node*)makedfa(yypt[-1].yyv.s, 1), (Node *)REGEXPR); } break;
+case 164:
+#line 395 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(SPLIT, yypt[-3].yyv.p, makearr(yypt[-1].yyv.p), NIL, (Node*)STRING); } break;
+case 165:
+#line 396 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(yypt[-3].yyv.i, yypt[-1].yyv.p); } break;
+case 166:
+#line 397 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break;
+case 167:
+#line 399 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(yypt[-3].yyv.s, 1), yypt[-1].yyv.p, rectonode()); } break;
+case 168:
+#line 401 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-3].yyv.p))
+ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-3].yyv.p), 1), yypt[-1].yyv.p, rectonode());
+ else
+ yyval.p = op4(yypt[-5].yyv.i, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p, rectonode()); } break;
+case 169:
+#line 406 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(yypt[-5].yyv.s, 1), yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 170:
+#line 408 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ if (constnode(yypt[-5].yyv.p))
+ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-5].yyv.p), 1), yypt[-3].yyv.p, yypt[-1].yyv.p);
+ else
+ yyval.p = op4(yypt[-7].yyv.i, (Node *)1, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 171:
+#line 413 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(SUBSTR, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break;
+case 172:
+#line 415 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op3(SUBSTR, yypt[-3].yyv.p, yypt[-1].yyv.p, NIL); } break;
+case 175:
+#line 421 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op2(ARRAY, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break;
+case 176:
+#line 422 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(INDIRECT, celltonode(yypt[-0].yyv.cp, CVAR)); } break;
+case 177:
+#line 423 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(INDIRECT, yypt[-0].yyv.p); } break;
+case 178:
+#line 427 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ arglist = yyval.p = 0; } break;
+case 179:
+#line 428 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ arglist = yyval.p = celltonode(yypt[-0].yyv.cp,CVAR); } break;
+case 180:
+#line 429 "/n/bopp/v7/bwk/awk/awkgram.y"
+{
+ checkdup(yypt[-2].yyv.p, yypt[-0].yyv.cp);
+ arglist = yyval.p = linkum(yypt[-2].yyv.p,celltonode(yypt[-0].yyv.cp,CVAR)); } break;
+case 181:
+#line 435 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = celltonode(yypt[-0].yyv.cp, CVAR); } break;
+case 182:
+#line 436 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(ARG, itonp(yypt[-0].yyv.i)); } break;
+case 183:
+#line 437 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = op1(VARNF, (Node *) yypt[-0].yyv.cp); } break;
+case 184:
+#line 442 "/n/bopp/v7/bwk/awk/awkgram.y"
+{ yyval.p = notnull(yypt[-1].yyv.p); } break;
+ }
+ goto yystack; /* stack new state and value */
+}
diff --git a/utils/awk/ytabh.bak b/utils/awk/ytabh.bak
new file mode 100644
index 00000000..d18ddfdb
--- /dev/null
+++ b/utils/awk/ytabh.bak
@@ -0,0 +1,100 @@
+
+typedef union {
+ Node *p;
+ Cell *cp;
+ int i;
+ char *s;
+} YYSTYPE;
+extern YYSTYPE yylval;
+#define FIRSTTOKEN 57346
+#define PROGRAM 57347
+#define PASTAT 57348
+#define PASTAT2 57349
+#define XBEGIN 57350
+#define XEND 57351
+#define NL 57352
+#define ARRAY 57353
+#define MATCH 57354
+#define NOTMATCH 57355
+#define MATCHOP 57356
+#define FINAL 57357
+#define DOT 57358
+#define ALL 57359
+#define CCL 57360
+#define NCCL 57361
+#define CHAR 57362
+#define OR 57363
+#define STAR 57364
+#define QUEST 57365
+#define PLUS 57366
+#define AND 57367
+#define BOR 57368
+#define APPEND 57369
+#define EQ 57370
+#define GE 57371
+#define GT 57372
+#define LE 57373
+#define LT 57374
+#define NE 57375
+#define IN 57376
+#define ARG 57377
+#define BLTIN 57378
+#define BREAK 57379
+#define CLOSE 57380
+#define CONTINUE 57381
+#define DELETE 57382
+#define DO 57383
+#define EXIT 57384
+#define FOR 57385
+#define FUNC 57386
+#define SUB 57387
+#define GSUB 57388
+#define IF 57389
+#define INDEX 57390
+#define LSUBSTR 57391
+#define MATCHFCN 57392
+#define NEXT 57393
+#define NEXTFILE 57394
+#define ADD 57395
+#define MINUS 57396
+#define MULT 57397
+#define DIVIDE 57398
+#define MOD 57399
+#define ASSIGN 57400
+#define ASGNOP 57401
+#define ADDEQ 57402
+#define SUBEQ 57403
+#define MULTEQ 57404
+#define DIVEQ 57405
+#define MODEQ 57406
+#define POWEQ 57407
+#define PRINT 57408
+#define PRINTF 57409
+#define SPRINTF 57410
+#define ELSE 57411
+#define INTEST 57412
+#define CONDEXPR 57413
+#define POSTINCR 57414
+#define PREINCR 57415
+#define POSTDECR 57416
+#define PREDECR 57417
+#define VAR 57418
+#define IVAR 57419
+#define VARNF 57420
+#define CALL 57421
+#define NUMBER 57422
+#define STRING 57423
+#define REGEXPR 57424
+#define GETLINE 57425
+#define RETURN 57426
+#define SPLIT 57427
+#define SUBSTR 57428
+#define WHILE 57429
+#define CAT 57430
+#define NOT 57431
+#define UMINUS 57432
+#define POWER 57433
+#define DECR 57434
+#define INCR 57435
+#define INDIRECT 57436
+#define LASTTOKEN 57437
diff --git a/utils/c2l/Nt.c b/utils/c2l/Nt.c
new file mode 100644
index 00000000..bf36e0dd
--- /dev/null
+++ b/utils/c2l/Nt.c
@@ -0,0 +1,131 @@
+#include <windows.h>
+#include <lib9.h>
+
+#define Windows (1<<2) /* hack - can't include cc.h because of clashes */
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ fprint(2, "mywait called\n");
+ abort();
+ return 0;
+}
+
+int
+mydup(int f1, int f2)
+{
+ int ok;
+
+ ok = _dup2(f1, f2);
+ if(ok < 0)
+ return -1;
+ return f2;
+/*
+ fprint(2, "mydup called\n");
+ abort();
+ return 0;
+*/
+}
+
+int
+mypipe(int *fd)
+{
+ fprint(2, "mypipe called\n");
+ abort();
+ return 0;
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Windows;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getcwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ fprint(2, "myexec called\n");
+ abort();
+ return 0;
+}
+
+int
+myfork(void)
+{
+ fprint(2, "myfork called\n");
+ abort();
+ return 0;
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(uint n)
+{
+ return mysbrk(n);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ return mysbrk(m*n);
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+void
+free(void *p)
+{
+}
diff --git a/utils/c2l/Plan9.c b/utils/c2l/Plan9.c
new file mode 100644
index 00000000..853df40b
--- /dev/null
+++ b/utils/c2l/Plan9.c
@@ -0,0 +1,108 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ int p;
+ Waitmsg *w;
+
+ if((w = wait()) == nil)
+ return -1;
+ else{
+ p = w->pid;
+ *s = 0;
+ if(w->msg[0])
+ *s = 1;
+ free(w);
+ return p;
+ }
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return exec(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/c2l/Posix.c b/utils/c2l/Posix.c
new file mode 100644
index 00000000..065f1e20
--- /dev/null
+++ b/utils/c2l/Posix.c
@@ -0,0 +1,91 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ return wait(s);
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup2(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Unix;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return (char*)getcwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return execvp(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(size_t n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void *p)
+{
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
diff --git a/utils/c2l/acid.c b/utils/c2l/acid.c
new file mode 100644
index 00000000..c31e600f
--- /dev/null
+++ b/utils/c2l/acid.c
@@ -0,0 +1,13 @@
+#include "cc.h"
+
+void
+acidtype(Type *t)
+{
+ USED(t);
+}
+
+void
+acidvar(Sym *s)
+{
+ USED(s);
+}
diff --git a/utils/c2l/bits.c b/utils/c2l/bits.c
new file mode 100644
index 00000000..a22ba512
--- /dev/null
+++ b/utils/c2l/bits.c
@@ -0,0 +1,89 @@
+#include "cc.h"
+
+Bits
+bor(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] | b.b[i];
+ return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] & b.b[i];
+ return c;
+}
+
+/*
+Bits
+bnot(Bits a)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = ~a.b[i];
+ return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a->b[i])
+ return 1;
+ return 0;
+}
+
+int
+beq(Bits a, Bits b)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a.b[i] != b.b[i])
+ return 0;
+ return 1;
+}
+
+int
+bnum(Bits a)
+{
+ int i;
+ long b;
+
+ for(i=0; i<BITS; i++)
+ if(b = a.b[i])
+ return 32*i + bitno(b);
+ diag(Z, "bad in bnum");
+ return 0;
+}
+
+Bits
+blsh(uint n)
+{
+ Bits c;
+
+ c = zbits;
+ c.b[n/32] = 1L << (n%32);
+ return c;
+}
+
+int
+bset(Bits a, uint n)
+{
+ if(a.b[n/32] & (1L << (n%32)))
+ return 1;
+ return 0;
+}
diff --git a/utils/c2l/c2l.c b/utils/c2l/c2l.c
new file mode 100644
index 00000000..f870d640
--- /dev/null
+++ b/utils/c2l/c2l.c
@@ -0,0 +1,5118 @@
+#define EXTERN
+
+#include "cc.h"
+
+/*
+ * locals, parameters, globals etc of the same name should work ok without having
+ * to duplicate Syms because the details are on the containing Nodes
+ */
+
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_FLOAT 4
+#define SZ_IND 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+
+char buf[128], mbuf[128];
+static Sym *sysop, *bioop, *libcop;
+static int again;
+
+#define INFINITY 0x7fffffff
+#define STAR 0x80
+#define RET 0x80
+
+#define LARR (-1729)
+
+static void swalk(void);
+static int isdec(Node*);
+static int isconst(Node*, vlong);
+static int cktype(Node*, Node*, int, int);
+static void addnode(int, Node*);
+static int argpos(Node*, Node*);
+static void setdec(Sym*, Type*);
+static Type* tcp(Type*);
+static int isadt(Type*);
+static void aargs(Node*);
+static int iteq(Type*, Type*);
+static Node* arg(Node*, int);
+static void etgen2(Sym*);
+static Node* ckneg(Node*);
+static Sym* suename(Type*);
+static int isnil(Node*);
+static void sliceasgn(Node*);
+static Node* lastn(Node*);
+static char* hasm(void);
+static void prn(Node*, int);
+static int isfn(Type*);
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
+
+enum{
+ TCFD = 1,
+ TCFC = 2,
+ TCPC = 4,
+ TCAR = 8,
+ TCIN = 16,
+ TCGEN = TCFD|TCFC|TCPC|TCAR,
+ TCALL = TCFD|TCFC|TCPC|TCAR|TCIN,
+};
+
+enum{
+ SGLOB,
+ SPARM,
+ SAUTO,
+};
+
+typedef struct Scope Scope;
+
+struct Scope{
+ Node *n;
+ int k;
+ Scope *nxt;
+};
+
+static void
+prtyp(Type *t, char *s, int nl)
+{
+ print("%s: ", s);
+ if(t == T){
+ print("nil");
+ if(nl)
+ print("\n");
+ return;
+ }
+ while(t != T){
+ print("%d(%d)[%x] ", t->etype, t->mark, (int)t);
+ if(isadt(t))
+ break;
+ t = t->link;
+ }
+ if(nl)
+ print("\n");
+}
+
+static Node*
+func(Node *n)
+{
+ while(n != Z && n->op != OFUNC)
+ n = n->left;
+ return n;
+}
+
+static void
+setmain(Node *n)
+{
+ inmain |= n->left->op == ONAME && strcmp(n->left->sym->name, "main") == 0;
+}
+
+static Node*
+protoname(Node *n)
+{
+ do
+ n = n->left;
+ while(n != Z && n->op != ONAME && n->op != ODOTDOT);
+ return n;
+}
+
+static Type*
+prototype(Node *n, Type *t)
+{
+ for( ; n != Z ; n = n->left){
+ switch(n->op){
+ case OARRAY:
+ t = typ(TARRAY, t);
+ t->width = 0;
+ break;
+ case OIND:
+ t = typ(TIND, t);
+ break;
+ case OFUNC:
+ t = typ(TFUNC, t);
+ t->down = fnproto(n);
+ break;
+ }
+ }
+ return t;
+}
+
+static Scope *scopes, *freescopes;
+
+static void
+pushdcl(Node *n, int c)
+{
+ Sym *s;
+
+ if(passes){
+ s = n->sym;
+ push1(s);
+ if(c != CAUTO || s->class != CSTATIC)
+ s->class = c;
+ s->type = n->type;
+ }
+}
+
+static void
+pushparams(Node *n)
+{
+ if(n == Z)
+ return;
+ if(passes){
+ if(n->op == OLIST){
+ pushparams(n->left);
+ pushparams(n->right);
+ }
+ else if(n->op == OPROTO){
+ n = protoname(n);
+ if(n != Z && n->op == ONAME)
+ pushdcl(n, CPARAM);
+ }
+ else if(n->op == ONAME){
+ addnode(OPROTO, n);
+ pushdcl(n, CPARAM);
+ }
+ else if(n->op != ODOTDOT)
+ diag(Z, "bad op in pushparams");
+ }
+}
+
+static void
+pushscope(Node *n, int k)
+{
+ Scope *s;
+
+ if(freescopes != nil){
+ s = freescopes;
+ freescopes = freescopes->nxt;
+ }
+ else
+ s = (Scope*)malloc(sizeof(Scope));
+ s->n = n;
+ s->k = k;
+ s->nxt = scopes;
+ scopes = s;
+ if(passes && (k == SPARM || k == SAUTO))
+ markdcl();
+ if(k == SPARM)
+ pushparams(n->right);
+}
+
+static void
+popscope(void)
+{
+ int k;
+ Scope *s;
+
+ s = scopes;
+ k = s->k;
+ scopes = scopes->nxt;
+ s->nxt = freescopes;
+ freescopes = s;
+ if(passes && (k == SPARM || k == SAUTO))
+ revertdcl();
+}
+
+static Node*
+curfn(void)
+{
+ Scope *s;
+
+ for(s = scopes; s != nil; s = s->nxt)
+ if(s->k == SPARM)
+ return s->n;
+ return Z;
+}
+
+static void
+marktype(Type *t, int tc)
+{
+ t->mark = tc;
+}
+
+static int
+marked(Type *t)
+{
+ return t == T ? 0 : t->mark;
+}
+
+static Sym*
+decsym(Node *n)
+{
+ if(n == Z)
+ return S;
+ if(n->op == OFUNC){
+ if(n->left->op == ONAME)
+ return n->left->sym;
+ return S;
+ }
+ if(n->op == ODAS)
+ return n->left->sym;
+ return n->sym;
+}
+
+static void
+trep(Type *t1, Type *t)
+{
+ int l;
+ Sym *s;
+ Type *t2;
+
+ if(t1 != T){
+ l = t1->lineno;
+ s = t1->sym;
+ t2 = t1->down;
+ *t1 = *t;
+ t1->down = t2;
+ t1->sym = s;
+ t1->lineno = l;
+ }
+}
+
+static void
+tind(Node *n)
+{
+ if(n == Z)
+ return;
+ n = protoname(n);
+ if(n != Z && n->type != T){
+ n->type = tcp(n->type->link);
+ marktype(n->type, TCIN);
+ }
+}
+
+static void
+tcon(Node *n, Type *t)
+{
+ Type *tt;
+
+ if(n->garb)
+ return;
+ n->garb = 1;
+ again = 1;
+ switch(n->op){
+ case OCONST:
+ if(t->mark == TCFD && !isnil(n))
+ addnode(OFILDES, n);
+ n->type = t;
+ break;
+ case OCAST:
+ tcon(n->left, t);
+ *n = *n->left;
+ n->type = t;
+ break;
+ case ONAME:
+ n->sym->type = t;
+ n->type = t;
+ setdec(n->sym, t);
+ break;
+ case ODOT:
+ case ODOTIND:
+ trep(n->type, t);
+ n->type = t;
+ break;
+ case OARRIND:
+ tt = n->left->type;
+ if(tt != T)
+ tt->link = t;
+ n->type = t;
+ break;
+ case OFUNC:
+ n->left->type->link = t;
+ if(n->left->op == ONAME)
+ n->left->sym->type->link = t;
+ n->type = t;
+ break;
+ }
+}
+
+static Node*
+retval(Node *n)
+{
+ int i;
+ Type *t;
+ Node *a, *l, *cf;
+
+ cf = curfn();
+ t = cf->left->type->link;
+ if(t->mark&(TCPC|TCFC) && (n == Z || !(n->type->mark&(TCPC|TCFC)))){
+ if(n == Z)
+ n = new1(ORETURN, Z, Z);
+ l = n->left;
+ for(i = 0; ; i++){
+ a = arg(cf->right, i);
+ if(a == Z)
+ break;
+ a = protoname(a);
+ if(a == Z || a->op != ONAME)
+ break;
+ if(a->type->mark == TCIN){
+ if(l == Z)
+ l = ncopy(a);
+ else
+ l = new1(OTUPLE, l, ncopy(a));
+ }
+ }
+ n->left = l;
+ n->type = l->type = t;
+ }
+ return n;
+}
+
+static void
+sube(Node *n)
+{
+ Node *l, *r, *nn;
+ Type *tt;
+ static Node *gn;
+ int p;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op){
+ default:
+ sube(l);
+ sube(r);
+ break;
+ case OIND:
+ if(l == Z)
+ return;
+ tt = l->type;
+ sube(l);
+ if(cktype(l, n, TCIN, 0) && iteq(tt, l->type))
+ *n = *n->left;
+ break;
+ case OARRIND:
+ tt = l->type;
+ sube(l);
+ sube(r);
+ if(!isconst(r, 0))
+ break;
+ if(cktype(l, n, TCIN, 0) && iteq(tt, l->type))
+ *n = *n->left;
+ break;
+ case ONAME:
+ if(cktype(n, n, TCALL, 0))
+ setdec(n->sym, n->type);
+ break;
+ case OCAST:
+ sube(l);
+ if(cktype(l, n, TCALL, 0))
+ n->type = l->type;
+ break;
+ case OPROTO:
+ sube(l);
+ sube(r);
+ nn = protoname(n);
+ if(nn != Z && cktype(nn, n, TCALL, 0)){
+ n->type = nn->type;
+ p = argpos(n, gn->right);
+ for(tt = gn->left->type->down; tt != T && p >= 0; tt = tt->down){
+ if(p == 0){
+ trep(tt, nn->type);
+ break;
+ }
+ --p;
+ }
+ }
+ break;
+ case OFUNC:
+ if(n->kind == KEXP)
+ aargs(n);
+ if(n->left->op == ONAME)
+ gn = n;
+ sube(l);
+ sube(r);
+ if(l != Z && cktype(n, n, TCGEN, 0))
+ l->type->link = n->type;
+ break;
+ case OAS:
+ sube(l);
+ sube(r);
+ if(r->op == ORETV){
+ n->left = new1(OTUPLE, l, r->right);
+ n->right = r->left;
+ n->left->type = n->type;
+ break;
+ }
+ if(cktype(r, n, TCGEN, 0)){
+ tcon(l, r->type);
+ n->type = r->type;
+ }
+ if(cktype(l, n, TCGEN, 1)){
+ tcon(r, l->type);
+ n->type = l->type;
+ }
+ break;
+ case OLT:
+ case OGE:
+ sube(l);
+ sube(r);
+ if(cktype(l, n, TCFD, 0) && isconst(r, 0)){
+ n->op = n->op == OLT ? OEQ : ONE;
+ r->op = ONIL;
+ r->type = l->type;
+ }
+ break;
+ case OGT:
+ case OLE:
+ sube(l);
+ sube(r);
+ if(cktype(r, n, TCFD, 0) && isconst(l, 0)){
+ n->op = n->op == OGT ? OEQ : ONE;
+ l->op = ONIL;
+ l->type = r->type;
+ }
+ break;
+ }
+}
+
+static void
+subs(Node *n, int blk, int aut)
+{
+ Node *l, *r;
+
+ if(n == Z)
+ return;
+ if(blk)
+ pushscope(n, SAUTO);
+ nearln = n->lineno;
+ l = n->left;
+ r = n->right;
+ switch(n->op){
+ default:
+ sube(n);
+ break;
+ case ONAME:
+ if(aut && n->kind != KEXP)
+ pushdcl(n, CAUTO);
+ if(cktype(n, n, TCALL, 0))
+ setdec(n->sym, n->type);
+ break;
+ case ODAS:
+ if(aut)
+ pushdcl(l, CAUTO);
+ subs(l, 0, aut);
+ if(cktype(l, n, TCALL, 0))
+ tcon(r, l->type);
+ break;
+ case OSBREAK:
+ case ONUL:
+ case OLABEL:
+ case OGOTO:
+ case OCONTINUE:
+ case OBREAK:
+ case OSET:
+ case OUSED:
+ break;
+ case OBLK:
+ subs(l, 1, aut);
+ break;
+ case OCASE:
+ subs(r, 1, aut);
+ break;
+ case OLIST:
+ subs(l, 0, aut);
+ subs(r, 0, aut);
+ break;
+ case ORETURN:
+ sube(l);
+ if(l != Z && cktype(l, n, TCGEN, 0)){
+ n->type = l->type;
+ tcon(curfn(), l->type);
+ }
+ retval(n);
+ break;
+ case OSWITCH:
+ case OWHILE:
+ case ODWHILE:
+ sube(l);
+ subs(r, 1, aut);
+ break;
+ case OIF:
+ sube(l);
+ subs(r->left, 1, aut);
+ subs(r->right, 1, aut);
+ break;
+ case OFOR:
+ sube(l->left);
+ sube(l->right->left);
+ sube(l->right->right);
+ subs(r, 1, aut);
+ break;
+ }
+ if(blk)
+ popscope();
+}
+
+static Node*
+finddec0(Sym *s, Node *n)
+{
+ Node *nn;
+
+ if(n == Z)
+ return ZZ;
+ switch(n->op){
+ case OLIST:
+ nn = finddec0(s, n->left);
+ if(nn != Z)
+ return nn;
+ return finddec0(s, n->right);
+ case OFUNC:
+ if(n->op != KEXP){
+ if(s == decsym(n))
+ return n;
+ return finddec0(s, n->right);
+ }
+ else
+ return ZZ;
+ case OPROTO:
+ case OIND:
+ case OARRAY:
+ return finddec0(s, n->left);
+ case ODOTDOT:
+ return ZZ;
+ case ONOOP:
+ case OPUSH:
+ case OPOP:
+ case OCODE:
+ case ODECE:
+ case ODECT:
+ return finddec0(s, n->right);
+ case ODECV:
+ case ODECF:
+ if(s == decsym(n->left) && !isfn(n->left->type))
+ return n->left;
+ return finddec0(s, n->right);
+ }
+ if(isdec(n)){
+ if(s == decsym(n) && !isfn(n->type))
+ return n;
+ return Z;
+ }
+ return ZZ;
+}
+
+static Node*
+finddec(Sym *s, int g)
+{
+ Node *n;
+ Scope *sc;
+
+ for(sc = scopes; sc != nil; sc = sc->nxt){
+ if(!g || sc->k == SGLOB){
+ n = finddec0(s, sc->n);
+ if(n != Z && n != ZZ)
+ return n;
+ }
+ }
+ return Z;
+}
+
+static void
+setdec(Sym *s, Type *t)
+{
+ Node *n;
+
+ if((n = finddec(s, 0)) != Z){
+ n->type = t;
+ if(n->op == ODAS){
+ n = n->left;
+ n->type = t;
+ }
+ n->sym->type = t;
+ }
+}
+
+typedef struct Syml Syml;
+
+struct Syml{
+ Sym *sym;
+ Syml *nxt;
+};
+
+typedef struct Symq Symq;
+
+struct Symq{
+ Syml *f;
+ Syml *r;
+};
+
+typedef struct Modl Modl;
+
+struct Modl{
+ char *mod;
+ int ld;
+ Modl *nxt;
+};
+
+static void
+prn(Node *n, int i)
+{
+ int j;
+
+ for(j = 0; j < i; j++)
+ print("\t");
+ if(n == Z){
+ print("Z\n");
+ return;
+ }
+ print("%s", onames[n->op]);
+ if(n->blk)
+ print(" block");
+ if(n->type == T)
+ print(" T");
+ else
+ print(" %s", tnames[n->type->etype]);
+ if(n->op == OCONST)
+ print(" %d", (int)n->vconst);
+ else if(n->op == OSTRING)
+ print(" %s", n->cstring);
+ else if(n->op == ONAME)
+ print(" %s", n->sym->name);
+ print("\n");
+ if(n->op != OLIST)
+ i++;
+ prn(n->left, i);
+ prn(n->right, i);
+}
+
+static int
+isbigv(vlong v)
+{
+ return v > 0xffffffff;
+}
+
+static int
+islbigv(vlong v)
+{
+ return v > 0x7fffffff || v < -0x7fffffff;
+}
+
+static int
+isuintv(vlong v)
+{
+ return !isbigv(v) && (v&0x80000000) != 0;
+}
+
+static int
+isadt(Type *t)
+{
+ return t != T && (t->etype == TSTRUCT || t->etype == TUNION);
+}
+
+static int
+isreal(Type *t)
+{
+ return t != T && (t->etype == TDOUBLE || t->etype == TFLOAT);
+}
+
+static int
+isbyte(Type *t)
+{
+ return t != T && (t->etype == TCHAR || t->etype == TUCHAR);
+}
+
+static int
+isshort(Type *t)
+{
+ return t != T && (t->etype == TSHORT || t->etype == TUSHORT);
+}
+
+static int
+isint(Type *t)
+{
+ return t != T && (t->etype == TINT || t->etype == TUINT);
+}
+
+static int
+islong(Type *t)
+{
+ return t != T && (t->etype == TLONG || t->etype == TULONG);
+}
+
+static int
+isbig(Type *t)
+{
+ return t != T && (t->etype == TVLONG || t->etype == TUVLONG);
+}
+
+static int
+isinteger(Type *t)
+{
+ return isbyte(t) || isshort(t) || isint(t) || islong(t) || isbig(t);
+}
+
+static int
+isptr(Type *t)
+{
+ return t != T && (t->etype == TIND || t->etype == TARRAY || t->etype == TFUNC);
+}
+
+static int
+isscalar(Type *t)
+{
+ return t != T && !isadt(t) && t->etype != TTUPLE;
+}
+
+static int
+isvoid(Type *t)
+{
+ return t == T || t->etype == TVOID;
+}
+
+static int
+isnum(Type *t)
+{
+ return t != T && isscalar(t) && !isptr(t) && !isvoid(t);
+}
+
+static int
+isarray(Type *t)
+{
+ return t != T && (t->etype == TARRAY || (t->etype == TIND && !isadt(t->link)));
+}
+
+static int
+isstr(Type *t)
+{
+ return t != T && (t->etype == TSTRING || isarray(t) && isbyte(t->link));
+}
+
+static int
+isfn(Type *t)
+{
+ return t != T && t->etype == TFUNC;
+}
+
+static int
+iscastable(Type *t, Type *tt)
+{
+ return t != T && (!isptr(t) || isarray(t) && isbyte(t->link) && isstr(tt));
+}
+
+static int
+isname(Node *n)
+{
+ return n->op == ONAME;
+}
+
+static int
+isstring(Node *n)
+{
+ return n->op == OSTRING || n->op == OLSTRING || n->op == ONAME && n->sym->tenum != T && n->sym->tenum->etype == TIND;
+}
+
+static int
+isnil(Node *n)
+{
+ if(!isptr(n->type))
+ return 0;
+ while(n->op == OCAST)
+ n = n->left;
+ return n->op == OCONST && n->vconst == 0 || n->op == ONIL;
+}
+
+static int
+isconst(Node *n, vlong v)
+{
+ while(n->op == OCAST)
+ n = n->left;
+ return n->op == OCONST && n->vconst == v;
+}
+
+static Node*
+cknil(Node *n)
+{
+ if(isconst(n, 0))
+ n->op = ONIL;
+ return n;
+}
+
+static int
+cktype(Node *n, Node *t, int mask, int lev)
+{
+ int g, m, m0;
+
+ g = t->garb > lev;
+ m = marked(n->type) & mask;
+ if(n->op == ONAME){
+ m0 = marked(n->sym->type) & mask;
+ if(m && !m0){
+ n->sym->type = n->type;
+ if(!g)
+ again = 1;
+ }
+ if(!m && m0){
+ n->type = n->sym->type;
+ if(!g)
+ again = 1;
+ }
+ m |= m0;
+ }
+ if(m && t->garb < 2)
+ t->garb++;
+ return m && !g ? m : 0;
+}
+
+int
+isconsym(Sym *s)
+{
+ switch(s->class){
+ case CXXX:
+ case CTYPEDEF:
+ return 1;
+ case CEXTERN:
+ case CGLOBL:
+ case CSTATIC:
+ case CLOCAL:
+ return s->type != T && s->type->etype == TENUM;
+ }
+ return -1;
+}
+
+static void genstart(void);
+
+static char*
+mprolog[] =
+{
+ "%%: module",
+ "{",
+ "\tPATH: con \"%%%.dis\";",
+ "",
+ nil
+};
+
+static char*
+mepilog[] =
+{
+ "};",
+ nil
+};
+
+static char*
+bprolog[] =
+{
+ "implement %%;",
+ "",
+ "include \"draw.m\";",
+ "",
+ "%%: module",
+ "{",
+ " init: fn(nil: ref Draw->Context, argl: list of string);",
+ "};",
+ "",
+ nil
+};
+
+static char*
+bmprolog[] =
+{
+ "implement %%;",
+ "",
+ "include \"draw.m\";",
+ "",
+ nil
+};
+
+static char*
+bepilog[] =
+{
+ nil
+};
+
+static void
+pgen0(char **txt)
+{
+ int sub;
+ char *b, *s, *t, **p;
+
+ p = txt;
+ for(;;){
+ s = *p++;
+ if(s == nil)
+ break;
+ sub = 0;
+ for(t = s; *t != 0; t++){
+ if(*t == '%' && *(t+1) == '%'){
+ sub = 1;
+ break;
+ }
+ }
+ if(sub){
+ strcpy(buf, s);
+ b = buf;
+ for(t = s; *t != 0; t++){
+ if(*t == '%' && *(t+1) == '%'){
+ if(*(t+2) == '%'){
+ outmod(mbuf, 0);
+ t++;
+ }
+ else
+ outmod(mbuf, 1);
+ strcpy(b, mbuf);
+ b += strlen(mbuf);
+ t++;
+ }
+ else
+ *b++ = *t;
+ }
+ *b = 0;
+ prline(buf);
+ }
+ else
+ prline(s);
+ }
+}
+
+static char*
+hasm()
+{
+ outmod(mbuf, 0);
+ strcat(mbuf, ".m");
+ if(exists(mbuf))
+ return mbuf;
+ else if(domod){
+ outmod(buf, 0);
+ strcat(buf, ".h");
+ if(exists(buf))
+ return mbuf;
+ }
+ return nil;
+}
+
+void
+pgen(int b)
+{
+ char **p;
+
+ if(!dolog())
+ return;
+ if(b)
+ p = hasm() ? bmprolog : bprolog;
+ else
+ p = mprolog;
+ pgen0(p);
+ if(b && passes)
+ genstart();
+ if(!b)
+ incind();
+}
+
+void
+epgen(int b)
+{
+ char **p;
+
+ /* output(INFINITY, 1); */
+ if(!dolog())
+ return;
+ if(b){
+ if(!passes)
+ genstart();
+ p = bepilog;
+ }
+ else
+ p = mepilog;
+ if(!b)
+ decind();
+ pgen0(p);
+}
+
+static int lastsec = 0;
+
+#define ASSOC 1
+#define RASSOC 2
+#define POSTOP 4
+
+#define LEFT 1
+#define RIGHT 2
+#define PRE 4
+#define POST 8
+
+static int space[] = { 0, 0, 2, 0, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static struct{
+ char *name;
+ int prec;
+ int kind;
+} ops[] = {
+ "", 0, 0, /* ONOOP */
+ "", 16, 0, /* OXXX, */
+ "+", 12, ASSOC, /* OADD, */
+ "&", 14, RASSOC, /* OADDR, */
+ "&", 8, ASSOC, /* OAND, */
+ "&&", 5, ASSOC, /* OANDAND, */
+ "", 16, 0, /* OARRAY, */
+ "=", 2, RASSOC, /* OAS, */
+ "=", 2, RASSOC, /* OASI, */
+ "+=", 2, RASSOC, /* OASADD, */
+ "&=", 2, RASSOC, /* OASAND, */
+ "<<=", 2, RASSOC, /* OASASHL, */
+ ">>=", 2, RASSOC, /* OASASHR, */
+ "/=", 2, RASSOC, /* OASDIV, */
+ "<<", 11, 0, /* OASHL, */
+ ">>", 11, 0, /* OASHR, */
+ "/=", 2, RASSOC, /* OASLDIV, */
+ "%=", 2, RASSOC, /* OASLMOD, */
+ "*=", 2, RASSOC, /* OASLMUL, */
+ ">>=", 2, RASSOC, /* OASLSHR, */
+ "%=", 2, RASSOC, /* OASMOD, */
+ "*=", 2, RASSOC, /* OASMUL, */
+ "|=", 2, RASSOC, /* OASOR, */
+ "-=", 2, RASSOC, /* OASSUB, */
+ "^=", 2, RASSOC, /* OASXOR, */
+ "", -1, 0, /* OBIT, */
+ "", -1, 0, /* OBREAK, */
+ "", -1, 0, /* OCASE, */
+ "", 14, RASSOC, /* OCAST, */
+ "", 1, ASSOC, /* OCOMMA, */
+ "", 3, RASSOC, /* OCOND, */
+ "", 16, 0, /* OCONST, */
+ "", -1, 0, /* OCONTINUE, */
+ "/", 13, 0, /* ODIV, */
+ ".", 15, 0, /* ODOT, */
+ "...", 16, 0, /* ODOTDOT, */
+ "", -1, 0, /* ODWHILE, */
+ "", -1, 0, /* OENUM, */
+ "==", 9, 0, /* OEQ, */
+ "", -1, 0, /* OFOR, */
+ "", 15, 0, /* OFUNC, */
+ ">=", 10, 0, /* OGE, */
+ "", -1, 0, /* OGOTO, */
+ ">", 10, 0, /* OGT, */
+ ">", 10, 0, /* OHI, */
+ ">=", 10, 0, /* OHS, */
+ "", -1, 0, /* OIF, */
+ "*", 14, RASSOC, /* OIND, */
+ "", -1, 0, /* OINDREG, */
+ "", 16, 0, /* OINIT, */
+ "", -1, 0, /* OLABEL, */
+ "/", 13, 0, /* OLDIV, */
+ "<=", 10, 0, /* OLE, */
+ "", 16, 0, /* OLIST, */
+ "%", 13, 0, /* OLMOD, */
+ "*", 13, ASSOC, /* OLMUL, */
+ "<", 10, 0, /* OLO, */
+ "<=", 10, 0, /* OLS, */
+ ">>", 11, 0, /* OLSHR, */
+ "<", 10, 0, /* OLT, */
+ "%", 13, 0, /* OMOD, */
+ "*", 13, ASSOC, /* OMUL, */
+ "", 16, 0, /* ONAME, */
+ "!=", 9, 0, /* ONE, */
+ "!", 14, RASSOC, /* ONOT, */
+ "|", 6, ASSOC, /* OOR, */
+ "||", 4, ASSOC, /* OOROR, */
+ "--", 14, RASSOC|POSTOP, /* OPOSTDEC, */
+ "++", 14, RASSOC|POSTOP, /* OPOSTINC, */
+ "--", 14, RASSOC, /* OPREDEC, */
+ "++", 14, RASSOC, /* OPREINC, */
+ "", 16, 0, /* OPROTO, */
+ "", -1, 0, /* OREGISTER, */
+ "", 0, 0, /* ORETURN, */
+ "SET", -1, 0, /* OSET, */
+ "signof", 14, RASSOC, /* OSIGN, */
+ "sizeof", 14, RASSOC, /* OSIZE, */
+ "", 16, 0, /* OSTRING, */
+ "", 16, 0, /* OLSTRING, */
+ "", 16, 0, /* OSTRUCT, */
+ "-", 12, 0, /* OSUB, */
+ "", -1, 0, /* OSWITCH, */
+ "", 16, 0, /* OUNION, */
+ "USED", -1, 0, /* OUSED, */
+ "", -1, 0, /* OWHILE, */
+ "^", 7, ASSOC, /* OXOR, */
+ "-", 14, RASSOC, /* ONEG, */
+ "~", 14, RASSOC, /* OCOM, */
+ "", 16, 0, /* OELEM, */
+ "", -1, 0, /* OTST, */
+ "", -1, 0, /* OINDEX, */
+ "", -1, 0, /* OFAS, */
+ "", -1, 0, /* OBLK */
+ "+", 14, RASSOC, /* OPOS */
+ "", -1, 0, /* ONUL */
+ ".", 15, 0, /* ODOTIND */
+ "", 15, 0, /* OARRIND */
+ "", -1, 0, /* ODAS */
+ ":=", 2, RASSOC, /* OASD */
+ "", 16, 0, /* OIOTA */
+ "", 14, RASSOC, /* OLEN */
+ "", 17, 0, /* OBRACKET */
+ "", 14, RASSOC, /* OREF */
+ "", 14, RASSOC, /* OARRAYOF */
+ "", 15, 0, /* OSLICE */
+ "&", 14, RASSOC, /* OSADDR, */
+ "", 16, 0, /* ONIL */
+ "", 16, 0, /* OS2AB */
+ "", 16, 0, /* OAB2S */
+ "", 16, 0, /* OFILDES */
+ ".", 15, 0, /* OFD */
+ "", 16, 0, /* OTUPLE */
+ ".", 15, 0, /* OT0 */
+ "", 15, 0, /* ORETV */
+ "+", 12, ASSOC, /* OCAT */
+ "", -1, 0, /* OSBREAK, */
+ ".", 15, 0, /* OLDOT */
+ "->", 15, 0, /* OMDOT */
+ nil, -1, 0, /* OCODE */
+ nil, -1, 0, /* ODECE */
+ nil, -1, 0, /* ODECT */
+ nil, -1, 0, /* ODECV */
+ nil, -1, 0, /* ODECF */
+ nil, -1, 0, /* OPUSH */
+ nil, -1, 0, /* OPOP */
+ "", -1, 0, /* OEND */
+};
+
+#define COMPLEX 32
+
+#define NOBR 2
+#define NOIN 4
+#define YESBR 8
+#define NONL 16
+#define NOENL 32
+
+enum{
+ LNONE,
+ LSTRLEN,
+ LSTRCMP,
+ LSTRCPY,
+ LSTRCAT,
+ LSTRNCMP,
+ LSTRNCPY,
+ LSTRNCAT,
+ LSTRDUP,
+ LMEMMOVE,
+ LMALLOC,
+ LFREE,
+ LEXIT,
+ LCLOSE,
+ LATOI,
+ LATOL,
+ LATOF,
+ LPRINT,
+ LFPRINT,
+ LSPRINT,
+ LSELF,
+};
+
+static int tmp;
+
+static void egen(Node*, int, int);
+static Node* buildcases(Node*);
+static void tdgen(Node *, int);
+static Node* cfind(Node*);
+static Node* cgen(Node*, Node*);
+static void cgen0(Node*, Node*);
+static int lteq(Type*, Type*);
+static Type* ntype(Node*);
+static int rewe(Node*, Type*, int);
+static void rewlc(Node*, int, Type*);
+static Node* con(vlong);
+static void clrbrk(Node*);
+static int hasbrk(Node*);
+static int isgen(char*);
+static int simple(Node*);
+static void pfmt(char*);
+static void lpfmt(ushort*);
+static int lline(Node*);
+static void args(Node*);
+static void addmodn(Sym*);
+static void scomplex(Node*);
+static void mset(Node*);
+
+static Node *lastd;
+
+static int
+rev(int op)
+{
+ switch(op){
+ case OLT: return OGT;
+ case OLE: return OGE;
+ case OGT: return OLT;
+ case OGE: return OLE;
+ }
+ return op;
+}
+
+void
+newsec(int l)
+{
+ if(l != 1 && lastd != Z){
+ tdgen(lastd, 1);
+ lastd = Z;
+ }
+ if(l != 2)
+ etgen2(nil);
+ if(lastsec && l != lastsec)
+ newline();
+ lastsec = l;
+}
+
+static Node*
+defval(Type *t)
+{
+ Node *n;
+
+ if(t == T)
+ t = types[TINT];
+ n = con(0);
+ n->type = types[TINT];
+ n->kind = KDEC;
+ switch(t->etype){
+ case TFLOAT:
+ case TDOUBLE:
+ n->type = types[TDOUBLE];
+ n->fconst = 0.0;
+ n->cstring = "0.0";
+ return n;
+ default:
+ break;
+ case TIND:
+ case TFUNC:
+ case TARRAY:
+ n->type = typ1(TIND, types[TVOID]);
+ return n;
+ case TVOID:
+ case TSTRUCT:
+ case TUNION:
+ free(n);
+ return Z;
+ }
+ if(!lteq(n->type, t)){
+ n = new1(OCAST, n, Z);
+ n->type = t;
+ }
+ return n;
+}
+
+static int
+teq(Type *t1, Type *t2)
+{
+ if(t1 == t2)
+ return 1;
+ return sametype(t1, t2);
+/*
+ if(t1->etype != t2->etype)
+ return 0;
+ switch(t1->etype){
+ case TARRAY:
+ if(t1->width != t2->width)
+ return 0;
+ break;
+ case TFUNC:
+ if(!teq(t1->down, t2->down))
+ return 0;
+ break;
+ case TSTRUCT:
+ case TUNION:
+ return t1->link == t2->link;
+ case TENUM:
+ return 1;
+ }
+ return teq(t1->link, t2->link);
+*/
+}
+
+static int
+tequiv(Type *t1, Type *t2)
+{
+ if(!teq(t1, t2))
+ return 0;
+ if(t1->etype == TSTRUCT || t1->etype == TUNION)
+ return suename(t1) == suename(t2);
+ return 1;
+}
+
+static int
+iteq(Type *t1, Type *t2)
+{
+ if(t1 == T || t2 == T)
+ return 0;
+ return t1->etype == TIND && (teq(t1->link, t2) || (t1->link->etype == TVOID && isnum(t2)));
+}
+
+static Type *
+ltype(Type *t)
+{
+ switch(t->etype){
+ case TUCHAR:
+ return types[TCHAR];
+ case TSHORT:
+ case TUSHORT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TENUM:
+ return types[TINT];
+ case TUVLONG:
+ return types[TVLONG];
+ case TFLOAT:
+ return types[TDOUBLE];
+ default:
+ return t;
+ }
+ return t;
+}
+
+static int
+lteq(Type *t1, Type *t2)
+{
+ if(t1 == T || t2 == T)
+ return 0;
+ if(t1 == t2)
+ return 1;
+ if(t1->etype == TIND && t2->etype == TIND)
+ return lteq(t1->link, t2->link);
+ return sametype(ltype(t1), ltype(t2));
+}
+
+static Type*
+tcp(Type *t)
+{
+ Type *nt;
+
+ if(t == T)
+ return T;
+ nt = typ1(TXXX, T);
+ *nt = *t;
+ return nt;
+}
+
+static Type*
+tuple(Type *t1, Type *t2)
+{
+ Type *t, **at, *l;
+
+ if(t1 == T || t1->etype == TVOID)
+ return tcp(t2);
+ if(t2 == T || t2->etype == TVOID)
+ return tcp(t1);
+ if(t2->etype == TTUPLE)
+ diag(Z, "bad tuple type");
+ t = typ1(TTUPLE, T);
+ at = &t->link;
+ if(t1->etype == TTUPLE){
+ for(l = t1->link; l != T; l = l->down){
+ *at = tcp(l);
+ at = &(*at)->down;
+ }
+ }
+ else{
+ *at = tcp(t1);
+ at = &(*at)->down;
+ }
+ *at = tcp(t2);
+ return t;
+}
+
+static Sym*
+sue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return S;
+}
+
+static void
+pranon(int i)
+{
+ prid("anon_");
+ prnum(i+1, KDEC, T);
+}
+
+static int
+dotpath(Sym *s, Type *t, int pr)
+{
+ int i;
+ Type *t1;
+
+ if(t == T)
+ return 0;
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(t1->sym == s){
+ if(pr){
+ prdelim(".");
+ prsym(s, 0);
+ }
+ return 1;
+ }
+ }
+ i = 0;
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(t1->sym == S){
+ i++;
+ if(typesu[t1->etype] && sametype(s->type, t1)){
+ if(pr){
+ prdelim(".");
+ pranon(i-1);
+ }
+ return 1;
+ }
+ }
+ }
+ i = 0;
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(t1->sym == S){
+ i++;
+ if(typesu[t1->etype] && dotpath(s, t1, 0)){
+ if(pr){
+ prdelim(".");
+ pranon(i-1);
+ dotpath(s, t1, 1);
+ }
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static Sym*
+suename(Type *t)
+{
+ Sym *s;
+
+ s = sue(t->link);
+ if(s != S)
+ return s;
+ else if(t->tag != S)
+ return t->tag;
+ else if(t->sym != S)
+ return t->sym;
+ return S;
+}
+
+static int
+cycle(Type *t, Type *base)
+{
+ int r;
+ Type *l;
+
+ if(t->vis){
+ /* sametype() does structural comparison so have to check names */
+ if(t == base || tequiv(t, base))
+ return 1;
+ return 0;
+ }
+ r = 0;
+ t->vis = 1;
+ switch(t->etype){
+ case TIND:
+ case TARRAY:
+ r = cycle(t->link, base);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ case TTUPLE:
+ for(l = t->link; l != T; l = l->down)
+ r |= cycle(l, base);
+ break;
+ }
+ t->vis = 0;
+ return r;
+}
+
+static void
+addnode(int op, Node *n)
+{
+ Node *nn;
+
+ nn = new1(OXXX, Z, Z);
+ *nn = *n;
+ n->op = op;
+ n->left = nn;
+ n->right = Z;
+ n->type = nn->type;
+}
+
+static void
+cast(Node *n, Type *t)
+{
+ addnode(OCAST, n);
+ n->type = t;
+}
+
+static void
+intcast(Node *n)
+{
+ if(isptr(n->type)){
+ addnode(ONE, n);
+ n->right = con(0);
+ n->right->type = n->left->type;
+ n->type = types[TINT];
+ }
+ else
+ cast(n, types[TINT]);
+}
+
+static void
+strcast(Node *n)
+{
+ cast(n, stringtype);
+}
+
+static void
+bptr(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ default:
+ if(!lteq(n->type, types[TINT]))
+ intcast(n);
+ break;
+ case ONOT:
+ if(!lteq(n->left->type, types[TINT])){
+ intcast(n->left);
+ if(n->left->op == ONE){
+ n->left->op = OEQ;
+ *n = *n->left;
+ }
+ }
+ break;
+ case OANDAND:
+ case OOROR:
+ bptr(n->left);
+ bptr(n->right);
+ break;
+ case OCOND:
+ bptr(n->right->left);
+ bptr(n->right->right);
+ break;
+ }
+}
+
+static void
+bcomplex(Node *n)
+{
+ if(n == Z)
+ return;
+ if(!passes)
+ complex(n);
+ bptr(n);
+}
+
+static void
+ecomplex(Node *n)
+{
+ if(!passes)
+ complex(n);
+ rewe(n, T, 0);
+}
+
+static void
+becomplex(Node *n)
+{
+ bcomplex(n);
+ rewe(n, T, 0);
+}
+
+static void
+tgen(Type *t, int dec, int arinit)
+{
+ Type *l;
+
+ if(t == T)
+ return;
+ switch(t->etype){
+ case TXXX:
+ prid("int");
+ break;
+ case TCHAR:
+ case TUCHAR:
+ prid("byte");
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TENUM:
+ prid("int");
+ break;
+ case TVLONG:
+ case TUVLONG:
+ prid("big");
+ break;
+ case TFLOAT:
+ case TDOUBLE:
+ prid("real");
+ break;
+ case TIND:
+ if(strings == 2 && t->link && t->link->etype == TCHAR){
+ prid("string");
+ break;
+ }
+ if(isadt(t->link) || t->link->etype == TFUNC)
+ prid("ref ");
+ else
+ prid("array of ");
+ if(t->link && t->link->etype == TVOID){
+ prid("byte");
+ prcom("was void*", Z);
+ }
+ else
+ tgen(t->link, 1, 0);
+ break;
+ case TFUNC:
+ if(0){
+ prid("int");
+ prcom("was function", Z);
+ break;
+ }
+ prid("fn");
+ prdelim("(");
+ for(l = t->down; l != T; l = l->down){
+ if(l->etype == TVOID && l->down == T)
+ break;
+ if(l->etype == TDOT){
+ prcom("was ...", Z);
+ break;
+ }
+ if(l->sym != S)
+ prsym(l->sym, 0);
+ else
+ prid("nil");
+ prdelim(": ");
+ tgen(l, 1, 0);
+ if(l->down != T && l->down->etype != TDOT)
+ prdelim(", ");
+ }
+ /* tgen(t->down, dec, 0, 0); */
+ prdelim(")");
+ if(!isvoid(t->link)){
+ prdelim(": ");
+ tgen(t->link, dec, 0);
+ }
+ break;
+ case TARRAY:
+ prid("array");
+ if(t->width == LARR)
+ t->width = LARR;
+ else if(dec){
+ if(t->nwidth != Z)
+ prcom("array index was ", t->nwidth);
+ else if(t->width != 0){
+ sprint(buf, "array index was %ld", t->width/t->link->width);
+ prcom(buf, Z);
+ }
+ }
+ else{
+ prdelim("[");
+ if(t->nwidth != Z)
+ egen(t->nwidth, ONOOP, PRE);
+ else if(t->width != 0)
+ prnum(t->width/t->link->width, KDEC, T);
+ prdelim("]");
+ }
+ prdelim(" of ");
+ if(!arinit)
+ tgen(t->link, 1, 0);
+ break;
+ case TVOID:
+ /* prid("void"); */
+ prid("byte");
+ prcom("was void", Z);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ if(t->link != T && t->link->etype == TFD){
+ prid("Sys->FD");
+ usemod(sysop, 0);
+ }
+ else
+ prsym(suename(t), 1);
+ break;
+ case TTUPLE:
+ prdelim("(");
+ for(l = t->link; l != T; l = l->down){
+ tgen(l, dec, 0);
+ if(l->down != T)
+ prdelim(", ");
+ }
+ prdelim(")");
+ break;
+ case TDOT:
+ prdelim("...");
+ break;
+ case TSTRING:
+ prid("string");
+ break;
+ case TFD:
+ prid("fd");
+ break;
+ default:
+ diag(Z, "unknown type");
+ break;
+ }
+}
+
+static Type*
+typn(Type *t, int i)
+{
+ Type *l;
+
+ for(l = t->down; l != T && --i >= 0; l = l->down)
+ ;
+ return l;
+}
+
+void
+ttgen2(Type *t)
+{
+ Type *l;
+ Sym *s;
+ int anon = 0;
+
+ switch(t->etype){
+ case TSTRUCT:
+ case TUNION:
+ newsec(0);
+ output(t->lineno, 1);
+ s = suename(t);
+ if(isgen(s->name))
+ addmodn(s);
+ setmod(s);
+ prsym(s, 0);
+ prdelim(": ");
+ prid("adt");
+ prdelim("{");
+ if(t->etype == TUNION)
+ prcom("was union", Z);
+ newline();
+ incind();
+ t->vis = 1;
+ for(l = t->link; l != T; l = l->down){
+ output(l->lineno, 1);
+ if(l->nbits)
+ prcom("was bit field", Z);
+ if(l->sym != S)
+ prsym(l->sym, 0);
+ else
+ pranon(anon++);
+ prdelim(": ");
+ if(cycle(l, t))
+ prid("cyclic ");
+ tgen(l, 1, 0);
+ prdelim(";");
+ newline();
+ }
+ t->vis = 0;
+ decind();
+ prdelim("};");
+ newline();
+ newline();
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+canjoin(Node *n, Node *nn)
+{
+ return teq(n->type, nn->type) && isname(n) && isname(nn) && n->type->etype != TARRAY;
+}
+
+void
+vtgen2(Node *n)
+{
+ int t, c, comma = 0;
+ Node *nn;
+ Sym *s;
+
+ nn = n;
+ if(n->op == ODAS)
+ nn = n->left;
+ if(nn->type == T || nn->sym == S)
+ return;
+ t = nn->type->etype;
+ c = nn->sym->class;
+ if(0 && c == CTYPEDEF){
+ /* egen(nn, ONOOP, PRE); */
+ /* tdgen(n, 1, 0); */
+ if(isadt(n->type)){
+ s = suename(n->type);
+ if(isgen(s->name)){
+ s->lname = nn->sym->name;
+ ttgen2(n->type);
+ }
+ }
+ }
+ if(c != CGLOBL && c != CSTATIC && c != CLOCAL && c != CEXREG)
+ return;
+ newsec(1);
+ if(lastd != Z){
+ if(t != TFUNC && canjoin(lastd, n))
+ comma = 1;
+ else
+ tdgen(lastd, 1);
+ }
+ output(nn->lineno, 1);
+ if(t == TFUNC){
+ if(ism()){
+ setmod(nn->sym);
+ egen(nn, ONOOP, PRE);
+ tdgen(n, 1);
+ }
+ lastd = Z;
+ return;
+ }
+ if(comma)
+ prdelim(", ");
+ if(nn->op != ONAME)
+ diag(nn, "internal: not name in vtgen");
+ setmod(nn->sym);
+ prsym(nn->sym, 0);
+ /* egen(nn, ONOOP, PRE); */
+ /* tdgen(n, 1, 0); */
+ lastd = n;
+ if(n->op == ODAS)
+ rewe(n->right, T, 1);
+}
+
+static void minseq(Syml*);
+
+static Node*
+con(vlong v)
+{
+ int neg = 0;
+ Node *n;
+
+ if(v < 0){
+ neg = 1;
+ v = -v;
+ }
+ n = new1(OCONST, Z, Z);
+ n->vconst = v;
+ n->kind = KDEC;
+ n->type = types[TINT];
+ if(neg)
+ n = new1(ONEG, n, Z);
+ return n;
+}
+
+/*
+static Node*
+fcon(double v)
+{
+ int neg = 0;
+ Node *n;
+
+ if(v < 0){
+ neg = 1;
+ v = -v;
+ }
+ n = new1(OCONST, Z, Z);
+ n->fconst = v;
+ n->kind = KDEC;
+ n->type = types[TDOUBLE];
+ if(neg)
+ n = new1(ONEG, n, Z);
+ return n;
+}
+*/
+
+static Node*
+add(vlong v, Node *n)
+{
+ if(v == 0)
+ return n;
+ return new1(OADD, con(v), n);
+}
+
+static Node*
+addn(Node *n1, Node *n2)
+{
+ if(n1 == Z || n2 == Z)
+ return Z;
+ if(isconst(n1, 0))
+ return n2;
+ if(isconst(n2, 0))
+ return n1;
+ return new1(OADD, n1, n2);
+}
+
+static Node*
+mul(vlong v, Node *n)
+{
+ if(v == 0)
+ return con(0);
+ else if(v == 1)
+ return n;
+ else if(v == -1)
+ return new1(ONEG, n, Z);
+ return new1(OMUL, con(v), n);
+}
+
+static Node*
+mydiv(Node *n, vlong w)
+{
+ Node *nn;
+
+ if(w == 0)
+ return Z;
+ if(w == 1)
+ return n;
+ else if(w == -1)
+ return new1(ONEG, n, Z);
+ switch(n->op){
+ case OCONST:
+ if(n->vconst % w == 0){
+ n->vconst /= w;
+ if(n->left != Z && mydiv(n->left, w) == Z){
+ n->vconst *= w;
+ break;
+ }
+ return n;
+ }
+ break;
+ case OCAST:
+ return mydiv(n->left, w);
+ case OMUL:
+ nn = mydiv(n->right, w);
+ if(nn != Z){
+ if(isconst(nn, 1))
+ *n = *n->left;
+ return n;
+ }
+ nn = mydiv(n->left, w);
+ if(nn != Z){
+ if(isconst(nn, 1))
+ *n = *n->right;
+ return n;
+ }
+ break;
+ default:
+ break;
+ }
+ return Z;
+}
+
+static Node*
+iota(void)
+{
+ return new1(OIOTA, Z, Z);
+}
+
+static Node*
+symcon(Sym *s)
+{
+ Node *n;
+
+ if(s->nconst != Z)
+ return s->nconst;
+ n = con(s->vconst);
+ n->kind = s->kind;
+ return n;
+}
+
+#define ARITH 1
+#define GEOM 2
+
+static Syml*
+newsyml(Sym *s, Syml **frees)
+{
+ Syml *sl, *f;
+
+ if((f = *frees) != nil){
+ sl = f;
+ *frees = f->nxt;
+ }
+ else
+ sl = (Syml*)malloc(sizeof(Syml));
+ sl->sym = s;
+ sl->nxt = nil;
+ return sl;
+}
+
+static Syml*
+etseq(Syml *syml)
+{
+ int e, pio, io, comma;
+ vlong d, dd, v0, v1, v, t, tt;
+ Node *expr;
+ Sym *s;
+ Syml *sl, *lsl;
+
+ lsl = nil;
+ pio = io = ARITH|GEOM;
+ e = 0;
+ dd = 0;
+ for(sl = syml; sl != nil; sl = sl->nxt){
+ s = sl->sym;
+ if(isreal(s->tenum) || s->tenum->etype == TIND)
+ break;
+ if(e == 0)
+ v0 = s->vconst;
+ if(e == 1){
+ v1 = s->vconst;
+ d = v1-v0;
+ }
+ if(e > 0 && (v <= 0 || s->vconst != 2*v))
+ io &= ~GEOM;
+ if(0 && e > 1 && s->vconst-v != d)
+ io &= ~ARITH;
+ if(e > 1){
+ t = s->vconst-v;
+ tt = t-d;
+ if(e > 2 && tt != dd)
+ io &= ~ARITH;
+ else{
+ d = t;
+ dd = tt;
+ }
+ }
+ if(io == 0)
+ break;
+ v = s->vconst;
+ lsl = sl;
+ pio = io;
+ e++;
+ }
+ if(e < 2)
+ pio = 0;
+ if(pio&GEOM){
+ if(e < 3)
+ pio = 0;
+ }
+ else if(pio&ARITH){
+ int n;
+
+ if(d == 0 && dd == 0)
+ n = 2;
+ else if(dd == 0)
+ n = 3;
+ else
+ n = 4;
+ if(e < n || (dd&1) != 0)
+ pio = 0;
+ }
+ if(lsl == nil || pio == 0)
+ lsl = syml;
+ comma = 0;
+ for(sl = syml; sl != nil; sl = sl->nxt){
+ s = sl->sym;
+ nearln = s->lineno;
+ output(s->lineno, 1);
+ if(pio){
+ if(comma)
+ prdelim(", ");
+ setmod(s);
+ prsym(s, 0);
+ comma = 1;
+ }
+ else{
+ setmod(s);
+ prsym(s, 0);
+ prdelim(": ");
+ prid("con ");
+ if(isbyte(s->tenum) || isbig(s->tenum) && !islbigv(s->vconst) || !isbig(s->tenum) && isuintv(s->vconst)){
+ tgen(s->tenum, 1, 0);
+ prdelim(" ");
+ }
+ if(s->nconst != Z)
+ egen(s->nconst, ONOOP, PRE);
+ else if(s->kind == KCHR)
+ prchar(s->vconst);
+ else if(isreal(s->tenum))
+ prreal(s->fconst, s->cstring, s->kind);
+ else
+ prnum(s->vconst, s->kind, s->tenum);
+ prdelim(";");
+ newline();
+ }
+ if(sl == lsl)
+ break;
+ }
+ if(pio){
+ s = syml->sym;
+ prdelim(": ");
+ prid("con ");
+ if(isbyte(s->tenum) || isbig(s->tenum)){
+ tgen(s->tenum, 1, 0);
+ prdelim(" ");
+ }
+ if(pio&GEOM){
+ if(v0 == 0 || v0 == 1 || v0 == -1)
+ expr = mul(v0, new1(OASHL, con(1), iota()));
+ else
+ expr = new1(OMUL, symcon(s), new1(OASHL, con(1), iota()));
+ }
+ else if(d == 0 && dd == 0)
+ expr = symcon(s);
+ else if(dd == 0)
+ expr = add(v0, mul(d, iota()));
+ else
+ expr = add(v0, new1(OADD, mul(v1-dd/2-v0, iota()), mul(dd/2, new1(OMUL, iota(), iota()))));
+ complex(expr);
+ expr = ckneg(expr);
+ egen(expr, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ }
+ return lsl->nxt;
+}
+
+static void
+adde(Syml *sl, Symq *q)
+{
+ if(q->f == nil)
+ q->f = sl;
+ else
+ q->r->nxt = sl;
+ q->r = sl;
+}
+
+static void
+freeq(Symq *q, Syml **frees)
+{
+ if(q->f){
+ q->r->nxt = *frees;
+ *frees = q->f;
+ q->f = q->r = nil;
+ }
+}
+
+static void
+etgen2(Sym *s)
+{
+ Syml *sl;
+ static Syml *frees;
+ static Symq symq, symq1;
+
+ if(s != nil){
+ newsec(2);
+ sl = newsyml(s, &frees);
+ adde(sl, &symq);
+ if(isinteger(s->tenum) && isbigv(s->vconst) && !isbig(s->tenum))
+ s->tenum = types[TVLONG];
+ return;
+ }
+ /* end of enums */
+ if(symq.f && symq.f == symq.r){ /* try to merge with other singletons */
+ adde(symq.f, &symq1);
+ symq.f = symq.r = nil;
+ return;
+ }
+ if(symq1.f){
+ for(sl = symq1.f; sl != nil; sl = etseq(sl))
+ ;
+ freeq(&symq1, &frees);
+ }
+ if(symq.f){
+ for(sl = symq.f; sl != nil; sl = etseq(sl))
+ ;
+ freeq(&symq, &frees);
+ }
+}
+
+static void
+lgen(Node *n, int br, int first)
+{
+ if(br)
+ prdelim("(");
+ if(n == Z){
+ if(br)
+ prdelim(")");
+ return;
+ }
+ if(n->op == OLIST || n->op == OTUPLE){
+ lgen(n->left, 0, first);
+ lgen(n->right, 0, 0);
+ }
+ else if(n->op != ODOTDOT){
+ if(!first)
+ prdelim(", ");
+ egen(n, ONOOP, PRE);
+ }
+ else
+ prcom("was ...", Z);
+ if(br)
+ prdelim(")");
+}
+
+static void
+preced(int op1, int op2, int s, int c)
+{
+ int p1, p2, k1, k2, br;
+ char buf[2];
+
+ br = 0;
+ p1 = ops[op1].prec;
+ p2 = ops[op2].prec;
+ if(p1 < 0 || p2 < 0)
+ diag(Z, "-ve precedence");
+ if(p1 > p2)
+ br = 1;
+ else if(p1 == p2){
+ k1 = ops[op1].kind;
+ k2 = ops[op2].kind;
+ if(op1 == op2){
+ if(k1&RASSOC)
+ br = s == LEFT;
+ else
+ br = s == RIGHT && !(k1&ASSOC);
+ }
+ else{
+ if(k1&RASSOC)
+ br = s == LEFT;
+ else
+ br = s == RIGHT && op1 != OADD;
+
+ if(k1&POSTOP && !(k2&POSTOP))
+ br = 1;
+
+ /* funny case */
+ if(op2 == OMDOT && s == LEFT && (op1 == ODOT || op1 == ODOTIND))
+ br = 1;
+ }
+ }
+ if(br){
+ buf[0] = c;
+ buf[1] = '\0';
+ prdelim(buf);
+ }
+}
+
+static void
+egen(Node *n, int op0, int side)
+{
+ int op, p;
+ Type *t;
+ Node *nn;
+
+ if(n == Z){
+ if(op0 == OBRACKET)
+ prdelim("()");
+ return;
+ }
+ if(n->op == OCONST && n->left != Z){ /* actual node in source */
+ n->left->type = n->type;
+ n = n->left;
+ }
+ if((n->op == OSTRING || n->op == OLSTRING) && n->left != Z) /* actual node in source */
+ n = n->left;
+ if(n->op == OCAST && (lteq(n->type, n->left->type) || isnil(n) || !iscastable(n->type, n->left->type))){
+ if(isnil(n))
+ prid("nil");
+ else
+ egen(n->left, op0, side);
+ return;
+ }
+ if(n->op == ONAME && arrow(n->sym))
+ n->op = OMDOT;
+ if(n->op != OLIST)
+ output(n->lineno, 0);
+ op = n->op;
+ preced(op0, op, side, '(');
+ switch(op){
+ case OLIST:
+ case OTUPLE:
+ lgen(n, 1, 1);
+ break;
+ case OIOTA:
+ prid("iota");
+ break;
+ case OMDOT:
+ case ONAME:
+ case OXXX:
+ prsym(n->sym, 1);
+ break;
+ case OCONST:
+ if(n->kind == KCHR)
+ prchar(n->vconst);
+ else if(isreal(n->type))
+ prreal(n->fconst, n->cstring, n->kind);
+ else if(isnil(n))
+ prid("nil");
+ else
+ prnum(n->vconst, n->kind, n->type);
+ if(n->right != Z)
+ prcom("was ", n->right);
+ break;
+ case OSTRING:
+ prstr(n->cstring);
+ break;
+ case OLSTRING:
+ prlstr(n->rstring);
+ break;
+ case OCOND:
+ egen(n->left, op, POST);
+ prdelim(" ? ");
+ egen(n->right->left, op, PRE|POST);
+ prdelim(" : ");
+ egen(n->right->right, op, PRE);
+ prcom("?", Z);
+ break;
+ case OCOMMA:
+ if(op0 != OCOMMA)
+ prdelim("(");
+ egen(n->left, op, LEFT);
+ prdelim(", ");
+ egen(n->right, op, RIGHT);
+ if(op0 != OCOMMA)
+ prdelim(")");
+ break;
+ case OLDOT:
+ egen(n->left, OMOD, LEFT); /* any precedence 13 operator */
+ prdelim(".");
+ egen(n->right, op, RIGHT);
+ break;
+ default:
+ p = ops[op].prec;
+ egen(n->left, op, LEFT);
+ if(space[p])
+ prdelim(" ");
+ prdelim(ops[op].name);
+ if(space[p])
+ prdelim(" ");
+ egen(n->right, op, RIGHT);
+ break;
+ case OIND: case OADDR: case OSADDR:
+ case OPOS: case ONEG:
+ case ONOT: case OCOM:
+ case OPREINC: case OPREDEC:
+ if(op == OADDR){
+ n->op = OSADDR;
+ if(!isfn(n->left->type))
+ prcom("was ", n);
+ }
+ else
+ prdelim(ops[op].name);
+ egen(n->left, op, PRE);
+ break;
+ case OPOSTINC: case OPOSTDEC:
+ egen(n->left, op, POST);
+ prdelim(ops[op].name);
+ break;
+ case ODOT:
+ egen(n->left, op, LEFT);
+ dotpath(n->sym, n->left->type, 1);
+ /* prdelim(ops[op].name); */
+ /* prsym(n->sym, 0); */
+ break;
+ case ODOTIND:
+ egen(n->left, op, LEFT);
+ if(isadt(n->left->type))
+ dotpath(n->sym, n->left->type, 1); /* type may be demoted arg */
+ else
+ dotpath(n->sym, n->left->type->link, 1);
+ /* prdelim(ops[op].name); */
+ /* prsym(n->sym, 0); */
+ break;
+ case OARRIND:
+ egen(n->left, op, LEFT);
+ prdelim("[");
+ egen(n->right, ONOOP, RIGHT);
+ prdelim("]");
+ if(n->right->op == OCONST && n->right->vconst < 0)
+ prcom("negative array index", Z);
+ break;
+ case OLEN:
+ prid("len ");
+ egen(n->right, op, PRE);
+ break;
+ case OREF:
+ prid("ref ");
+ tgen(n->type->link, 0, 0);
+ break;
+ case OARRAYOF:
+ prid("array");
+ prdelim("[");
+ egen(n->left, ONOOP, LEFT);
+ prdelim("]");
+ prid(" of ");
+ tgen(n->type->link, 0, 0);
+ break;
+ case OSLICE:
+ egen(n->left, op, LEFT);
+ prdelim("[");
+ egen(n->right->left, ONOOP, RIGHT);
+ prdelim(": ");
+ egen(n->right->right, ONOOP, RIGHT);
+ prdelim("]");
+ break;
+ case OFUNC:
+ if(n->kind == KEXP)
+ egen(n->left, op, LEFT);
+ else
+ prsym(n->left->sym, 0);
+ lgen(n->right, 1, 1);
+ if(n->kind != KEXP && !isvoid(n->left->type->link)){
+ prdelim(": ");
+ tgen(n->left->type->link, 0, 0);
+ }
+ break;
+ case ONIL:
+ prid("nil");
+ break;
+ case OCAST:
+ if(isnil(n))
+ prid("nil");
+ else if(iscastable(n->type, n->left->type)){
+ tgen(n->type, 0, 0);
+ prdelim(" ");
+ egen(n->left, op, RIGHT);
+ }
+ else
+ egen(n->left, op0, RIGHT);
+ break;
+ case OARRAY:
+ tgen(n->type, 0, 0);
+ egen(n->left, op, LEFT);
+ prdelim("[");
+ egen(n->right, ONOOP, RIGHT);
+ prdelim("]");
+ break;
+ case OSTRUCT:
+ case OUNION:
+ tgen(n->type, 0, 0);
+ lgen(n->left, 1, 1);
+ break;
+ case OELEM:
+ prdelim(".");
+ /* tgen(n->type, 0, 0, 0); */
+ prsym(n->sym, 0);
+ break;
+ case OSIZE:
+ case OSIGN:
+ prid(ops[op].name);
+ if(n->left != Z)
+ egen(n->left, OBRACKET, RIGHT);
+ else{
+ prdelim(" ");
+ prid(tnames[n->type->etype]);
+ if(typesu[n->type->etype] && n->type->tag){
+ prdelim(" ");
+ prid(n->type->tag->name);
+ }
+ }
+ break;
+ case OPROTO:
+ nn = n;
+ t = n->type;
+ n = protoname(n);
+ if(n != Z)
+ t = n->type;
+ else
+ t = prototype(nn->left, t);
+ if(!isvoid(t) || n != Z){
+ if(n == Z)
+ prid("nil");
+ else if(n->op == ODOTDOT){
+ prcom("was ...", Z);
+ break;
+ }
+ else
+ prsym(n->sym, 0);
+ /* egen(n, ONOOP, PRE); */
+ prdelim(": ");
+ tgen(t, 1, 0);
+ }
+ break;
+ case ODOTDOT:
+ prid("...");
+ break;
+ case OINIT:
+ egen(n->left, ONOOP, PRE);
+ break;
+ case OS2AB:
+ prid("libc0->s2ab");
+ prdelim("(");
+ egen(n->left, ONOOP, PRE);
+ prdelim(")");
+ usemod(libcop, 1);
+ break;
+ case OAB2S:
+ prid("libc0->ab2s");
+ prdelim("(");
+ egen(n->left, ONOOP, PRE);
+ prdelim(")");
+ usemod(libcop, 1);
+ break;
+ case OFILDES:
+ prid("sys->fildes");
+ prdelim("(");
+ egen(n->left, ONOOP, PRE);
+ prdelim(")");
+ usemod(sysop, 1);
+ break;
+ case OFD:
+ egen(n->left, op, LEFT);
+ prdelim(ops[op].name);
+ prid("fd");
+ break;
+ case OT0:
+ egen(n->left, op, LEFT);
+ prdelim(ops[op].name);
+ prid("t0");
+ break;
+ case ORETV:
+ n->op = OAS;
+ nn = n->left;
+ p = isvoid(n->type) || n->type->etype != TTUPLE || n->type->mark == TCPC;
+ if(p)
+ n->left = n->right;
+ else
+ n->left = new1(OTUPLE, new1(ONIL, Z, Z), n->right);
+ n->right = nn;
+ n->left->type = n->type;
+ if(!p && op0 != ONOOP)
+ addnode(OT0, n);
+ egen(n, op0, side);
+ break;
+ case OCAT:
+ egen(n->left, op, LEFT);
+ prdelim(" + ");
+ egen(n->right, op, RIGHT);
+ break;
+ }
+ preced(op0, op, side, ')');
+}
+
+static int
+isexpr(Node *n, Type *t)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST || n->op == OINIT || n->op == OSTRUCT)
+ return 0;
+ if(teq(t, n->type))
+ return 1;
+ return 0;
+}
+
+static Node *
+nxtval(Node *n, Node **nn)
+{
+ if(n == Z){
+ *nn = Z;
+ return Z;
+ }
+ if(n->op == OLIST){
+ *nn = n->right;
+ return n->left;
+ }
+ *nn = Z;
+ return n;
+}
+
+static Node*
+eagen(Node *n, Type *t, int ar, int *nz, int depth)
+{
+ int i, w, nw, down;
+ Type *t1;
+ Node *nn, *tn;
+
+ if(n != Z){
+ if(n->type == T && t == T){
+ egen(n, ONOOP, PRE);
+ if(ar){
+ prdelim(",");
+ newline();
+ }
+ return Z;
+ }
+ if(ar && n->op == OLIST && n->left->op == OARRAY){
+ egen(n->left->left, ONOOP, PRE);
+ prdelim(" => ");
+ n = n->right;
+ }
+ if(n->op == OLIST && n->left->op == OELEM){
+ prcom("cannot do ", n->left);
+ n = n->right;
+ }
+ if(n->op == OUSED || n->op == ODOTDOT)
+ n = n->left;
+ if(t == T)
+ t = n->type;
+ }
+ switch(t->etype){
+ case TSTRUCT:
+ case TUNION:
+ if(isexpr(n, t))
+ goto Default;
+ down = 0;
+ tn = nxtval(n, &nn);
+ if(tn != Z && (tn->op == OINIT || tn->op == OSTRUCT)){
+ down = 1;
+ n = tn->left;
+ }
+ if(depth > 0){
+ tgen(t, 0, 0);
+ prdelim(" ");
+ }
+ prdelim("(");
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(n == Z)
+ n = defval(t1);
+ n = eagen(n, t1, 0, nil, depth+1);
+ if(t1->down != T){
+ prdelim(",");
+ if(ar)
+ prdelim("\t");
+ else
+ prdelim(" ");
+ }
+ }
+ prdelim(")");
+ if(down)
+ n = nn;
+ break;
+ case TARRAY:
+ if(isexpr(n, t))
+ goto Default;
+ if(depth > 0){
+ tgen(t, 0, 1);
+ prdelim(" ");
+ }
+ prdelim("{");
+ newline();
+ incind();
+ w = t->width/t->link->width;
+ nw = 0;
+ for(i = 0; i < w; i++){
+ down = 0;
+ tn = nxtval(n, &nn);
+ if(tn != Z && (tn->op == OINIT || tn->op == OSTRUCT)){
+ down = 1;
+ n = tn->left;
+ }
+ n = eagen(n, t->link, 1, &nw, depth+1);
+ if(down)
+ n = nn;
+ }
+ if(nw > 0){
+ if(nw > 1)
+ prdelim("* => ");
+ egen(defval(t->link), ONOOP, PRE);
+ newline();
+ }
+ decind();
+ prdelim("}");
+ break;
+ default:
+Default:
+ if(n == Z){
+ if(ar)
+ (*nz)++;
+ else
+ egen(defval(t), ONOOP, PRE);
+ return Z;
+ }
+ n = nxtval(n, &nn);
+ if(ar && isnil(n) && iscastable(t, types[TINT])){
+ tgen(t, 0, 0);
+ prdelim(" ");
+ }
+ egen(n, ONOOP, PRE);
+ n = nn;
+ break;
+ }
+ if(ar){
+ prdelim(",");
+ newline();
+ }
+ return n;
+}
+
+/* better is
+ * array of byte "abcde\0"
+ * but limbo compiler does not accept this as a constant expression
+ */
+static void
+stob(Node *n)
+{
+ int m;
+ char *s = nil, buf[UTFmax];
+ ushort *u = nil;
+
+ while(n->op == ONAME)
+ n = n->sym->nconst;
+ if(n->op == OSTRING)
+ s = n->cstring;
+ else
+ u = n->rstring;
+ prdelim("{ ");
+ if(s){
+ while(*s){
+ prid("byte ");
+ prchar(*s++);
+ prdelim(", ");
+ }
+ }
+ else{
+ while(*u){
+ m = runetochar(buf, u++);
+ s = buf;
+ while(--m >= 0){
+ prid("byte ");
+ prchar(*s++);
+ prdelim(", ");
+ }
+ }
+ }
+ prid("byte ");
+ prchar('\0');
+ prdelim(" }");
+}
+
+static Type *arrayofchar;
+
+static void
+sdgen(Node *n, int glob)
+{
+ int sop = 0;
+
+ prdelim(" := ");
+ if(glob && n->right->op == OS2AB && isstring(n->right->left)){
+ if(arrayofchar == T){
+ arrayofchar = typ1(TARRAY, types[TCHAR]);
+ arrayofchar->width = 0;
+ }
+ n->type = n->right->type = arrayofchar;
+ sop = 1;
+ }
+ else
+ n->type = n->right->type = T;
+ tgen(n->type, 0, 1);
+ if(sop)
+ stob(n->right->left);
+ else
+ eagen(n->right, n->type, 0, nil, 0);
+ prdelim(";");
+ newline();
+}
+
+static void
+tdgen(Node *n, int glob)
+{
+ int ar, arinit;
+
+ if(ism()){
+ prdelim(": ");
+ tgen(n->type, 1, 0);
+ if(n->op == ODAS)
+ prcom("initial value was ", n->right);
+ prdelim(";");
+ newline();
+ return;
+ }
+ if(n->op == ODAS && (isstring(n->right) || n->right->op == OS2AB)){
+ sdgen(n, glob);
+ return;
+ }
+ ar = n->type->etype == TARRAY && n->type->width != LARR;
+ arinit = ar && n->op == ODAS;
+ if(ar)
+ prdelim(" := ");
+ else
+ prdelim(": ");
+ tgen(n->type, 0, arinit);
+ if(n->op == ODAS){
+ if(!arinit)
+ prdelim(" = ");
+ eagen(n->right, n->type, 0, nil, 0);
+ }
+ prdelim(";");
+ newline();
+}
+
+static int
+isdec(Node *n)
+{
+ return isname(n) && n->kind != KEXP || n->op == ODAS;
+}
+
+static void
+sgen(Node *n, int blk, Node **ln)
+{
+ int comma = 0;
+ Node *nn;
+
+ if(n == Z)
+ return;
+ if(blk){
+ pushscope(n, SAUTO);
+ if(n->op == OLIST && !(blk&NOBR) || (blk&YESBR)){
+ prdelim("{");
+ newline();
+ }
+ else if(!(blk&NONL))
+ newline();
+ if(!(blk&NOIN))
+ incind();
+ }
+ if((nn = *ln) != Z && isdec(nn)){
+ if(isdec(n)){
+ if(canjoin(nn, n))
+ comma = 1;
+ else
+ tdgen(nn, 0);
+ }
+ else if(n->op != OLIST){
+ tdgen(nn, 0);
+ newline();
+ }
+ }
+ if(n->op != OLIST){
+ *ln = n;
+ output(n->lineno, 1);
+ }
+ switch(n->op){
+ default:
+ egen(n, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ break;
+ case ODAS:
+ pushdcl(n->left, CAUTO);
+ egen(n->left, ONOOP, PRE);
+ break;
+ case ONAME:
+ if(n->kind == KEXP){
+ egen(n, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ }
+ else{
+ pushdcl(n, CAUTO);
+ if(comma)
+ prdelim(", ");
+ if(n->op != ONAME)
+ diag(n, "internal: not name in sgen");
+ prsym(n->sym, 0);
+ /* egen(n, ONOOP, PRE); */
+/*
+ prdelim(": ");
+ tgen(n->type, 0, 0, 0);
+ prdelim(";");
+ newline();
+*/
+ }
+ break;
+ case OSBREAK:
+ break;
+ case ONUL:
+ prdelim(";");
+ newline();
+ break;
+ case OBLK:
+ sgen(n->left, 1|YESBR, ln);
+ break;
+ case OLIST:
+ sgen(n->left, 0, ln);
+ sgen(n->right, 0, ln);
+ break;
+ case ORETURN:
+ prkeywd("return");
+ if(n->left != Z)
+ prdelim(" ");
+ egen(n->left, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ break;
+ case OLABEL:
+ prcom("was label ", n->left);
+ /* i = zeroind(); */
+ /* egen(n->left, ONOOP, PRE); */
+ /* prdelim(":"); */
+ newline();
+ /* restoreind(i); */
+ break;
+ case OGOTO:
+ prcom("was goto ", n->left);
+ /* prkeywd("goto "); */
+ /* egen(n->left, ONOOP, PRE); */
+ prdelim(";");
+ newline();
+ break;
+ case OCASE:
+ for(nn = n->left; nn != Z; nn = nn->right){
+ if(nn != n->left)
+ prkeywd(" or ");
+ if(nn->left != Z)
+ egen(nn->left, ONOOP, PRE);
+ else
+ prkeywd("*");
+ }
+ prdelim(" =>");
+ clrbrk(n->right);
+ sgen(n->right, 1|NOBR, ln);
+ if(n->kind != KLAST && !hasbrk(n->right)){
+ prcom("fall through", Z);
+ newline();
+ }
+ break;
+ case OSWITCH:
+ prkeywd("case");
+ egen(n->left, OBRACKET, PRE);
+ sgen(n->right, 1|NOIN|YESBR, ln);
+ break;
+ case OWHILE:
+ prkeywd("while");
+ egen(n->left, OBRACKET, PRE);
+ sgen(n->right, 1, ln);
+ break;
+ case ODWHILE:
+ prkeywd("do");
+ sgen(n->right, 1|NOENL, ln);
+ prkeywd("while");
+ egen(n->left, OBRACKET, PRE);
+ prdelim(";");
+ newline();
+ break;
+ case OFOR:
+ prkeywd("for");
+ prdelim("(");
+ egen(n->left->right->left, ONOOP, PRE);
+ prdelim(";");
+ if(n->left->left != Z)
+ prdelim(" ");
+ egen(n->left->left, ONOOP, PRE);
+ prdelim(";");
+ if(n->left->right->right != Z)
+ prdelim(" ");
+ egen(n->left->right->right, ONOOP, PRE);
+ prdelim(")");
+ sgen(n->right, 1, ln);
+ break;
+ case OCONTINUE:
+ prkeywd("continue");
+ prdelim(";");
+ newline();
+ break;
+ case OBREAK:
+ prkeywd("break");
+ prdelim(";");
+ newline();
+ break;
+ case OIF:
+ prkeywd("if");
+ egen(n->left, OBRACKET, PRE);
+ if(n->right->left->op == OIF && n->right->left->right->right == Z && n->right->right != Z) /* avoid dangling else */
+ sgen(n->right->left, 1|YESBR, ln);
+ else
+ sgen(n->right->left, 1, ln);
+ if(n->right->right != Z){
+ prdelim("else");
+ if(n->right->right->op == OIF){ /* merge else and if */
+ prdelim(" ");
+ sgen(n->right->right, 1|NONL|NOIN, ln);
+ }
+ else
+ sgen(n->right->right, 1, ln);
+ }
+ break;
+ case OSET:
+ case OUSED:
+ prkeywd(ops[n->op].name);
+ lgen(n->left, 1, 1);
+ prdelim(";");
+ newline();
+ break;
+ }
+ if(blk){
+ if(!(blk&NOIN))
+ decind();
+ if(n->op == OLIST&& !(blk&NOBR) || (blk&YESBR)){
+ prdelim("}");
+ if(!(blk&NOENL))
+ newline();
+ }
+ popscope();
+ }
+}
+
+static void rew(Node*, int);
+
+static void
+rewc0(Node *n, Node *r)
+{
+ Node *nn;
+
+ if((nn = cfind(n)) != Z){
+ cgen0(nn, n);
+ if(r->op == ORETURN){
+ n->right->left = new1(ORETURN, n->right->left, Z);
+ n->right->right = new1(ORETURN, n->right->right, Z);
+ n->right->left->type = n->right->left->left->type;
+ n->right->right->type = n->right->right->left->type;
+ *r = *n;
+ }
+ }
+}
+
+static void
+rewc1(Node *n)
+{
+ Node *c, *nc;
+
+ if(n == Z || n->op != OCOND || side(n) || !simple(n))
+ return;
+ c = n->left;
+ nc = new1(ONOT, ncopy(c), Z);
+ n->op = OOROR;
+ n->left = new1(OANDAND, c, n->right->left);
+ n->right = new1(OANDAND, nc, n->right->right);
+}
+
+static void
+rewc(Node *n, Node *r)
+{
+ Node *nn, *rr, *i;
+
+ if((nn = cfind(n)) != Z){
+ i = cgen(nn, n);
+ rr = new1(OXXX, Z, Z);
+ if(n == r && nn == n)
+ *rr = *nn;
+ else
+ *rr = *r;
+ r->op = OLIST;
+ r->left = i;
+ r->right = rr;
+ }
+}
+
+static int
+rewe(Node *n, Type *t, int lev)
+{
+ int op, k, k1, k2;
+ int v;
+ Node *nn;
+
+ if(n == Z)
+ return -1;
+ switch(n->op){
+ case OCONST:
+ break;
+ case ONAME:
+ if(strings || !isstring(n))
+ break;
+ case OSTRING:
+ case OLSTRING:
+ if(!strings)
+ addnode(OS2AB, n);
+ break;
+ case OCOND:
+ bptr(n->left);
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ case OIND:
+ if(isfn(n->type)){
+ *n = *n->left;
+ rewe(n, T, 1);
+ break;
+ }
+ if(!isadt(n->type)){
+ n->op = OARRIND;
+ n->right = con(0);
+ rewe(n, T, 1);
+ break;
+ }
+ rewe(n->left, T, 1);
+ break;
+ case OADDR:
+ if(n->left->op == OARRIND){
+ n->right = n->left;
+ n->left = n->right->left;
+ n->right->left = n->right->right;
+ n->right->right = Z;
+ n->right->op = OLIST;
+ n->op = OSLICE;
+ rewe(n, T, 1);
+ break;
+ }
+ rewe(n->left, T, 1);
+ break;
+ case OSLICE:
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ if(n->left->op == OSLICE){
+ n->right->left = addn(n->left->right->left, n->right->left);
+ n->right->right = addn(n->left->right->left, n->right->right);
+ n->left = n->left->left;
+ rewe(n, T, 1);
+ break;
+ }
+ break;
+ case OCOMMA:
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ if(n->left->op == OAS && n->right->op == OAS){
+ n->op = OAS;
+ n->left->op = n->right->op = OLIST;
+ nn = n->left->right;
+ n->left->right = n->right->left;
+ n->right->left = nn;
+ rewe(n, T, 1);
+ break;
+ }
+ break;
+ case OFUNC:
+ if(n->left->op == ONAME){
+ if((k = n->left->sym->kind) != LNONE){
+ rewlc(n, k, t);
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ args(n);
+ return k;
+ }
+ }
+ else
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ args(n);
+ break;
+ case OCAST:
+ rewe(n->left, n->type, 1);
+ break;
+ case OAS:
+ case OASI:
+ case OASD:
+ rewe(n->left, T, 1);
+ rewe(n->right, n->type, 1);
+ break;
+ case ONOT:
+ case OANDAND:
+ case OOROR:
+ bptr(n);
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ case OPREINC:
+ case OPOSTINC:
+ case OASADD:
+ if(n->op != OPOSTINC || lev == 0){
+ sliceasgn(n);
+ if(n->op == OAS){
+ rewe(n, T, 1);
+ break;
+ }
+ }
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGT:
+ case OGE:
+ k1 = rewe(n->left, T, 1);
+ k2 = rewe(n->right, T, 1);
+ if(k1 == LSTRCMP && n->right->op == OCONST){
+ op = -1;
+ v = n->right->vconst;
+ switch(v){
+ case -1:
+ if(n->op == OEQ)
+ op = OLT;
+ else if(n->op == ONE)
+ op = OGE;
+ break;
+ case 0:
+ op = n->op;
+ break;
+ case 1:
+ if(n->op == OEQ)
+ op = OGT;
+ else if(n->op == ONE)
+ op = OLE;
+ break;
+ }
+ if(op != -1){
+ *n = *n->left;
+ n->op = op;
+ }
+ }
+ if(k2 == LSTRCMP && n->left->op == OCONST){
+ op = -1;
+ v = n->left->vconst;
+ switch(v){
+ case -1:
+ if(n->op == OEQ)
+ op = OLT;
+ else if(n->op == ONE)
+ op = OGE;
+ break;
+ case 0:
+ op = rev(n->op);
+ break;
+ case 1:
+ if(n->op == OEQ)
+ op = OGT;
+ else if(n->op == ONE)
+ op = OLE;
+ break;
+ }
+ if(op != -1){
+ *n = *n->right;
+ n->op = op;
+ }
+ }
+ break;
+ default:
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ }
+ return -1;
+}
+
+/*
+static void
+rewf(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ case OFUNC:
+ if(n->left->op == ONAME)
+ fdargs(n);
+ break;
+ default:
+ rewf(n->left);
+ rewf(n->right);
+ break;
+ }
+}
+*/
+
+static void
+rew(Node *n, int blk)
+{
+ int i;
+ Node *a, *nn;
+
+ if(n == Z)
+ return;
+ if(blk)
+ pushscope(n, SAUTO);
+ nearln = n->lineno;
+ if(n->blk){
+ n->blk = 0;
+ addnode(OBLK, n);
+ }
+ switch(n->op){
+ default:
+ if(simple(n))
+ rewc0(n, n);
+ else
+ rewc(n, n);
+ if(n->op == OLIST || n->op == OIF){
+ rew(n, 0);
+ break;
+ }
+ ecomplex(n);
+ break;
+ case ODAS:
+ pushdcl(n->left, CAUTO);
+ rewe(n->right, T, 1);
+ break;
+ case OSBREAK:
+ case ONUL:
+ break;
+ case ONAME:
+ if(n->kind == KEXP)
+ ecomplex(n);
+ else
+ pushdcl(n, CAUTO);
+ break;
+ case OBLK:
+ rew(n->left, 1);
+ break;
+ case OLIST:
+ rew(n->left, 0);
+ rew(n->right, 0);
+ break;
+ case ORETURN:
+ if(simple(n->left))
+ rewc0(n->left, n);
+ else
+ rewc(n->left, n);
+ if(n->op != ORETURN){
+ rew(n, 0);
+ break;
+ }
+ ecomplex(n);
+ break;
+ case OLABEL:
+ case OGOTO:
+ break;
+ case OCASE:
+ for(nn = n->left; nn != Z; nn = nn->right)
+ if(nn->left != Z)
+ ecomplex(nn->left);
+ rew(n->right, 1);
+ break;
+ case OSWITCH:
+ rewc(n->left, n);
+ if(n->op == OLIST){
+ rew(n, 0);
+ break;
+ }
+ ecomplex(n->left);
+ if(!lteq(n->left->type, types[TINT]))
+ intcast(n->left);
+ n->right = buildcases(n->right);
+ rew(n->right, 1);
+ break;
+ case OWHILE:
+ case ODWHILE:
+ rewc1(n->left);
+ becomplex(n->left);
+ rew(n->right, 1);
+ break;
+ case OFOR:
+ rewc1(n->left->left);
+ rewc(n->left->right->left, n);
+ if(n->op == OLIST){
+ rew(n, 0);
+ break;
+ }
+ becomplex(n->left->left);
+ ecomplex(n->left->right->left);
+ ecomplex(n->left->right->right);
+ rew(n->right, 1);
+ break;
+ case OCONTINUE:
+ break;
+ case OBREAK:
+ break;
+ case OIF:
+ rewc1(n->left);
+ rewc(n->left, n);
+ if(n->op == OLIST){
+ rew(n, 0);
+ break;
+ }
+ becomplex(n->left);
+ rew(n->right->left, 1);
+ rew(n->right->right, 1);
+ break;
+ case OSET:
+ if(n->left == Z){
+ n->op = ONUL;
+ n->left = n->right = Z;
+ break;
+ }
+ if(n->left->op != OLIST){
+ n->op = OAS;
+ n->right = defval(n->left->type);
+ rew(n, 0);
+ break;
+ }
+ i = 0;
+ nn = Z;
+ for(;;){
+ a = arg(n->left, i);
+ if(a == Z)
+ break;
+ a = new1(OAS, a, defval(a->type));
+ if(i == 0)
+ nn = a;
+ else
+ nn = new1(OLIST, nn, a);
+ i++;
+ }
+ *n = *nn;
+ rew(n, 0);
+ break;
+ case OUSED:
+ if(n->left == Z){
+ n->op = ONUL;
+ n->left = n->right = Z;
+ break;
+ }
+ i = 0;
+ nn = Z;
+ for(;;){
+ a = arg(n->left, i);
+ if(a == Z)
+ break;
+ if(i == 0)
+ nn = a;
+ else
+ nn = new1(OOROR, nn, a);
+ i++;
+ }
+ n->op = OIF;
+ n->left = nn;
+ n->right = new1(OLIST, Z, Z);
+ n->right->left = new1(ONUL, Z, Z);
+ rew(n, 0);
+ break;
+ }
+ if(blk)
+ popscope();
+}
+
+void
+codgen2(Node *n, Node *nn, int lastlno, int rw)
+{
+ Node *ln = Z;
+
+ newsec(0);
+ output(nn->lineno, 1);
+ tmp = 0;
+ /* t = types[TVOID]; */
+ nn = func(nn);
+ pushscope(nn, SPARM);
+ if(rw)
+ rew(n, 1);
+ egen(nn, ONOOP, PRE);
+ newline();
+ prdelim("{");
+ newline();
+ incind();
+ /* rewf(n); */
+ pushscope(n, SAUTO);
+ sgen(n, 0, &ln);
+ if(ln != Z && isdec(ln))
+ tdgen(ln, 0);
+ popscope();
+ popscope();
+ if(n != Z)
+ output(lline(n), 1);
+ output(lastlno, 1);
+ decind();
+ prdelim("}");
+ newline();
+ newline();
+ setmain(nn);
+}
+
+void
+rewall(Node *n, Node *nn, int lastlno)
+{
+ USED(lastlno);
+ tmp = 0;
+ nn = func(nn);
+ pushscope(nn, SPARM);
+ rew(n, 1);
+ popscope();
+ setmain(nn);
+}
+
+void
+suball(Node *n, Node *nn)
+{
+ Node *rn;
+
+ nn = func(nn);
+ pushscope(nn, SPARM);
+ subs(nn, 0, 0);
+ subs(n, 1, 1);
+ nn = lastn(n);
+ if(nn != Z && nn->op != ORETURN){
+ rn = retval(Z);
+ if(rn != Z){
+ addnode(OLIST, nn);
+ nn->right = rn;
+ }
+ }
+ popscope();
+}
+
+void
+ginit(void)
+{
+ thechar = 'o';
+ thestring = "386";
+ tfield = types[TLONG];
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael2);
+ o = align(o, t, Ael1);
+ w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
+ break;
+ }
+ o = round(o, w);
+ if(0)
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v = round(v, SZ_LONG);
+ if(v > max)
+ return v;
+ return max;
+}
+
+static int
+nlen(Node *n)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST)
+ return nlen(n->left)+nlen(n->right);
+ return 1;
+}
+
+static void
+flatten(Node *n, Node **a, int *i)
+{
+ if(n == Z)
+ return;
+ if(n->op == OLIST){
+ flatten(n->left, a, i);
+ flatten(n->right, a, i);
+ free(n);
+ return;
+ }
+ a[(*i)++] = n;
+}
+
+static Node*
+addcase(Node *n, Node **e, Node **s, int k)
+{
+ Node *nn;
+
+ if(*e != Z){
+ nn = new1(OCASE, *e, *s);
+ nn->right->blk = 0;
+ nn->kind = k;
+ }
+ else
+ nn = *s;
+ *e = *s = Z;
+ if(n == Z)
+ return nn;
+ return new1(OLIST, n, nn);
+}
+
+/* collect case code together */
+static Node*
+buildcases(Node *n)
+{
+ int i, m, m0, c;
+ Node *e, *s, *nn, **a, **ep;
+
+ m = nlen(n);
+ a = (Node **)malloc(m*sizeof(Node*));
+ m0 = 0;
+ flatten(n, a, &m0);
+ if(m != m0)
+ diag(Z, "internal: bad buildcases()");
+ c = 1;
+ e = s = nn = Z;
+ ep = &e;
+ for(i = 0; i < m; i++){
+ n = a[i];
+ if(n->op == OCASE){
+ if(!c){
+ nn = addcase(nn, &e, &s, KNIL);
+ ep = &e;
+ }
+ *ep = new1(OLIST, n->left, Z);
+ if(n->left == Z)
+ (*ep)->lineno = n->lineno;
+ ep = &(*ep)->right;
+ c = 1;
+ }
+ else{
+ if(s == Z)
+ s = n;
+ else
+ s = new1(OLIST, s, n);
+ c = 0;
+ }
+ }
+ nn = addcase(nn, &e, &s, KLAST);
+ free(a);
+ return nn;
+}
+
+static Sym *
+tmpgen(Type *t)
+{
+ Sym *s;
+
+ sprint(buf, "tmp_%d", ++tmp);
+ s = slookup(buf);
+ s->type = t;
+ s->class = CAUTO;
+ if(t->etype == TENUM)
+ s->type = types[TINT];
+ return s;
+}
+
+static Node*
+cfind(Node *n)
+{
+ Node *nn;
+
+ if(n == Z)
+ return Z;
+ if(n->op == OCOND)
+ return n;
+ nn = cfind(n->left);
+ if(nn != Z)
+ return nn;
+ return cfind(n->right);
+}
+
+Node*
+ncopy(Node *n)
+{
+ Node *nn;
+
+ if(n == Z)
+ return Z;
+ nn = new1(n->op, Z, Z);
+ *nn = *n;
+ nn->left = ncopy(n->left);
+ nn->right = ncopy(n->right);
+ return nn;
+}
+
+static int
+complexity(Node *n, int *cond)
+{
+ int c;
+
+ if(n == Z)
+ return 0;
+ c = complexity(n->left, cond)+1+complexity(n->right, cond);
+ if(n->op == OCOND)
+ (*cond)++;
+ return c;
+}
+
+static int
+simple(Node *n)
+{
+ int c;
+
+ c = 0;
+ return complexity(n, &c) < COMPLEX && c <= 1;
+}
+
+static Type*
+intype(Node *n)
+{
+ Type *t;
+
+ t = ntype(n);
+ if(t == T)
+ return T;
+ return t->link;
+}
+
+static Type*
+ntype(Node *n)
+{
+ Type *t;
+
+ if(n == Z)
+ return T;
+ t = n->type;
+ if(t != T){
+ if(t->etype == TENUM)
+ return n->sym->tenum;
+ return t;
+ }
+ switch(n->op){
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case ONOT:
+ case OANDAND:
+ case OOROR:
+ case OIOTA:
+ return types[TINT];
+ case OCOMMA:
+ return ntype(n->right);
+ case OCOND:
+ return maxtype(ntype(n->right->left), ntype(n->right->right));
+ case OFUNC:
+ return intype(n->left);
+ case ODOT:
+ tcomd(n, ntype(n->left));
+ t = n->type;
+ n->type = T;
+ return t;
+ case ODOTIND:
+ tcomd(n, intype(n->left));
+ t = n->type;
+ n->type = T;
+ return t;
+ case OARRIND:
+ return intype(n->left);
+ case OADDR:
+ return typ1(TIND, ntype(n->left));
+ case OIND:
+ return intype(n->left);
+ case OSTRUCT:
+ return T;
+ }
+ return maxtype(ntype(n->left), ntype(n->right));
+}
+
+static Type*
+gettype(Node *n1, Node *n2)
+{
+ Type *t;
+
+ t = maxtype(n1->type, n2->type);
+ if(t != T)
+ return t;
+ return maxtype(ntype(n1), ntype(n2));
+}
+
+static void
+cgen0(Node *n, Node *e)
+{
+ Node *c, *nn, *ed, *ee;
+
+ if(n == e){
+ n->op = OIF;
+ return;
+ }
+ c = n->left;
+ ed = new1(OXXX, Z, Z);
+ *ed = *e;
+ ee = ncopy(e);
+ nn = cfind(ee);
+ *n = *n->right->left;
+ *nn = *nn->right->right;
+ e->op = OIF;
+ e->left = c;
+ e->right = new1(OLIST, ed, ee);
+}
+
+static Node*
+cgen(Node *n, Node *e)
+{
+ Type *t;
+ Node *tn, *i;
+
+ USED(e);
+ tn = new1(ONAME, Z, Z);
+ t = gettype(n->right->left, n->right->right);
+ tn->sym = tmpgen(t);
+ tn->type = tn->sym->type;
+/*
+ if(n == e){
+ n->op = OIF;
+ n->right->left = new1(OASD, tn, n->right->left);
+ n->right->right = new1(OAS, tn, n->right->right);
+ return n;
+ }
+*/
+ i = new1(OIF, n->left, new1(OLIST, new1(OASD, tn, n->right->left), new1(OAS, tn, n->right->right)));
+ *n = *tn;
+ return i;
+}
+
+static struct{
+ char *name;
+ int args;
+ int fd;
+ char *lname;
+} sysops[] = {
+ "create", 1, RET, nil,
+ "dirstat", 1, 0, "stat",
+ "dirfstat", 0, 1, "fstat",
+ "dirwstat", 1, 0, "wstat",
+ "dirfwstat", 0, 1, "fwstat",
+ "dirread", 0, 1, nil,
+ "dup", 0, 0, nil,
+ "fprint", 2|STAR, 1, nil,
+ "fprintf", 2|STAR, 1, "fprint",
+ "open", 1, RET, nil,
+ "print", 1|STAR, 0, nil,
+ "printf", 1|STAR, 0, "print",
+ "read", 0, 1, nil,
+ "remove", 1, 0, nil,
+ "seek", 0, 1, nil,
+ "sleep", 0, 0, nil,
+ "sprint", 1|STAR, 0, nil,
+ "sprintf", 1|STAR, 0, "sprint",
+ "write", 0, 1, nil,
+ 0
+};
+
+/* dummy entry for module */
+#define BIOTMP "__bio__"
+
+static struct{
+ char *name;
+ char *lname;
+} bioops[] = {
+ "Bflush", "flush",
+ "Bgetc", "getc",
+ "Bprint", "puts",
+ "Bputc", "putc",
+ "Bread", "read",
+ "Bseek", "seek",
+ "Bungetc", "ungetc",
+ "Bwrite", "write",
+ BIOTMP, nil,
+ 0
+};
+
+char *libcops[] = {
+ "isalnum",
+ "isalpha",
+ "isascii",
+ "iscntrl",
+ "isdigit",
+ "isgraph",
+ "islower",
+ "isprint",
+ "ispunct",
+ "isspace",
+ "isupper",
+ "isxdigit",
+ "strchr",
+ "strrchr",
+ "toascii",
+ "tolower",
+ "toupper",
+ "abs",
+ "min",
+ "max",
+ 0,
+};
+
+static struct{
+ char *name;
+ int type;
+ int string;
+} xops[] = {
+ "strlen", LSTRLEN, 1,
+ "strcmp", LSTRCMP, 1,
+ "strcpy", LSTRCPY, 1,
+ "strcat", LSTRCAT, 1,
+ "strncmp", LSTRNCMP, 1,
+ "strncpy", LSTRNCPY, 1,
+ "strncat", LSTRNCAT, 1,
+ "strdup", LSTRDUP, 1,
+ "memcpy", LMEMMOVE, 0,
+ "memmove", LMEMMOVE, 0,
+ "malloc", LMALLOC, 0,
+ "free", LFREE, 0,
+ "exit", LEXIT, 0,
+ "exits", LEXIT, 0,
+ "close", LCLOSE, 0,
+ "atoi", LATOI, 0,
+ "atol", LATOI, 0,
+ "atoll", LATOL, 0,
+ "atof", LATOF, 0,
+ "atod", LATOF, 0,
+ "print", LPRINT, 0,
+ "printf", LPRINT, 0,
+ "fprint", LFPRINT, 0,
+ "fprintf", LFPRINT, 0,
+ "sprint", LSPRINT, 0,
+ "sprintf", LSPRINT, 0,
+ 0
+};
+
+char *mathsops[] = {
+ "sin",
+ "cos",
+ "tan",
+ "sinh",
+ "cosh",
+ "tanh",
+ "asin",
+ "acos",
+ "atan",
+ "asinh",
+ "acosh",
+ "atanh",
+ "atan2",
+ "sqrt",
+ "cbrt",
+ "pow",
+ "pow10",
+ "exp",
+ "log",
+ "log10",
+ 0
+};
+
+Node *glob, *globe;
+
+void
+sysinit(void)
+{
+ int i;
+ Sym *s;
+
+ glob = globe = new1(ONOOP, Z, Z);
+ for(i = 0; sysops[i].name; i++){
+ s = slookup(sysops[i].name);
+ s->class = CEXTERN;
+ s->args = sysops[i].args;
+ s->fd = sysops[i].fd;
+ s->mod = "sys";
+ s->lname = sysops[i].lname;
+ s->limbo = 1;
+ sysop = s;
+ }
+ for(i = 0; bioops[i].name; i++){
+ s = slookup(bioops[i].name);
+ s->class = CEXTERN;
+ if(strcmp(bioops[i].name, BIOTMP) == 0){
+ s->mod = "bufio";
+ bioop = s;
+ }
+ s->lname = bioops[i].lname;
+ s->kind = LSELF;
+ s->limbo = 1;
+ }
+ for(i = 0; mathsops[i]; i++){
+ s = slookup(mathsops[i]);
+ s->class = CEXTERN;
+ s->mod = "math";
+ s->limbo = 1;
+ }
+ for(i = 0; libcops[i]; i++){
+ s = slookup(libcops[i]);
+ s->class = CEXTERN;
+ s->mod = strings ? "libc" : "libc0";
+ s->limbo = 1;
+ libcop = s;
+ }
+ for(i = 0; xops[i].name; i++){
+ s = slookup(xops[i].name);
+ s->class = CEXTERN;
+ if(strings || !xops[i].string)
+ s->kind = xops[i].type;
+ else
+ s->mod = "libc0";
+ if(s->kind == LEXIT)
+ s->lname = "exit";
+ s->limbo = 1;
+ }
+ usemod(sysop, 1);
+ if(!strings)
+ usemod(libcop, 1);
+}
+
+void
+clbegin(void)
+{
+ pushscope(glob, SGLOB);
+}
+
+void
+clend(void)
+{
+ if(passes)
+ swalk();
+ popscope();
+}
+
+static Modl *mods;
+
+void
+usemod(Sym *s, int ld)
+{
+ Modl *ml;
+
+ for(ml = mods; ml != nil; ml = ml->nxt)
+ if(strcmp(ml->mod, s->mod) == 0){
+ ml->ld |= ld;
+ return;
+ }
+ ml = (Modl *)malloc(sizeof(Modl));
+ ml->mod = s->mod;
+ ml->ld = ld;
+ ml->nxt = mods;
+ mods = ml;
+}
+
+static void
+ginc(Modl *ml)
+{
+ int c;
+ char *s;
+
+ if(ml == nil)
+ return;
+ if(ml->nxt != nil)
+ ginc(ml->nxt);
+ s = ml->mod;
+ c = toupper(s[0]);
+ sprint(buf, "include \"%s.m\";", s);
+ prline(buf);
+ if(ml->ld){
+ sprint(buf, " %s: %c%s;", s, c, s+1);
+ prline(buf);
+ }
+}
+
+static void
+gload(Modl *ml)
+{
+ int c;
+ char *s;
+
+ if(ml == nil)
+ return;
+ if(ml->nxt != nil)
+ gload(ml->nxt);
+ if(ml->ld){
+ s = ml->mod;
+ c = toupper(s[0]);
+ sprint(buf, " %s = load %c%s %c%s->PATH;", s, c, s+1, c, s+1);
+ prline(buf);
+ }
+}
+
+static void
+callmain(void)
+{
+ if(inmain){
+ if(strings)
+ prline(" main(len argl, argl);");
+ else
+ prline(" main(len argl, libc0->ls2aab(argl));");
+ }
+}
+
+static void
+genstart(void)
+{
+ char *s;
+
+ if(!strings && inmain)
+ usemod(libcop, 1);
+ ginc(mods);
+ s = hasm();
+ if(s){
+ sprint(buf, "include \"%s\";", s);
+ prline(buf);
+ }
+ prline("");
+ prline("init(nil: ref Draw->Context, argl: list of string)");
+ prline("{");
+ gload(mods);
+ callmain();
+ prline("}");
+ prline("");
+}
+
+static int
+argpos0(Node *nn, Node *n, int *p)
+{
+ int pp;
+
+ if(n == Z)
+ return -1;
+ if(n->op == OLIST){
+ pp = argpos0(nn, n->left, p);
+ if(pp >= 0)
+ return pp;
+ return argpos0(nn, n->right, p);
+ }
+ if(n == nn)
+ return *p;
+ (*p)++;
+ return -1;
+}
+
+static int
+argpos(Node *nn, Node *n)
+{
+ int p = 0;
+
+ p = argpos0(nn, n, &p);
+ if(p < 0)
+ diag(Z, "-ve argpos");
+ return p;
+}
+
+static Node*
+arg0(Node *n, int a, int *i)
+{
+ Node *nn;
+
+ if(n == Z)
+ return Z;
+ if(n->op == OLIST){
+ nn = arg0(n->left, a, i);
+ if(nn != Z)
+ return nn;
+ return arg0(n->right, a, i);
+ }
+ if(a == (*i)++)
+ return n;
+ return Z;
+}
+
+static Node*
+arg(Node *n, int a)
+{
+ int i = 0;
+
+ return arg0(n, a, &i);
+}
+
+static Node*
+list(Node *l, Node *r)
+{
+ if(r == Z)
+ return l;
+ if(l == Z)
+ return r;
+ return new1(OLIST, l, r);
+}
+
+static Node*
+droparg(Node *n, int a, int *i)
+{
+ if(n == Z)
+ return Z;
+ if(n->op == OLIST)
+ return list(droparg(n->left, a, i), droparg(n->right, a, i));
+ if(a == (*i)++)
+ return Z;
+ return n;
+}
+
+static void
+sargs(Node *n)
+{
+ int s, f, i, j;
+ Node *a;
+
+ if(strings || (f = n->left->sym->args) == 0)
+ return;
+ s = 0;
+ for(i = 1, j = 0; i < STAR || s; i *= 2, j++){
+ if(f&i || s){
+ a = arg(n->right, j);
+ if(a == Z)
+ break;
+ if(s && !isstr(a->type))
+ continue;
+ if(f&STAR)
+ s++;
+ if(a->op == OS2AB){
+ *a = *a->left;
+ continue;
+ }
+ addnode(OAB2S, a);
+ }
+ }
+}
+
+static void
+fdargs(Node *n)
+{
+ int f, i, j;
+ Node *a;
+
+ if((f = n->left->sym->fd) == 0)
+ return;
+ marktype(pfdtype, TCFD);
+ if(f&RET)
+ tcon(n, pfdtype);
+ for(i = 1, j = 0; i < RET; i *= 2, j++){
+ if(f&i){
+ a = arg(n->right, j);
+ if(a == Z)
+ break;
+ tcon(a, pfdtype);
+ }
+ }
+}
+
+static void
+aargs(Node *n)
+{
+ int i;
+ Node *a, *nn, *fn;
+ Type *t, *t0, *ft, *at, *st;
+
+ if(!doaddr)
+ return;
+ if(n->op != OFUNC || n->left->op != ONAME)
+ return;
+ /* ft = n->left->type; */
+ ft = n->left->sym->type;
+ t = t0 = ft->link;
+ nn = Z;
+ for(i = 0; ; i++){
+ a = arg(n->right, i);
+ if(a == Z)
+ break;
+ at = typn(ft, i);
+ if(at != T && at->etype != TDOT && (a->op == OADDR || iteq(a->type, at) || iteq(at, a->type))){
+ if(iteq(at, a->type))
+ st = at->link;
+ else
+ st = a->type->link;
+ if(doalladdr || isscalar(st)){
+ if(a->op == OADDR)
+ *a = *a->left;
+ else if(iteq(a->type, at))
+ a->type = at;
+ if(t->mark == 0){
+ t = tuple(t, a->type);
+ trep(at, at->link);
+ fn = finddec(n->left->sym, 1);
+ if(fn != Z && fn->op == OFUNC)
+ tind(arg(fn->right, i));
+ }
+ if(nn == Z)
+ nn = cknil(ncopy(a));
+ else{
+ nn = new1(OTUPLE, nn, cknil(ncopy(a)));
+ nn->type = t;
+ }
+ }
+ }
+ }
+ if(nn != Z){
+ if(isvoid(t0) || t->mark == TCPC)
+ marktype(t, TCPC);
+ else
+ marktype(t, TCFC);
+ tcon(n, t);
+ addnode(ORETV, n);
+ n->right = nn;
+ }
+}
+
+static void
+args(Node *n)
+{
+ if(n->op != OFUNC || n->left->op != ONAME)
+ return;
+ sargs(n);
+ if(passes){
+ fdargs(n);
+ aargs(n);
+ }
+}
+
+static Node*
+indir(Node *n)
+{
+ if(n->op == OADDR)
+ return n->left;
+ return new1(OIND, n, Z);
+}
+
+static void
+rewlc(Node *n, int k, Type *t)
+{
+ int i;
+ Type *tt;
+ Node *a0, *a1, *a2, *nn;
+
+ if(t == T)
+ t = n->type;
+ a0 = arg(n->right, 0);
+ a1 = arg(n->right, 1);
+ switch(k){
+ case LSTRLEN:
+ n->op = OLEN;
+ break;
+ case LSTRCMP:
+ n->op = ONE;
+ n->left = a0;
+ n->right = a1;
+ break;
+ case LSTRCPY:
+ n->op = OAS;
+ n->left = a0;
+ n->right = a1;
+ n->type = n->left->type;
+ break;
+ case LSTRCAT:
+ n->op = OASADD;
+ n->left = a0;
+ n->right = a1;
+ n->type = n->left->type;
+ break;
+ case LSTRDUP:
+ *n = *a0;
+ break;
+ case LMEMMOVE:
+ if(!teq(a0->type, a1->type))
+ break;
+ if(a0->type->etype == TIND){
+ tt = a0->type->link;
+ a2 = arg(n->right, 2);
+ if(isadt(tt) && isconst(a2, tt->width)){
+ n->op = OAS;
+ n->left = indir(a0);
+ n->right = indir(a1);
+ n->type = n->left->type = n->right->type = tt;
+ break;
+ }
+ if(mydiv(a2, tt->width) != Z){
+ n->op = OAS;
+ n->left = new1(OSLICE, a0, new1(OLIST, con(0), Z));
+ n->right = new1(OSLICE, a1, new1(OLIST, con(0), a2));
+ n->type = n->left->type = n->right->type = a0->type;
+ }
+ }
+ break;
+ case LMALLOC:
+ if(t->etype == TIND){
+ tt = t->link;
+ if(isadt(tt) && isconst(a0, tt->width)){
+ n->op = OREF;
+ n->left = Z;
+ n->right = Z;
+ n->type = t;
+ break;
+ }
+ if(mydiv(a0, tt->width) != Z){
+ n->op = OARRAYOF;
+ n->left = a0;
+ n->right = Z;
+ n->type = t;
+ if(isadt(tt)){
+ n->type = typ1(TARRAY, tt);
+ n->type->width = LARR; /* limbo array without bounds */
+ marktype(n->type, TCAR);
+ }
+ }
+ }
+ break;
+ case LFREE:
+ n->op = OAS;
+ n->left = a0;
+ n->right = con(0);
+ n->type = n->left->type;
+ n->right->type = n->type;
+ break;
+ case LEXIT:
+ i = n->kind;
+ *n = *n->left;
+ n->kind = i;
+ break;
+ case LCLOSE:
+ n->op = OAS;
+ n->left = a0;
+ n->right = con(0);
+ n->left->type = typ1(TIND, n->left->type);
+ n->type = n->left->type;
+ n->right->type = n->type;
+ break;
+ case LATOI:
+ if(!strings)
+ strcast(a0);
+ n->op = OCAST;
+ n->left = a0;
+ n->right = Z;
+ n->type = types[TINT];
+ break;
+ case LATOL:
+ if(!strings)
+ strcast(a0);
+ n->op = OCAST;
+ n->left = a0;
+ n->right = Z;
+ n->type = types[TVLONG];
+ break;
+ case LATOF:
+ if(!strings)
+ strcast(a0);
+ n->op = OCAST;
+ n->left = a0;
+ n->right = Z;
+ n->type = types[TDOUBLE];
+ break;
+ case LPRINT:
+ if(a0->op == OSTRING)
+ pfmt(a0->cstring);
+ else if(a0->op == OLSTRING)
+ lpfmt(a0->rstring);
+ break;
+ case LFPRINT:
+ if(a1->op == OSTRING)
+ pfmt(a1->cstring);
+ else if(a1->op == OLSTRING)
+ lpfmt(a1->rstring);
+ break;
+ case LSPRINT:
+ if(n->right->kind != KDROP){
+ if(a1->op == OSTRING)
+ pfmt(a1->cstring);
+ else if(a1->op == OLSTRING)
+ lpfmt(a1->rstring);
+ nn = new1(OXXX, Z, Z);
+ *nn = *n;
+ i = 0;
+ nn->right = droparg(nn->right, 0, &i);
+ nn->right->kind = KDROP;
+ n->op = OAS;
+ n->left = a0;
+ n->right = nn;
+ n->type = nn->type;
+ }
+ break;
+ case LSELF:
+ if(n->right != Z && n->right->kind != KDROP){
+ i = 0;
+ n->right = droparg(n->right, 0, &i);
+ if(n->right != Z)
+ n->right->kind = KDROP;
+ addnode(OLDOT, n->left);
+ n->left->right = n->left->left;
+ n->left->left = a0;
+ usemod(bioop, 1);
+ }
+ break;
+ }
+}
+
+void
+expgen(Node *n)
+{
+ egen(n, ONOOP, PRE);
+}
+
+static void
+clrbrk(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ case OLIST:
+ clrbrk(n->right);
+ break;
+ case OBREAK:
+ n->op = OSBREAK;
+ n->left = n->right = Z;
+ break;
+ }
+}
+
+static int
+hasbrk(Node *n)
+{
+ if(n == Z)
+ return 0;
+ switch(n->op){
+ case OLIST:
+ case OWHILE:
+ case ODWHILE:
+ case OFOR:
+ return hasbrk(n->right);
+ case OIF:
+ if(n->right->right == Z)
+ return 0;
+ return hasbrk(n->right->left) && hasbrk(n->right->right);
+ case ORETURN:
+ case OGOTO:
+ case OCONTINUE:
+ case OBREAK:
+ case OSBREAK:
+ return 1;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int
+isgen(char *s)
+{
+ char *s1, *s2;
+
+ s1 = strchr(s, '_');
+ s2 = strrchr(s, '_');
+ if(s1 == nil || s2-s1 != 4)
+ return 0;
+ return s1[1] == 'a' && s1[2] == 'd' && s1[3] == 't';
+}
+
+static void
+addmodn(Sym *s)
+{
+ char buf[128], *ns;
+
+ if(s->name[0] == '_'){
+ outmod(buf, -1);
+ ns = malloc(strlen(buf)+strlen(s->name)+1);
+ strcpy(ns, buf);
+ strcat(ns, s->name);
+ s->name = ns;
+ }
+}
+
+static void
+pfmt(char *s)
+{
+ char *t = s;
+
+ while(*s != '\0'){
+ if(*s == '%'){
+ *t++ = *s++;
+ if(*s == 'l'){
+ s++;
+ if(*s == 'l')
+ *t++ = 'b';
+ else
+ *t++ = *s;
+ s++;
+ }
+ else if(*s == 'p'){
+ *t++ = 'x';
+ s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ *t = '\0';
+}
+
+static void
+lpfmt(ushort *s)
+{
+ ushort*t = s;
+
+ while(*s != '\0'){
+ if(*s == '%'){
+ *t++ = *s++;
+ if(*s == 'l'){
+ s++;
+ if(*s == 'l')
+ *t++ = 'b';
+ else
+ *t++ = *s;
+ s++;
+ }
+ else if(*s == 'p'){
+ *t++ = 'x';
+ s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ *t = '\0';
+}
+
+int
+line(Node *n)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST)
+ return line(n->left);
+ return n->lineno;
+}
+
+static int
+lline(Node *n)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST)
+ return lline(n->right);
+ return n->lineno+1;
+}
+
+static Node*
+lastn(Node *n)
+{
+ while(n != Z && n->op == OLIST)
+ n = n->right;
+ return n;
+}
+
+static Node*
+newnode(int op, Node *l)
+{
+ Node *n;
+
+ n = new1(op, l, Z);
+ globe->right = n;
+ globe = n;
+ return n;
+}
+
+void
+codgen1(Node *n, Node *nn, int lastlno)
+{
+ Node *nnn;
+
+ scomplex(n);
+ nnn = newnode(OCODE, new1(OLIST, n, nn));
+ nnn->lineno = lastlno;
+ mset(n);
+ mset(nn);
+ nn = func(nn);
+ newnode(ODECF, nn);
+ setmain(nn);
+}
+
+void
+vtgen1(Node *n)
+{
+ int c;
+ Node *nn = n;
+
+ if(n->op == ODAS)
+ nn = n->left;
+ if(nn->type == T || nn->sym == S)
+ return;
+ c = nn->sym->class;
+ if(c == CGLOBL || c == CSTATIC || c == CLOCAL || c == CEXREG){
+ newnode(ODECV, n);
+ if(nn->type->etype != TFUNC || ism())
+ setmod(nn->sym);
+ }
+ mset(n);
+}
+
+void
+etgen1(Sym *s)
+{
+ Node *n;
+
+ n = newnode(ODECE, Z);
+ n->sym = s;
+ if(s != S)
+ setmod(s);
+}
+
+void
+ttgen1(Type *t)
+{
+ Node *n;
+
+ n = newnode(ODECT, Z);
+ n->type = t;
+ if(isadt(t))
+ setmod(suename(t));
+}
+
+void
+outpush1(char *s)
+{
+ Node *n;
+ char *t;
+
+ n = newnode(OPUSH, Z);
+ if(s == nil)
+ t = nil;
+ else{
+ t = malloc(strlen(s)+1);
+ strcpy(t, s);
+ }
+ n->cstring = t;
+ outpush0(s, n);
+}
+
+void
+outpop1(int lno)
+{
+ Node *n;
+
+ n = newnode(OPOP, Z);
+ n->lineno = lno;
+ outpop0(lno);
+}
+
+void
+codgen(Node *n, Node *nn, int lastlno)
+{
+ if(passes)
+ codgen1(n, nn, lastlno);
+ else
+ codgen2(n, nn, lastlno, 1);
+}
+
+void
+vtgen(Node *n)
+{
+ if(passes)
+ vtgen1(n);
+ else
+ vtgen2(n);
+}
+
+void
+etgen(Sym *s)
+{
+ if(passes)
+ etgen1(s);
+ else
+ etgen2(s);
+}
+
+void
+ttgen(Type *t)
+{
+ if(passes)
+ ttgen1(t);
+ else
+ ttgen2(t);
+}
+
+void
+outpush(char *s)
+{
+ if(passes)
+ outpush1(s);
+ else
+ outpush2(s, Z);
+}
+
+void
+outpop(int lno)
+{
+ if(passes)
+ outpop1(lno);
+ else
+ outpop2(lno);
+}
+
+static void
+swalk(void)
+{
+ Node *n, *l;
+
+ for(n = glob; n != Z; n = n->right){
+ l = n->left;
+ switch(n->op){
+ case OCODE:
+ rewall(l->left, l->right, n->lineno);
+ break;
+ default:
+ break;
+ }
+ }
+ while(again){
+ again = 0;
+ for(n = glob; n != Z; n = n->right){
+ l = n->left;
+ switch(n->op){
+ case OCODE:
+ suball(l->left, l->right);
+ break;
+ case ODECV:
+ subs(l, 0, 0);
+ break;
+ case ODECE:
+ case ODECT:
+ case ODECF:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ for(n = glob; n != Z; n = n->right){
+ l = n->left;
+ switch(n->op){
+ case ONOOP:
+ break;
+ case OPUSH:
+ outpush2(n->cstring, n);
+ break;
+ case OPOP:
+ outpop2(n->lineno);
+ break;
+ case OCODE:
+ codgen2(l->left, l->right, n->lineno, 0);
+ break;
+ case ODECV:
+ vtgen2(l);
+ break;
+ case ODECE:
+ etgen2(n->sym);
+ break;
+ case ODECT:
+ ttgen2(n->type);
+ break;
+ case ODECF:
+ break;
+ }
+ }
+}
+
+static void
+scomplex(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ default:
+ complex(n);
+ break;
+ case ODAS:
+ case OSBREAK:
+ case ONUL:
+ case OLABEL:
+ case OGOTO:
+ case OCONTINUE:
+ case OBREAK:
+ break;
+ case ONAME:
+ if(n->kind == KEXP)
+ complex(n);
+ break;
+ case OBLK:
+ case OSET:
+ case OUSED:
+ scomplex(n->left);
+ break;
+ case OLIST:
+ scomplex(n->left);
+ scomplex(n->right);
+ break;
+ case ORETURN:
+ complex(n);
+ break;
+ case OCASE:
+ complex(n->left);
+ break;
+ case OSWITCH:
+ case OWHILE:
+ case ODWHILE:
+ complex(n->left);
+ scomplex(n->right);
+ break;
+ case OFOR:
+ complex(n->left->left);
+ complex(n->left->right->left);
+ complex(n->left->right->right);
+ scomplex(n->right);
+ break;
+ case OIF:
+ complex(n->left);
+ scomplex(n->right->left);
+ scomplex(n->right->right);
+ break;
+ }
+}
+
+static void
+mtset(Type *t)
+{
+ if(t == T)
+ return;
+ switch(t->etype){
+ case TIND:
+ case TARRAY:
+ mtset(t->link);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ prsym0(suename(t));
+ /*
+ for(l = t->link; l != T; l = l->down)
+ mtset(l);
+ */
+ break;
+ }
+}
+
+static void
+mset(Node *n)
+{
+ if(n == Z)
+ return;
+ n->garb = 0;
+ if(n->op == ONAME)
+ prsym0(n->sym);
+ mtset(n->type);
+ mset(n->left);
+ mset(n->right);
+}
+
+static int
+sign(Node *n)
+{
+ int s;
+
+ if(n == Z)
+ return 1;
+ switch(n->op){
+ case OCONST:
+ sign(n->left);
+ if(n->vconst < 0){
+ n->vconst = -n->vconst;
+ return -1;
+ }
+ break;
+ case OPOS:
+ s = sign(n->left);
+ *n = *n->left;
+ return s;
+ case ONEG:
+ s = sign(n->left);
+ *n = *n->left;
+ return -s;
+ case OADD:
+ if(sign(n->right) < 0)
+ n->op = OSUB;
+ break;
+ case OSUB:
+ if(sign(n->right) < 0)
+ n->op = OADD;
+ break;
+ case OMUL:
+ case ODIV:
+ return sign(n->left)*sign(n->right);
+ default:
+ break;
+ }
+ return 1;
+}
+
+static Node*
+ckneg(Node *n)
+{
+ if(sign(n) < 0)
+ return new1(ONEG, n, Z);
+ return n;
+}
+
+static void
+sliceasgn(Node *n)
+{
+ Type *t;
+ Node *nn;
+
+ if(side(n->left) || (n->right != Z && side(n->right)))
+ return;
+ t = n->type;
+ if(isarray(t) && (!strings || t->link->etype != TCHAR)){
+ if(n->op == OASADD)
+ nn = n->right;
+ else
+ nn = con(1);
+ n->op = OAS;
+ n->right = new1(OSLICE, ncopy(n->left), new1(OLIST, nn, Z));
+ }
+}
diff --git a/utils/c2l/cc.h b/utils/c2l/cc.h
new file mode 100644
index 00000000..3900506d
--- /dev/null
+++ b/utils/c2l/cc.h
@@ -0,0 +1,849 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Node Node;
+typedef struct Sym Sym;
+typedef struct Type Type;
+typedef struct Decl Decl;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Term Term;
+typedef struct Init Init;
+typedef struct Bits Bits;
+
+#define NHUNK 50000L
+#define BUFSIZ 8192
+#define NSYMB 500
+#define NHASH 1024
+#define STRINGSZ 200
+#define HISTSZ 20
+#define YYMAXDEPTH 500
+#define NTERM 10
+#define MAXALIGN 7
+
+#define SIGN(n) ((vlong)1<<(n-1))
+#define MASK(n) (SIGN(n)|(SIGN(n)-1))
+
+#define BITS 5
+#define NVAR (BITS*sizeof(ulong)*8)
+struct Bits
+{
+ ulong b[BITS];
+};
+
+EXTERN int lastnumbase;
+
+#define KNIL 0
+#define KCHR 1
+#define KOCT 2
+#define KDEC 3
+#define KHEX 4
+#define KEXP 5
+#define KDROP 6
+#define KLAST 7
+
+struct Node
+{
+ Node* left;
+ Node* right;
+ double fconst; /* fp constant */
+ vlong vconst; /* non fp const */
+ char* cstring; /* character string */
+ ushort* rstring; /* rune string */
+
+ Sym* sym;
+ Type* type;
+ long lineno;
+ char op;
+ char garb;
+ char kind;
+ char blk;
+};
+#define Z ((Node*)0)
+#define ZZ ((Node*)-1)
+
+struct Sym
+{
+ Sym* link;
+ Type* type;
+ Type* suetag;
+ Type* tenum;
+ char* macro;
+ long lineno;
+ long offset;
+ vlong vconst;
+ double fconst;
+ Node* nconst;
+ char* cstring;
+ Node* label;
+ char *name;
+ char *lname;
+ char *mod;
+ ushort lexical;
+ ushort block;
+ ushort sueblock;
+ char class;
+ char kind;
+ char lkw;
+ char args;
+ char fd;
+ char limbo;
+};
+#define S ((Sym*)0)
+
+struct Decl
+{
+ Decl* link;
+ Sym* sym;
+ Type* type;
+ long offset;
+ long lineno;
+ short val;
+ ushort block;
+ char class;
+};
+#define D ((Decl*)0)
+
+struct Type
+{
+ Sym* sym;
+ Sym* tag;
+ Type* link;
+ Type* down;
+ Node* nwidth;
+ long width;
+ long offset;
+ long lineno;
+ char shift;
+ char nbits;
+ char etype;
+ char garb;
+ char vis;
+ char mark;
+};
+#define T ((Type*)0)
+#define NODECL ((void(*)(int, Type*, Sym*))0)
+
+struct Init /* general purpose initialization */
+{
+ int code;
+ ulong value;
+ char* s;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char* p;
+ char b[BUFSIZ];
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+EXTERN Hist* hist;
+
+struct Term
+{
+ vlong mult;
+ Node *node;
+};
+
+enum
+{
+ Axxx,
+ Ael1,
+ Ael2,
+ Asu2,
+ Aarg0,
+ Aarg1,
+ Aarg2,
+ Aaut3,
+ NALIGN,
+};
+
+enum /* also in ../{8a,0a}.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+enum
+{
+ DMARK,
+ DAUTO,
+ DSUE,
+ DLABEL,
+};
+enum
+{
+ ONOOP,
+ OXXX,
+ OADD,
+ OADDR,
+ OAND,
+ OANDAND,
+ OARRAY,
+ OAS,
+ OASI,
+ OASADD,
+ OASAND,
+ OASASHL,
+ OASASHR,
+ OASDIV,
+ OASHL,
+ OASHR,
+ OASLDIV,
+ OASLMOD,
+ OASLMUL,
+ OASLSHR,
+ OASMOD,
+ OASMUL,
+ OASOR,
+ OASSUB,
+ OASXOR,
+ OBIT,
+ OBREAK,
+ OCASE,
+ OCAST,
+ OCOMMA,
+ OCOND,
+ OCONST,
+ OCONTINUE,
+ ODIV,
+ ODOT,
+ ODOTDOT,
+ ODWHILE,
+ OENUM,
+ OEQ,
+ OFOR,
+ OFUNC,
+ OGE,
+ OGOTO,
+ OGT,
+ OHI,
+ OHS,
+ OIF,
+ OIND,
+ OINDREG,
+ OINIT,
+ OLABEL,
+ OLDIV,
+ OLE,
+ OLIST,
+ OLMOD,
+ OLMUL,
+ OLO,
+ OLS,
+ OLSHR,
+ OLT,
+ OMOD,
+ OMUL,
+ ONAME,
+ ONE,
+ ONOT,
+ OOR,
+ OOROR,
+ OPOSTDEC,
+ OPOSTINC,
+ OPREDEC,
+ OPREINC,
+ OPROTO,
+ OREGISTER,
+ ORETURN,
+ OSET,
+ OSIGN,
+ OSIZE,
+ OSTRING,
+ OLSTRING,
+ OSTRUCT,
+ OSUB,
+ OSWITCH,
+ OUNION,
+ OUSED,
+ OWHILE,
+ OXOR,
+ ONEG,
+ OCOM,
+ OELEM,
+
+ OTST, /* used in some compilers */
+ OINDEX,
+ OFAS,
+
+ OBLK,
+ OPOS,
+ ONUL,
+ ODOTIND,
+ OARRIND,
+ ODAS,
+ OASD,
+ OIOTA,
+ OLEN,
+ OBRACKET,
+ OREF,
+ OARRAYOF,
+ OSLICE,
+ OSADDR,
+ ONIL,
+ OS2AB,
+ OAB2S,
+ OFILDES,
+ OFD,
+ OTUPLE,
+ OT0,
+ ORETV,
+ OCAT,
+ OSBREAK,
+ OLDOT,
+ OMDOT,
+
+ OCODE,
+ ODECE,
+ ODECT,
+ ODECV,
+ ODECF,
+ OPUSH,
+ OPOP,
+
+ OEND
+};
+enum
+{
+ TXXX,
+ TCHAR,
+ TUCHAR,
+ TSHORT,
+ TUSHORT,
+ TINT,
+ TUINT,
+ TLONG,
+ TULONG,
+ TVLONG,
+ TUVLONG,
+ TFLOAT,
+ TDOUBLE,
+ TIND,
+ TFUNC,
+ TARRAY,
+ TVOID,
+ TSTRUCT,
+ TUNION,
+ TENUM,
+ NTYPE,
+
+ TAUTO = NTYPE,
+ TEXTERN,
+ TSTATIC,
+ TTYPEDEF,
+ TREGISTER,
+ TCONSTNT,
+ TVOLATILE,
+ TUNSIGNED,
+ TSIGNED,
+ TDOT,
+ TFILE,
+ TOLD,
+
+ TSTRING,
+ TFD,
+ TTUPLE,
+
+ NALLTYPES,
+};
+enum
+{
+ CXXX,
+ CAUTO,
+ CEXTERN,
+ CGLOBL,
+ CSTATIC,
+ CLOCAL,
+ CTYPEDEF,
+ CPARAM,
+ CSELEM,
+ CLABEL,
+ CEXREG,
+ NCTYPES,
+};
+enum
+{
+ GXXX = 0,
+ GCONSTNT = 1<<0,
+ GVOLATILE = 1<<1,
+ NGTYPES = 1<<2,
+};
+enum
+{
+ BCHAR = 1L<<TCHAR,
+ BUCHAR = 1L<<TUCHAR,
+ BSHORT = 1L<<TSHORT,
+ BUSHORT = 1L<<TUSHORT,
+ BINT = 1L<<TINT,
+ BUINT = 1L<<TUINT,
+ BLONG = 1L<<TLONG,
+ BULONG = 1L<<TULONG,
+ BVLONG = 1L<<TVLONG,
+ BUVLONG = 1L<<TUVLONG,
+ BFLOAT = 1L<<TFLOAT,
+ BDOUBLE = 1L<<TDOUBLE,
+ BIND = 1L<<TIND,
+ BFUNC = 1L<<TFUNC,
+ BARRAY = 1L<<TARRAY,
+ BVOID = 1L<<TVOID,
+ BSTRUCT = 1L<<TSTRUCT,
+ BUNION = 1L<<TUNION,
+ BENUM = 1L<<TENUM,
+ BFILE = 1L<<TFILE,
+ BOLD = 1L<<TOLD,
+ BDOT = 1L<<TDOT,
+ BCONSTNT = 1L<<TCONSTNT,
+ BVOLATILE = 1L<<TVOLATILE,
+ BUNSIGNED = 1L<<TUNSIGNED,
+ BSIGNED = 1L<<TSIGNED,
+ BAUTO = 1L<<TAUTO,
+ BEXTERN = 1L<<TEXTERN,
+ BSTATIC = 1L<<TSTATIC,
+ BTYPEDEF = 1L<<TTYPEDEF,
+ BREGISTER = 1L<<TREGISTER,
+
+ BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
+ BLONG|BULONG|BVLONG|BUVLONG,
+ BNUMBER = BINTEGER|BFLOAT|BDOUBLE,
+
+/* these can be overloaded with complex types */
+
+ BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BREGISTER,
+
+ BGARB = BCONSTNT|BVOLATILE,
+};
+
+EXTERN struct
+{
+ Type* tenum; /* type of entire enum */
+ Type* cenum; /* type of current enum run */
+ vlong lastenum; /* value of current enum */
+ double floatenum; /* value of current enum */
+} en;
+
+EXTERN int autobn;
+EXTERN long autoffset;
+EXTERN int blockno;
+EXTERN int comm;
+EXTERN Decl* dclstack;
+EXTERN int doaddr;
+EXTERN int doalladdr;
+EXTERN int doinc;
+EXTERN int doloc;
+EXTERN int domod;
+EXTERN Hist* ehist;
+EXTERN long firstbit;
+EXTERN Decl* firstdcl;
+EXTERN int fperror;
+EXTERN Sym* hash[NHASH];
+EXTERN char* hunk;
+EXTERN char* include[20];
+EXTERN Type* fdtype;
+EXTERN int inmain;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int justcode;
+EXTERN long lastbit;
+EXTERN char lastclass;
+EXTERN Type* lastdcl;
+EXTERN long lastfield;
+EXTERN Type* lasttype;
+EXTERN long lineno;
+EXTERN long nearln;
+EXTERN int nerrors;
+EXTERN int newflag;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Node* nodproto;
+EXTERN Node* nodcast;
+EXTERN int passes;
+EXTERN char* pathname;
+EXTERN int peekc;
+EXTERN Type* pfdtype;
+EXTERN long pline;
+EXTERN long saveline;
+EXTERN Type* strf;
+EXTERN int strings;
+EXTERN Type* stringtype;
+EXTERN Type* strl;
+EXTERN char symb[NSYMB];
+EXTERN Sym* symstring;
+EXTERN int taggen;
+EXTERN Type* tfield;
+EXTERN Type* tufield;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN Type* thisfn;
+EXTERN long thunk;
+EXTERN Type* types[NTYPE];
+EXTERN Node* initlist;
+EXTERN int nterm;
+EXTERN int hjdickflg;
+EXTERN int fproundflg;
+EXTERN Bits zbits;
+
+extern char *onames[], *tnames[], *gnames[];
+extern char *cnames[], *qnames[], *bnames[];
+extern char tab[NTYPE][NTYPE];
+extern char comrel[], invrel[], logrel[];
+extern long ncast[], tadd[], tand[];
+extern long targ[], tasadd[], tasign[], tcast[];
+extern long tdot[], tfunct[], tindir[], tmul[];
+extern long tnot[], trel[], tsub[];
+
+extern char typeaf[];
+extern char typefd[];
+extern char typei[];
+extern char typesu[];
+extern char typesuv[];
+extern char typeu[];
+extern char typev[];
+extern char typec[];
+extern char typeh[];
+extern char typeil[];
+extern char typeilp[];
+extern char typechl[];
+extern char typechlp[];
+extern char typechlpfd[];
+
+extern ulong thash1;
+extern ulong thash2;
+extern ulong thash3;
+extern ulong thash[];
+
+/*
+ * Inferno.c/Posix.c/Nt.c
+ */
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
+
+/*
+ * parser
+ */
+int yyparse(void);
+int mpatof(char*, double*);
+int mpatov(char*, vlong*);
+
+/*
+ * lex.c
+ */
+void* allocn(void*, long, long);
+void* alloc(long);
+void cinit(void);
+int compile(char*, char**, int);
+void errorexit(void);
+int filbuf(void);
+int getc(void);
+long getr(void);
+int getnsc(void);
+Sym* lookup(void);
+void main(int, char*[]);
+void newfile(char*, int);
+void newio(void);
+void outbegin(char *);
+void outend(void);
+void outfun(Node*);
+void pushio(void);
+long escchar(long, int, int);
+Sym* slookup(char*);
+void syminit(Sym*);
+void unget(int);
+long yylex(void);
+int Lconv(Fmt*);
+int Tconv(Fmt*);
+int FNconv(Fmt*);
+int Oconv(Fmt*);
+int Qconv(Fmt*);
+int VBconv(Fmt*);
+void setinclude(char*);
+
+/*
+ * mac.c
+ */
+void dodefine(char*);
+void domacro(void);
+Sym* getsym(void);
+long getnsn(void);
+void linehist(char*, int);
+void macdef(void);
+void macprag(void);
+void macend(void);
+void macexpand(Sym*, char*);
+void macif(int);
+void macinc(void);
+void maclin(void);
+void macund(void);
+
+/*
+ * dcl.c
+ */
+Node* doinit(Sym*, Type*, long, Node*);
+Type* tcopy(Type*);
+void init1(Sym*, Type*, long, int);
+Node* newlist(Node*, Node*);
+void adecl(int, Type*, Sym*);
+int anyproto(Node*);
+void argmark(Node*, int);
+void dbgdecl(Sym*);
+Node* dcllabel(Sym*, int);
+Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*, int);
+Sym* mkstatic(Sym*);
+void doenum(Sym*, Node*);
+void snap(Type*);
+Type* dotag(Sym*, int, int);
+void edecl(int, Type*, Sym*);
+Type* fnproto(Node*);
+Type* fnproto1(Node*);
+void markdcl(void);
+Type* paramconv(Type*, int);
+void pdecl(int, Type*, Sym*);
+Decl* push(void);
+Decl* push1(Sym*);
+Node* revertdcl(void);
+#define round ccround
+long round(long, int);
+int rsametype(Type*, Type*, int, int);
+int sametype(Type*, Type*);
+ulong signature(Type*, int);
+void suallign(Type*);
+void tmerge(Type*, Sym*);
+void walkparam(Node*, int);
+void xdecl(int, Type*, Sym*);
+Node* contig(Sym*, Node*, long);
+
+/*
+ * com.c
+ */
+void ccom(Node*);
+void complex(Node*);
+int tcom(Node*);
+int tcoma(Node*, Node*, Type*, int);
+int tcomd(Node*, Type*);
+int tcomo(Node*, int);
+int tcomx(Node*);
+int tlvalue(Node*);
+void constas(Node*, Type*, Type*);
+
+/*
+ * con.c
+ */
+void acom(Node*);
+void acom1(vlong, Node*);
+void acom2(Node*, Type*);
+int acomcmp1(const void*, const void*);
+int acomcmp2(const void*, const void*);
+int addo(Node*);
+void evconst(Node*);
+
+/*
+ * sub.c
+ */
+void arith(Node*, int);
+Type* dotsearch(Sym*, Type*, Node*);
+long dotoffset(Type*, Type*, Node*);
+void gethunk(void);
+Node* invert(Node*);
+int bitno(long);
+void makedot(Node*, Type*, long);
+Node* new(int, Node*, Node*);
+Node* new1(int, Node*, Node*);
+int nilcast(Type*, Type*);
+int nocast(Type*, Type*);
+void prtree(Node*, char*);
+void prtree1(Node*, int, int);
+void relcon(Node*, Node*);
+int relindex(int);
+int simpleg(long);
+Type* garbt(Type*, long);
+int simplec(long);
+Type* simplet(long);
+int stcompat(Node*, Type*, Type*, long[]);
+int tcompat(Node*, Type*, Type*, long[]);
+void tinit(void);
+Type* typ(int, Type*);
+Type* typ1(int, Type*);
+void typeext(Type*, Node*);
+void typeext1(Type*, Node*);
+int side(Node*);
+int vconst(Node*);
+int vlog(Node*);
+int topbit(ulong);
+long typebitor(long, long);
+void diag(Node*, char*, ...);
+void warn(Node*, char*, ...);
+void yyerror(char*, ...);
+void fatal(Node*, char*, ...);
+
+/*
+ * acid.c
+ */
+void acidtype(Type*);
+void acidvar(Sym*);
+
+/*
+ * bits.c
+ */
+Bits bor(Bits, Bits);
+Bits band(Bits, Bits);
+Bits bnot(Bits);
+int bany(Bits*);
+int bnum(Bits);
+Bits blsh(uint);
+int beq(Bits, Bits);
+int bset(Bits, uint);
+
+/*
+ * dpchk.c
+ */
+void dpcheck(Node*);
+void arginit(void);
+void pragvararg(void);
+void praghjdicks(void);
+void pragfpround(void);
+
+/*
+ * calls to machine depend part
+ */
+void codgen(Node*, Node*, int);
+void gclean(void);
+void gextern(Sym*, Node*, long, long);
+void ginit(void);
+long outstring(char*, long);
+long outlstring(ushort*, long);
+void sextern(Sym*, Node*, long, long);
+void xcom(Node*);
+long exreg(Type*);
+long align(long, Type*, int);
+long maxround(long, long);
+
+extern schar ewidth[];
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+double convvtof(vlong);
+vlong convftov(double);
+double convftox(double, int);
+vlong convvtox(vlong, int);
+
+#pragma varargck argpos warn 2
+#pragma varargck argpos diag 2
+#pragma varargck argpos yyerror 1
+
+#pragma varargck type "F" Node*
+#pragma varargck type "L" long
+#pragma varargck type "Q" long
+#pragma varargck type "O" int
+#pragma varargck type "T" Type*
+#pragma varargck type "|" int
+
+/* output routines */
+
+void prline(char*);
+void prstr(char *);
+void prlstr(ushort *);
+void prkeywd(char *);
+void prid(char *);
+void prsym(Sym*, int);
+void prsym0(Sym*);
+void prdelim(char *);
+void prchar(vlong);
+void prreal(double, char*, int);
+void prnum(vlong, int, Type*);
+void prcom(char *, Node*);
+void newline(void);
+void incind(void);
+void decind(void);
+int zeroind(void);
+void restoreind(int);
+void startcom(int);
+void addcom(int);
+void endcom(void);
+int outcom(int);
+int arrow(Sym*);
+
+/* limbo generating routines */
+
+void pgen(int);
+void epgen(int);
+void ttgen(Type*);
+void vtgen(Node*);
+void etgen(Sym*);
+void expgen(Node*);
+
+/* -m routines */
+
+void newsec(int);
+
+void outpush(char*);
+void outpop(int);
+void outpush0(char*, Node*);
+void outpop0(int);
+void outpush2(char*, Node*);
+void outpop2(int);
+char* outmod(char*, int);
+
+/* miscellaneous */
+
+int iscon(char*);
+Node* ncopy(Node*);
+void doasenum(Sym*);
+Type *maxtype(Type*, Type*);
+
+void linit(void);
+void sysinit(void);
+
+int ism(void);
+int isb(void);
+int dolog(void);
+
+int line(Node*);
+
+void output(long, int);
+void usemod(Sym*, int);
+void setmod(Sym*);
+
+int exists(char*);
+int isconsym(Sym *);
+
+void clbegin(void);
+void clend(void);
+
+int gfltconv(Fmt*);
diff --git a/utils/c2l/cc.y b/utils/c2l/cc.y
new file mode 100644
index 00000000..22dc6c0c
--- /dev/null
+++ b/utils/c2l/cc.y
@@ -0,0 +1,1239 @@
+%{
+#include "cc.h"
+%}
+%union {
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ char c;
+ } tycl;
+ struct
+ {
+ Type* t1;
+ Type* t2;
+ } tyty;
+ struct
+ {
+ char* s;
+ long l;
+ } sval;
+ long lval;
+ double dval;
+ vlong vval;
+}
+%type <sym> ltag
+%type <lval> gctname cname gname tname
+%type <lval> gctnlist zgnlist tnlist
+%type <type> tlist etlist sbody complex
+%type <tycl> types etypes
+%type <node> zarglist arglist zcexpr
+%type <node> name block stmnt cexpr expr xuexpr pexpr
+%type <node> zelist elist adecl slist uexpr string lstring sstring slstring
+%type <node> xdecor xdecor2 labels label ulstmnt
+%type <node> adlist edecor tag qual qlist
+%type <node> abdecor abdecor1 abdecor2 abdecor3
+%type <node> zexpr lexpr init ilist
+
+%left ';'
+%left ','
+%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
+%right '?' ':'
+%left LOROR
+%left LANDAND
+%left '|'
+%left '^'
+%left '&'
+%left LEQ LNE
+%left '<' '>' LLE LGE
+%left LLSH LRSH
+%left '+' '-'
+%left '*' '/' '%'
+%right LMM LPP LMG '.' '[' '('
+
+%token <sym> LNAME LCTYPE LSTYPE
+%token <dval> LFCONST LDCONST
+%token <vval> LCHARACTER LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
+%token <sval> LSTRING LLSTRING
+%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
+%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
+%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED
+%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LUNION LUNSIGNED LWHILE
+%token LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF LVLONG
+%%
+prog:
+| prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+ zctlist ';'
+ {
+ dodecl(xdecl, lastclass, lasttype, Z, 1);
+ }
+| zctlist xdlist ';'
+| zctlist xdecor
+ {
+ lastdcl = T;
+ dodecl(xdecl, lastclass, lasttype, $2, 0);
+ if(lastdcl == T || lastdcl->etype != TFUNC) {
+ diag($2, "not a function");
+ lastdcl = types[TFUNC];
+ }
+ thisfn = lastdcl;
+ markdcl();
+ firstdcl = dclstack;
+ argmark($2, 0);
+ }
+ pdecl
+ {
+ argmark($2, 1);
+ }
+ block
+ {
+ $6->blk = 0;
+ codgen($6, $2, lineno);
+ revertdcl();
+ }
+
+xdlist:
+ xdecor
+ {
+ dodecl(xdecl, lastclass, lasttype, $1, 1);
+ }
+| xdecor
+ {
+ $1 = dodecl(xdecl, lastclass, lasttype, $1, 0);
+ }
+ '=' init
+ {
+ $4 = doinit($1->sym, $1->type, 0L, $4);
+ $4 = new(ODAS, $1, $4);
+ $4->type = $1->type;
+ $4->lineno = $1->lineno;
+ vtgen($4);
+ }
+| xdlist ',' xdlist
+
+xdecor:
+ xdecor2
+| '*' zgnlist xdecor
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+
+xdecor2:
+ tag
+| '(' xdecor ')'
+ {
+ $$ = $2;
+ }
+| xdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ /* outfun($$); */
+ }
+| xdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+/*
+ * automatic declarator
+ */
+adecl:
+ {
+ $$ = Z;
+ }
+| adecl ctlist ';'
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, Z, 1);
+ if($1 != Z)
+ if($$ != Z)
+ $$ = new(OLIST, $1, $$);
+ else
+ $$ = $1;
+ }
+| adecl ctlist adlist ';'
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+adlist:
+ xdecor
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, $1, 1);
+ if($$->sym->class == CSTATIC)
+ $$ = Z;
+ }
+| xdecor
+ {
+ $1 = dodecl(adecl, lastclass, lasttype, $1, 0);
+ }
+ '=' init
+ {
+ /* long w; */
+
+ /* w = $1->sym->type->width; */
+ $$ = doinit($1->sym, $1->type, 0L, $4);
+ /* $$ = contig($1->sym, $$, w); */
+ $$ = new(ODAS, $1, $$);
+ $$->type = $1->type;
+ $$->lineno = $1->lineno;
+ vtgen($$);
+ if($1->sym->class == CSTATIC)
+ $$ = Z;
+ }
+| adlist ',' adlist
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+/*
+ * parameter declarator
+ */
+pdecl:
+| pdecl ctlist pdlist ';'
+
+pdlist:
+ xdecor
+ {
+ dodecl(pdecl, lastclass, lasttype, $1, 1);
+ }
+| pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+ etlist
+ {
+ lasttype = $1;
+ }
+ zedlist ';'
+| edecl etlist
+ {
+ lasttype = $2;
+ }
+ zedlist ';'
+
+zedlist: /* extension */
+ {
+ lastfield = 0;
+ edecl(CXXX, lasttype, S);
+ }
+| edlist
+
+edlist:
+ edecor
+ {
+ dodecl(edecl, CXXX, lasttype, $1, 1);
+ }
+| edlist ',' edlist
+
+edecor:
+ xdecor
+ {
+ lastbit = 0;
+ firstbit = 1;
+ }
+| tag ':' lexpr
+ {
+ $$ = new(OBIT, $1, $3);
+ }
+| ':' lexpr
+ {
+ $$ = new(OBIT, Z, $2);
+ }
+
+/*
+ * abstract declarator
+ */
+abdecor:
+ {
+ $$ = (Z);
+ }
+| abdecor1
+
+abdecor1:
+ '*' zgnlist
+ {
+ $$ = new(OIND, (Z), Z);
+ $$->garb = simpleg($2);
+ }
+| '*' zgnlist abdecor1
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+| abdecor2
+
+abdecor2:
+ abdecor3
+| abdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| abdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+abdecor3:
+ '(' ')'
+ {
+ $$ = new(OFUNC, (Z), Z);
+ }
+| '[' zexpr ']'
+ {
+ $$ = new(OARRAY, (Z), $2);
+ }
+| '(' abdecor1 ')'
+ {
+ $$ = $2;
+ }
+
+init:
+ expr
+| '{' ilist '}'
+ {
+ $$ = new(OINIT, invert($2), Z);
+ }
+
+qual:
+ '[' lexpr ']'
+ {
+ $$ = new(OARRAY, $2, Z);
+ }
+| '.' ltag
+ {
+ $$ = new(OELEM, Z, Z);
+ $$->sym = $2;
+ }
+| qual '='
+
+qlist:
+ init ','
+| qlist init ','
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+| qual
+| qlist qual
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ilist:
+ qlist
+| init
+| qlist init
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+zarglist:
+ {
+ $$ = Z;
+ }
+| arglist
+ {
+ $$ = invert($1);
+ }
+
+
+arglist:
+ name
+| tlist abdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| tlist xdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| '.' '.' '.'
+ {
+ $$ = new(ODOTDOT, Z, Z);
+ }
+| arglist ',' arglist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+block:
+ '{' adecl slist '}'
+ {
+ $$ = invert($3);
+ if($2 != Z)
+ $$ = new(OLIST, $2, $$);
+ if($$ == Z)
+ $$ = new(ONUL, Z, Z);
+ $$->blk = 1;
+ }
+
+slist:
+ {
+ $$ = Z;
+ }
+| slist stmnt
+ {
+ if($1 == Z)
+ $$ = $2;
+ else
+ $$ = new(OLIST, $1, $2);
+ }
+
+labels:
+ label
+| labels label
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+label:
+ LCASE expr ':'
+ {
+ $$ = new(OCASE, $2, Z);
+ $$->lineno = $2->lineno;
+ }
+| LDEFAULT ':'
+ {
+ $$ = new(OCASE, Z, Z);
+ }
+| LNAME ':'
+ {
+ $$ = new(OLABEL, dcllabel($1, 1), Z);
+ $1->lineno = lineno;
+ }
+
+stmnt:
+ error ';'
+ {
+ $$ = Z;
+ }
+| ulstmnt
+| labels ulstmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ulstmnt:
+ zcexpr ';'
+ {
+ if($$ == Z)
+ $$ = new(ONUL, Z, Z);
+ $$->kind = KEXP;
+ }
+| {
+ markdcl();
+ }
+ block
+ {
+ revertdcl();
+ $$ = $2;
+ }
+| LIF '(' cexpr ')' stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, Z));
+ $$->lineno = $3->lineno;
+ $5->blk = 0;
+ }
+| LIF '(' cexpr ')' stmnt LELSE stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, $7));
+ $$->lineno = $3->lineno;
+ $5->blk = $7->blk = 0;
+ }
+| LFOR '(' zcexpr ';' zcexpr ';' zcexpr ')' stmnt
+ {
+ $$ = new(OFOR, new(OLIST, $5, new(OLIST, $3, $7)), $9);
+ if($3 != Z)
+ $$->lineno = $3->lineno;
+ else if($5 != Z)
+ $$->lineno = $5->lineno;
+ else if($7 != Z)
+ $$->lineno = $7->lineno;
+ else
+ $$->lineno = line($9);
+ $9->blk = 0;
+ }
+| LWHILE '(' cexpr ')' stmnt
+ {
+ $$ = new(OWHILE, $3, $5);
+ $$->lineno = $3->lineno;
+ $5->blk = 0;
+ }
+| LDO stmnt LWHILE '(' cexpr ')' ';'
+ {
+ $$ = new(ODWHILE, $5, $2);
+ $$->lineno = line($2);
+ $2->blk = 0;
+ }
+| LRETURN zcexpr ';'
+ {
+ $$ = new(ORETURN, $2, Z);
+ $$->type = thisfn->link;
+ if($2 != Z)
+ $$->lineno = $2->lineno;
+ }
+| LSWITCH '(' cexpr ')' stmnt
+ {
+ $$ = new(OSWITCH, $3, $5);
+ $$->lineno = $3->lineno;
+ $5->blk = 0;
+ }
+| LBREAK ';'
+ {
+ $$ = new(OBREAK, Z, Z);
+ }
+| LCONTINUE ';'
+ {
+ $$ = new(OCONTINUE, Z, Z);
+ }
+| LGOTO LNAME ';'
+ {
+ $$ = new(OGOTO, dcllabel($2, 0), Z);
+ $2->lineno = lineno;
+ }
+| LUSED '(' zelist ')' ';'
+ {
+ $$ = new(OUSED, $3, Z);
+ $$->lineno = line($3);
+ }
+| LSET '(' zelist ')' ';'
+ {
+ $$ = new(OSET, $3, Z);
+ $$->lineno = line($3);
+ }
+
+zcexpr:
+ {
+ $$ = Z;
+ }
+| cexpr
+
+zexpr:
+ {
+ $$ = Z;
+ }
+| lexpr
+
+lexpr:
+ expr
+ {
+ $$ = new(OCAST, $1, Z);
+ $$->type = types[TLONG];
+ }
+
+cexpr:
+ expr
+| cexpr ',' cexpr
+ {
+ $$ = new(OCOMMA, $1, $3);
+ }
+
+expr:
+ xuexpr
+| expr '*' expr
+ {
+ $$ = new(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = new(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = new(OMOD, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = new(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = new(OSUB, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = new(OASHR, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = new(OASHL, $1, $3);
+ }
+| expr '<' expr
+ {
+ $$ = new(OLT, $1, $3);
+ }
+| expr '>' expr
+ {
+ $$ = new(OGT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = new(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = new(OGE, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = new(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = new(ONE, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = new(OAND, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = new(OXOR, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = new(OOR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = new(OANDAND, $1, $3);
+ }
+| expr LOROR expr
+ {
+ $$ = new(OOROR, $1, $3);
+ }
+| expr '?' cexpr ':' expr
+ {
+ $$ = new(OCOND, $1, new(OLIST, $3, $5));
+ }
+| expr '=' expr
+ {
+ $$ = new(OAS, $1, $3);
+ }
+| expr LPE expr
+ {
+ $$ = new(OASADD, $1, $3);
+ }
+| expr LME expr
+ {
+ $$ = new(OASSUB, $1, $3);
+ }
+| expr LMLE expr
+ {
+ $$ = new(OASMUL, $1, $3);
+ }
+| expr LDVE expr
+ {
+ $$ = new(OASDIV, $1, $3);
+ }
+| expr LMDE expr
+ {
+ $$ = new(OASMOD, $1, $3);
+ }
+| expr LLSHE expr
+ {
+ $$ = new(OASASHL, $1, $3);
+ }
+| expr LRSHE expr
+ {
+ $$ = new(OASASHR, $1, $3);
+ }
+| expr LANDE expr
+ {
+ $$ = new(OASAND, $1, $3);
+ }
+| expr LXORE expr
+ {
+ $$ = new(OASXOR, $1, $3);
+ }
+| expr LORE expr
+ {
+ $$ = new(OASOR, $1, $3);
+ }
+
+xuexpr:
+ uexpr
+| '(' tlist abdecor ')' xuexpr
+ {
+ $$ = new(OCAST, $5, Z);
+ dodecl(NODECL, CXXX, $2, $3, 1);
+ $$->type = lastdcl;
+ }
+| '(' tlist abdecor ')' '{' ilist '}' /* extension */
+ {
+ $$ = new(OSTRUCT, $6, Z);
+ dodecl(NODECL, CXXX, $2, $3, 1);
+ $$->type = lastdcl;
+ }
+
+uexpr:
+ pexpr
+| '*' xuexpr
+ {
+ $$ = new(OIND, $2, Z);
+ }
+| '&' xuexpr
+ {
+ $$ = new(OADDR, $2, Z);
+ }
+| '+' xuexpr
+ {
+ $$ = new(OPOS, $2, Z);
+ }
+| '-' xuexpr
+ {
+ $$ = new(ONEG, $2, Z);
+ }
+| '!' xuexpr
+ {
+ $$ = new(ONOT, $2, Z);
+ }
+| '~' xuexpr
+ {
+ $$ = new(OCOM, $2, Z);
+ }
+| LPP xuexpr
+ {
+ $$ = new(OPREINC, $2, Z);
+ }
+| LMM xuexpr
+ {
+ $$ = new(OPREDEC, $2, Z);
+ }
+| LSIZEOF uexpr
+ {
+ $$ = new(OSIZE, $2, Z);
+ }
+| LSIGNOF uexpr
+ {
+ $$ = new(OSIGN, $2, Z);
+ }
+
+pexpr:
+ '(' cexpr ')'
+ {
+ $$ = $2;
+ }
+| LSIZEOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIZE, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4, 1);
+ $$->type = lastdcl;
+ }
+| LSIGNOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIGN, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4, 1);
+ $$->type = lastdcl;
+ }
+| pexpr '(' zelist ')'
+ {
+ $$ = new(OFUNC, $1, Z);
+ if($1->op == ONAME)
+ if($1->type == T)
+ dodecl(xdecl, CXXX, types[TINT], $$, 1);
+ $$->right = invert($3);
+ $$->kind = KEXP;
+ }
+| pexpr '[' cexpr ']'
+ {
+ $$ = new(OARRIND, $1, $3);
+ }
+| pexpr LMG ltag
+ {
+ $$ = new(ODOTIND, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr '.' ltag
+ {
+ $$ = new(ODOT, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr LPP
+ {
+ $$ = new(OPOSTINC, $1, Z);
+ }
+| pexpr LMM
+ {
+ $$ = new(OPOSTDEC, $1, Z);
+ }
+| name
+| LCHARACTER
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->kind = KCHR;
+ }
+| LCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TLONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LUCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUINT];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LULCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TULONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LDCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TDOUBLE];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ $$->kind = lastnumbase;
+ }
+| LFCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TFLOAT];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ $$->kind = lastnumbase;
+ }
+| LVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TVLONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LUVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUVLONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| string
+| lstring
+
+sstring:
+ LSTRING
+ {
+ $$ = new(OSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TCHAR]);
+ $$->type->width = $1.l + 1;
+ $$->cstring = $1.s;
+ $$->sym = symstring;
+ }
+
+string:
+ sstring
+ {
+ $$ = $1;
+ }
+| string sstring
+ {
+ char *s;
+ int n1, n2;
+
+ n1 = $1->type->width - 1;
+ n2 = $2->type->width - 1;
+ s = alloc(n1+n2+MAXALIGN);
+
+ memcpy(s, $1->cstring, n1);
+ memcpy(s+n1, $2->cstring, n2);
+ s[n1+n2] = 0;
+
+ $1->left = new(OCAT, ncopy($1), $2);
+
+ $$ = $1;
+ $$->type->width += n2;
+ $$->cstring = s;
+ }
+
+slstring:
+ LLSTRING
+ {
+ $$ = new(OLSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TUSHORT]);
+ $$->type->width = $1.l + sizeof(ushort);
+ $$->rstring = (ushort*)$1.s;
+ $$->sym = symstring;
+ }
+
+lstring:
+ slstring
+ {
+ $$ = $1;
+ }
+| lstring slstring
+ {
+ char *s;
+ int n1, n2;
+
+ n1 = $1->type->width - sizeof(ushort);
+ n2 = $2->type->width - sizeof(ushort);
+ s = alloc(n1+n2+MAXALIGN);
+
+ memcpy(s, $1->rstring, n1);
+ memcpy(s+n1, $2->rstring, n2);
+ *(ushort*)(s+n1+n2) = 0;
+
+ $1->left = new(OCAT, ncopy($1), $2);
+
+ $$ = $1;
+ $$->type->width += n2;
+ $$->rstring = (ushort*)s;
+ }
+
+zelist:
+ {
+ $$ = Z;
+ }
+| elist
+
+elist:
+ expr
+| elist ',' elist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+sbody:
+ '{'
+ {
+ $<tyty>$.t1 = strf;
+ $<tyty>$.t2 = strl;
+ strf = T;
+ strl = T;
+ lastbit = 0;
+ firstbit = 1;
+ }
+ edecl '}'
+ {
+ $$ = strf;
+ strf = $<tyty>2.t1;
+ strl = $<tyty>2.t2;
+ }
+
+zctlist:
+ {
+ lastclass = CXXX;
+ lasttype = types[TINT];
+ }
+| ctlist
+
+etypes:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| tnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ }
+
+types:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| complex gctnlist
+ {
+ $$.t = $1;
+ $$.c = simplec($2);
+ if($2 & ~BCLASS & ~BGARB)
+ diag(Z, "illegal combination of types 1: %Q/%T", $2, $1);
+ }
+| gctnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| gctnlist complex
+ {
+ $$.t = $2;
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ if($1 & ~BCLASS & ~BGARB)
+ diag(Z, "illegal combination of types 2: %Q/%T", $1, $2);
+ }
+| gctnlist complex gctnlist
+ {
+ $$.t = $2;
+ $$.c = simplec($1|$3);
+ $$.t = garbt($$.t, $1|$3);
+ if(($1|$3) & ~BCLASS & ~BGARB || $3 & BCLASS)
+ diag(Z, "illegal combination of types 3: %Q/%T/%Q", $1, $2, $3);
+ }
+
+etlist:
+ zgnlist etypes
+ {
+ $$ = $2.t;
+ if($2.c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[$2.c]);
+ $$ = garbt($$, $1);
+ }
+
+tlist:
+ types
+ {
+ $$ = $1.t;
+ if($1.c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
+ }
+
+ctlist:
+ types
+ {
+ lasttype = $1.t;
+ lastclass = $1.c;
+ }
+
+complex:
+ LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, 0);
+ $$ = $2->suetag;
+ $2->lineno = lineno;
+ }
+| LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, autobn);
+ saveline = $2->lineno = lineno;
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ $$->lineno = saveline;
+ suallign($$);
+ }
+| LSTRUCT
+ {
+ saveline = lineno;
+ }
+ sbody
+ {
+ char buf[128];
+
+ taggen++;
+ sprint(symb, "%s_adt_%d", outmod(buf, -1), taggen);
+ $$ = dotag(lookup(), TSTRUCT, autobn);
+ $$->link = $3;
+ $$->lineno = saveline;
+ lookup()->lineno = saveline;
+ suallign($$);
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, 0);
+ $$ = $2->suetag;
+ $2->lineno = lineno;
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, autobn);
+ saveline = $2->lineno = lineno;
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ $$->lineno = saveline;
+ suallign($$);
+ }
+| LUNION
+ {
+ saveline = lineno;
+ }
+ sbody
+ {
+ char buf[128];
+
+ taggen++;
+ sprint(symb, "%s_adt_%d", outmod(buf, -1), taggen);
+ $$ = dotag(lookup(), TUNION, autobn);
+ $$->link = $3;
+ $$->lineno = saveline;
+ lookup()->lineno = saveline;
+ suallign($$);
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, 0);
+ $$ = $2->suetag;
+ if($$->link == T)
+ $$->link = types[TINT];
+ $$ = $$->link;
+ $2->lineno = lineno;
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, autobn);
+ $2->lineno = lineno;
+ }
+ '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ if(en.tenum == T) {
+ diag(Z, "enum type ambiguous: %s", $2->name);
+ en.tenum = types[TINT];
+ }
+ $$->link = en.tenum;
+ $$ = en.tenum;
+ etgen(nil);
+ }
+| LENUM '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = en.tenum;
+ etgen(nil);
+ }
+| LCTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+| LSTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+
+tnlist:
+ tname
+| tnlist tname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctnlist:
+ gctname
+| gctnlist gctname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+zgnlist:
+ {
+ $$ = 0;
+ }
+| zgnlist gname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctname:
+ tname
+| gname
+| cname
+
+enum:
+ LNAME
+ {
+ doenum($1, Z);
+ $1->lineno = lineno;
+ }
+| LNAME '=' expr
+ {
+ doenum($1, $3);
+ $1->lineno = lineno;
+ }
+| enum ','
+| enum ',' enum
+
+tname: /* type words */
+ LCHAR { $$ = BCHAR; }
+| LSHORT { $$ = BSHORT; }
+| LINT { $$ = BINT; }
+| LLONG { $$ = BLONG; }
+| LSIGNED { $$ = BSIGNED; }
+| LUNSIGNED { $$ = BUNSIGNED; }
+| LFLOAT { $$ = BFLOAT; }
+| LDOUBLE { $$ = BDOUBLE; }
+| LVOID { $$ = BVOID; }
+| LVLONG { $$ = BVLONG|BLONG; }
+
+cname: /* class words */
+ LAUTO { $$ = BAUTO; }
+| LSTATIC { $$ = BSTATIC; }
+| LEXTERN { $$ = BEXTERN; }
+| LTYPEDEF { $$ = BTYPEDEF; }
+| LREGISTER { $$ = BREGISTER; }
+
+gname:
+ LCONSTNT { $$ = BCONSTNT; }
+| LVOLATILE { $$ = BVOLATILE; }
+
+name:
+ LNAME
+ {
+ $$ = new(ONAME, Z, Z);
+ if($1->class == CLOCAL)
+ $1 = mkstatic($1);
+ $$->sym = $1;
+ $$->type = $1->type;
+ }
+tag:
+ ltag
+ {
+ $$ = new(ONAME, Z, Z);
+ $$->sym = $1;
+ $$->type = $1->type;
+ }
+ltag:
+ LNAME
+| LCTYPE
+| LSTYPE
+
+%%
diff --git a/utils/c2l/com.c b/utils/c2l/com.c
new file mode 100644
index 00000000..283c2ae9
--- /dev/null
+++ b/utils/c2l/com.c
@@ -0,0 +1,918 @@
+#include "cc.h"
+
+void
+complex(Node *n)
+{
+
+ if(n == Z)
+ return;
+
+ nearln = n->lineno;
+ if(tcom(n))
+ return;
+ ccom(n);
+ acom(n);
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+ ADDROF = 1<<0,
+ CASTOF = 1<<1,
+ ADDROP = 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+ return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+ Node *l, *r;
+ Type *t;
+ int o;
+
+ if(n == Z) {
+ diag(Z, "Z in tcom");
+ errorexit();
+ }
+ l = n->left;
+ r = n->right;
+
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in type complex: %O", n->op);
+ goto bad;
+
+ case ODOTDOT:
+ /*
+ * tcom has already been called on this subtree
+ */
+ *n = *n->left;
+ if(n->type == T)
+ goto bad;
+ break;
+
+ case OCAST:
+ if(n->type == T)
+ break;
+ if(n->type->width == types[TLONG]->width) {
+ if(tcomo(l, ADDROF|CASTOF))
+ goto bad;
+ } else
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, n->type, tcast))
+ goto bad;
+ break;
+
+ case ORETURN:
+ if(l == Z) {
+ if(n->type->etype != TVOID)
+ warn(n, "null return of a typed function");
+ break;
+ }
+ if(tcom(l))
+ goto bad;
+ typeext(n->type, l);
+ if(tcompat(n, n->type, l->type, tasign))
+ break;
+ constas(n, n->type, l->type);
+ if(!sametype(n->type, l->type)) {
+ l = new1(OCAST, l, Z);
+ l->type = n->type;
+ n->left = l;
+ }
+ break;
+
+ case OASI: /* same as as, but no test for const */
+ n->op = OAS;
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+
+ typeext(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OAS:
+ case OASD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+
+ typeext(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ constas(n, l->type, r->type);
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OASADD:
+ case OASSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ typeext1(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasadd))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ typeext1(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASDIV)
+ n->op = OASLDIV;
+ if(n->op == OASMUL)
+ n->op = OASLMUL;
+ }
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->type = l->type;
+ if(typeu[n->type->etype]) {
+ if(n->op == OASASHR)
+ n->op = OASLSHR;
+ }
+ break;
+
+ case OASMOD:
+ case OASLMOD:
+ case OASOR:
+ case OASAND:
+ case OASXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tand))
+ goto bad;
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASMOD)
+ n->op = OASLMOD;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(tcom(l))
+ goto bad;
+ if(tlvalue(l) || tcompat(n, l->type, types[TINT], tadd))
+ goto bad;
+ n->type = l->type;
+ if(n->type->etype == TIND)
+ if(n->type->link->width < 1)
+ diag(n, "inc/dec of a void pointer");
+ break;
+
+ case OEQ:
+ case ONE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ typeext(l->type, r);
+ typeext(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ n->type = types[TINT];
+ break;
+
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ typeext1(l->type, r);
+ typeext1(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ if(typeu[n->type->etype])
+ n->op = logrel[relindex(n->op)];
+ n->type = types[TINT];
+ break;
+
+ case OCOND:
+ o = tcom(l);
+ o |= tcom(r->left);
+ if(o | tcom(r->right))
+ goto bad;
+ if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+ r->left->type = r->right->type;
+ r->left->vconst = 0;
+ }
+ if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+ r->right->type = r->left->type;
+ r->right->vconst = 0;
+ }
+ if(sametype(r->right->type, r->left->type)) {
+ r->type = r->right->type;
+ n->type = r->type;
+ break;
+ }
+ if(tcompat(r, r->left->type, r->right->type, trel))
+ goto bad;
+ arith(r, 0);
+ n->type = r->type;
+ break;
+
+ case OADD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tadd))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype]) {
+ if(n->op == ODIV)
+ n->op = OLDIV;
+ if(n->op == OMUL)
+ n->op = OLMUL;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->right = Z;
+ arith(n, 1);
+ n->right = new1(OCAST, r, Z);
+ n->right->type = types[TINT];
+ if(typeu[n->type->etype])
+ if(n->op == OASHR)
+ n->op = OLSHR;
+ break;
+
+ case OAND:
+ case OOR:
+ case OXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMOD:
+ case OLMOD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype])
+ n->op = OLMOD;
+ break;
+
+ case ONOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OPOS:
+ case ONEG:
+ case OCOM:
+ if(tcom(l))
+ goto bad;
+ n->type = l->type;
+ break;
+
+ case ONUL:
+ break;
+
+ case OIOTA:
+ n->type = types[TINT];
+ break;
+
+ case ODAS:
+ n->type = n->left->type;
+ break;
+
+ case OANDAND:
+ case OOROR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot) |
+ tcompat(n, T, r->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OCOMMA:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ n->type = r->type;
+ break;
+
+
+ case OSIGN: /* extension signof(type) returns a hash */
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "signof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width < 0) {
+ diag(n, "signof undefined type");
+ goto bad;
+ }
+ n->right = ncopy(n);
+ n->op = OCONST;
+ n->left = Z;
+ /* n->right = Z; */
+ n->vconst = convvtox(signature(n->type, 10), TULONG);
+ n->type = types[TULONG];
+ break;
+
+ case OSIZE:
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "sizeof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width <= 0) {
+ diag(n, "sizeof undefined type");
+ goto bad;
+ }
+ if(n->type->etype == TFUNC) {
+ diag(n, "sizeof function");
+ goto bad;
+ }
+ n->right = ncopy(n);
+ n->op = OCONST;
+ n->left = Z;
+ /* n->right = Z; */
+ n->vconst = convvtox(n->type->width, TINT);
+ n->type = types[TINT];
+ break;
+
+ case OFUNC:
+ o = tcomo(l, 0);
+ if(o)
+ goto bad;
+ if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+ l = new1(OIND, l, Z);
+ l->type = l->left->type->link;
+ n->left = l;
+ }
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(o | tcoma(l, r, l->type->down, 1))
+ goto bad;
+ n->type = l->type->link;
+ if(1)
+ if(l->type->down == T || l->type->down->etype == TOLD) {
+ nerrors--;
+ diag(n, "function args not checked: %F", l);
+ }
+ dpcheck(n);
+ break;
+
+ case ONAME:
+ if(n->type == T) {
+ diag(n, "name not declared: %F", n);
+ goto bad;
+ }
+ if(n->type->etype == TENUM) {
+ if(n->sym->tenum->etype == TIND){
+ /* n->op = OSTRING; */
+ n->type = n->sym->tenum;
+ /* n->cstring = n->sym->sconst; */
+ break;
+ }
+ n->left = ncopy(n);
+ n->op = OCONST;
+ n->type = n->sym->tenum;
+ if(!typefd[n->type->etype])
+ n->vconst = n->sym->vconst;
+ else{
+ n->fconst = n->sym->fconst;
+ n->cstring = n->sym->cstring;
+ }
+ break;
+ }
+ break;
+
+ case OLSTRING:
+ case OSTRING:
+ case OCONST:
+ break;
+
+ case ODOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tdot))
+ goto bad;
+ if(tcomd(n, l->type))
+ goto bad;
+ break;
+
+ case ODOTIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ if(tcompat(n, T, l->type->link, tdot))
+ goto bad;
+ if(tcomd(n, l->type->link))
+ goto bad;
+ break;
+
+ case OARRIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ if(tcom(r))
+ goto bad;
+ break;
+
+ case OADDR:
+ if(tcomo(l, ADDROP))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(l->type->nbits) {
+ diag(n, "address of a bit field");
+ goto bad;
+ }
+ if(l->op == OREGISTER) {
+ diag(n, "address of a register");
+ goto bad;
+ }
+ n->type = typ1(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ break;
+
+ case OIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ break;
+
+ case OSTRUCT:
+ if(tcomx(n))
+ goto bad;
+ break;
+ }
+ t = n->type;
+ if(t == T)
+ goto bad;
+ if(t->width < 0) {
+ snap(t);
+ if(t->width < 0) {
+ if(typesu[t->etype] && t->tag)
+ diag(n, "structure not fully declared %s", t->tag->name);
+ else
+ diag(n, "structure not fully declared");
+ goto bad;
+ }
+ }
+ if(typeaf[t->etype]) {
+ if(f & ADDROF)
+ goto addaddr;
+ if(f & ADDROP)
+ warn(n, "address of array/func ignored");
+ }
+ return 0;
+
+addaddr:
+ if(n->type->etype == TARRAY)
+ n->type = typ1(TIND, n->type->link);
+ return 0;
+ if(tlvalue(n))
+ goto bad;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OADDR;
+ if(l->type->etype == TARRAY)
+ l->type = l->type->link;
+ n->left = l;
+ n->right = Z;
+ n->type = typ1(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ return 0;
+
+bad:
+ n->type = T;
+ return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+ Node *n1;
+ int o;
+
+ if(t != T)
+ if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */
+ t = T;
+ if(n == Z) {
+ if(t != T && !sametype(t, types[TVOID])) {
+ diag(n, "not enough function arguments: %F", l);
+ return 1;
+ }
+ return 0;
+ }
+ if(n->op == OLIST) {
+ o = tcoma(l, n->left, t, 0);
+ if(t != T) {
+ t = t->down;
+ if(t == T)
+ t = types[TVOID];
+ }
+ return o | tcoma(l, n->right, t, 1);
+ }
+ if(f && t != T)
+ tcoma(l, Z, t->down, 0);
+ if(tcom(n) || tcompat(n, T, n->type, targ))
+ return 1;
+ if(sametype(t, types[TVOID])) {
+ diag(n, "too many function arguments: %F", l);
+ return 1;
+ }
+ if(t != T) {
+ typeext(t, n);
+ if(stcompat(nodproto, t, n->type, tasign)) {
+ diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+ n->type, t, l);
+ return 1;
+ }
+ switch(t->etype) {
+ case TCHAR:
+ case TSHORT:
+ /* t = types[TINT]; */
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ /* t = types[TUINT]; */
+ break;
+ }
+ } else {
+ switch(n->type->etype)
+ {
+ case TCHAR:
+ case TSHORT:
+ /* t = types[TINT]; */
+ t = n->type;
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ /* t = types[TUINT]; */
+ t = n->type;
+ break;
+
+ case TFLOAT:
+ /* t = types[TDOUBLE]; */
+ t = n->type;
+ }
+ }
+ if(t != T && !sametype(t, n->type)) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ }
+ return 0;
+}
+
+int
+tcomd(Node *n, Type *t)
+{
+ long o;
+
+ o = 0;
+ /* t = n->left->type; */
+ for(;;) {
+ t = dotsearch(n->sym, t->link, n);
+ if(t == T) {
+ diag(n, "not a member of struct/union: %F", n);
+ return 1;
+ }
+ o += t->offset;
+ if(t->sym == n->sym)
+ break;
+ if(sametype(t, n->sym->type))
+ break;
+ }
+ n->type = t;
+ return 0;
+}
+
+int
+tcomx(Node *n)
+{
+ Type *t;
+ Node *l, *r, **ar, **al;
+ int e;
+
+ e = 0;
+ if(n->type->etype != TSTRUCT) {
+ diag(n, "constructor must be a structure");
+ return 1;
+ }
+ l = invert(n->left);
+ n->left = l;
+ al = &n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ if(l == Z) {
+ diag(n, "constructor list too short");
+ return 1;
+ }
+ if(l->op == OLIST) {
+ r = l->left;
+ ar = &l->left;
+ al = &l->right;
+ l = l->right;
+ } else {
+ r = l;
+ ar = al;
+ l = Z;
+ }
+ if(tcom(r))
+ e++;
+ typeext(t, r);
+ if(tcompat(n, t, r->type, tasign))
+ e++;
+ constas(n, t, r->type);
+ if(!e && !sametype(t, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = t;
+ *ar = r;
+ }
+ }
+ if(l != Z) {
+ diag(n, "constructor list too long");
+ return 1;
+ }
+ return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+ if(0) {
+ diag(n, "not an l-value");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * general rewrite
+ * (IND(ADDR x)) ==> x
+ * (ADDR(IND x)) ==> x
+ * remove some zero operands
+ * remove no op casts
+ * evaluate constants
+ */
+void
+ccom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ case OAS:
+ case OASD:
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ case OASMOD:
+ case OASLMOD:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMUL:
+ case OASLMUL:
+ case OASSUB:
+ case OASADD:
+ ccom(l);
+ ccom(r);
+ if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst < 0)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ break;
+
+ case OCAST:
+ ccom(l);
+ if(l->op == OCONST) {
+ evconst(n);
+ if(n->op == OCONST)
+ break;
+ }
+ if(nocast(l->type, n->type)) {
+ l->type = n->type;
+ *n = *l;
+ }
+ break;
+
+ case OCOND:
+ ccom(l);
+ ccom(r);
+ break;
+
+ case OREGISTER:
+ case OINDREG:
+ case OCONST:
+ case ONAME:
+ break;
+
+ case OADDR:
+ ccom(l);
+ /* l->etype = TVOID; */
+ if(l->op == OIND) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OIND:
+ ccom(l);
+ if(l->op == OADDR) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OEQ:
+ case ONE:
+
+ case OLE:
+ case OGE:
+ case OLT:
+ case OGT:
+
+ case OLS:
+ case OHS:
+ case OLO:
+ case OHI:
+ ccom(l);
+ ccom(r);
+ relcon(l, r);
+ relcon(r, l);
+ goto common;
+
+ case OASHR:
+ case OASHL:
+ case OLSHR:
+ ccom(l);
+ ccom(r);
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst <= -t)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ goto common;
+
+ default:
+ if(l != Z)
+ ccom(l);
+ if(r != Z)
+ ccom(r);
+ common:
+ if(l != Z)
+ if(l->op != OCONST)
+ break;
+ if(r != Z)
+ if(r->op != OCONST)
+ break;
+ evconst(n);
+ }
+}
diff --git a/utils/c2l/com64.c b/utils/c2l/com64.c
new file mode 100644
index 00000000..9a193ef3
--- /dev/null
+++ b/utils/c2l/com64.c
@@ -0,0 +1,52 @@
+#include "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+/*
+ * more machine depend stuff.
+ * this is common for 8,16,32,64 bit machines.
+ * this is common for ieee machines.
+ */
+double
+convvtof(vlong v)
+{
+ double d;
+
+ d = v; /* BOTCH */
+ return d;
+}
+
+vlong
+convftov(double d)
+{
+ vlong v;
+
+
+ v = d; /* BOTCH */
+ return v;
+}
+
+double
+convftox(double d, int et)
+{
+
+ if(!typefd[et])
+ diag(Z, "bad type in castftox %s", tnames[et]);
+ return d;
+}
+
+vlong
+convvtox(vlong c, int et)
+{
+ int n;
+
+ n = 8 * ewidth[et];
+ c &= MASK(n);
+ if(!typeu[et])
+ if(c & SIGN(n))
+ c |= ~MASK(n);
+ return c;
+}
diff --git a/utils/c2l/dcl.c b/utils/c2l/dcl.c
new file mode 100644
index 00000000..6fb6977a
--- /dev/null
+++ b/utils/c2l/dcl.c
@@ -0,0 +1,1387 @@
+#include "cc.h"
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n, int gen)
+{
+ Sym *s;
+ Node *n1;
+ long v;
+
+ nearln = lineno;
+ lastfield = 0;
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ default:
+ diag(n, "unknown declarator: %O", n->op);
+ break;
+
+ case OARRAY:
+ t = typ(TARRAY, t);
+ t->width = 0;
+ n1 = n->right;
+ n = n->left;
+ if(n1 != Z) {
+ complex(n1);
+ v = -1;
+ if(n1->op == OCONST)
+ v = n1->vconst;
+ if(v <= 0) {
+ diag(n, "array size must be a positive constant");
+ v = 1;
+ }
+ t->width = v * t->link->width;
+ t->nwidth = n1->left;
+ }
+ goto loop;
+
+ case OIND:
+ t = typ(TIND, t);
+ t->garb = n->garb;
+ n = n->left;
+ goto loop;
+
+ case OFUNC:
+ t = typ(TFUNC, t);
+ t->down = fnproto(n);
+ n = n->left;
+ goto loop;
+
+ case OBIT:
+ n1 = n->right;
+ complex(n1);
+ lastfield = -1;
+ if(n1->op == OCONST)
+ lastfield = n1->vconst;
+ if(lastfield < 0) {
+ diag(n, "field width must be non-negative constant");
+ lastfield = 1;
+ }
+ if(lastfield == 0) {
+ lastbit = 0;
+ firstbit = 1;
+ if(n->left != Z) {
+ diag(n, "zero width named field");
+ lastfield = 1;
+ }
+ }
+ if(!typei[t->etype]) {
+ diag(n, "field type must be int-like");
+ t = types[TINT];
+ lastfield = 1;
+ }
+ if(lastfield > tfield->width*8) {
+ diag(n, "field width larger than field unit");
+ lastfield = 1;
+ }
+ lastbit += lastfield;
+ if(lastbit > tfield->width*8) {
+ lastbit = lastfield;
+ firstbit = 1;
+ }
+ n = n->left;
+ goto loop;
+
+ case ONAME:
+ if(f == NODECL)
+ break;
+ s = n->sym;
+ (*f)(c, t, s);
+ if(s->class == CLOCAL)
+ s = mkstatic(s);
+ firstbit = 0;
+ n->sym = s;
+ n->type = s->type;
+ acidvar(s);
+ if(gen)
+ vtgen(n);
+ break;
+ }
+ lastdcl = t;
+ return n;
+}
+
+Sym*
+mkstatic(Sym *s)
+{
+ Sym *s1;
+
+ if(s->class != CLOCAL)
+ return s;
+ snprint(symb, NSYMB, "%s$%d", s->name, s->block);
+ s1 = lookup();
+ if(s1->class != CSTATIC) {
+ s1->type = s->type;
+ s1->offset = s->offset;
+ s1->block = s->block;
+ s1->class = CSTATIC;
+ }
+ return s1;
+}
+
+/*
+ * make a copy of a typedef
+ * the problem is to split out incomplete
+ * arrays so that it is in the variable
+ * rather than the typedef.
+ */
+Type*
+tcopy(Type *t)
+{
+ Type *tl, *tx;
+ int et;
+
+ if(t == T)
+ return t;
+ et = t->etype;
+ if(typesu[et])
+ return t;
+ tl = tcopy(t->link);
+ if(tl != t->link ||
+ (et == TARRAY && t->width == 0)) {
+ tx = typ(TXXX, 0);
+ *tx = *t;
+ tx->link = tl;
+ return tx;
+ }
+ return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, long o, Node *a)
+{
+ Node *n, *reta;
+
+ if(t == T)
+ return Z;
+ if(s->class == CEXTERN)
+ s->class = CGLOBL;
+ if(0) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "doinit value");
+ }
+
+ n = initlist;
+ if(a->op == OINIT)
+ a = a->left;
+ initlist = a;
+
+ reta = a;
+ init1(s, t, o, 0);
+ if(initlist != Z)
+ diag(initlist, "more initializers than structure: %s",
+ s->name);
+ initlist = n;
+
+ return reta;
+}
+
+/*
+ * get next major operator,
+ * dont advance initlist.
+ */
+Node*
+peekinit(void)
+{
+ Node *a;
+
+ a = initlist;
+
+loop:
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ a = a->left;
+ goto loop;
+ }
+ return a;
+}
+
+/*
+ * consume and return next element on
+ * initlist. expand strings.
+ */
+Node*
+nextinit(void)
+{
+ Node *a, *n;
+
+ a = initlist;
+ n = Z;
+
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ n = a->right;
+ a = a->left;
+ }
+ initlist = n;
+ return a;
+}
+
+int
+isstruct(Node *a, Type *t)
+{
+ Node *n;
+
+ switch(a->op) {
+ case ODOTDOT:
+ n = a->left;
+ if(n && n->type && sametype(n->type, t))
+ return 1;
+ case OSTRING:
+ case OLSTRING:
+ case OCONST:
+ case OINIT:
+ case OELEM:
+ return 0;
+ }
+
+ n = new(ODOTDOT, Z, Z);
+ *n = *a;
+
+ /*
+ * ODOTDOT is a flag for tcom
+ * a second tcom will not be performed
+ */
+ a->op = ODOTDOT;
+ a->left = n;
+ a->right = Z;
+
+ if(tcom(n))
+ return 0;
+
+ if(sametype(n->type, t))
+ return 1;
+ return 0;
+}
+
+void
+init1(Sym *s, Type *t, long o, int exflag)
+{
+ Node *a, *r, nod;
+ Type *t1;
+ long e, w, so, mw;
+
+ a = peekinit();
+ if(a == Z)
+ return;
+
+ if(0) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "init1 value");
+ }
+
+ if(exflag && a->op == OINIT){
+ doinit(s, t, o, nextinit());
+ return;
+ }
+
+ switch(t->etype) {
+ default:
+ diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+ return;
+
+ case TCHAR:
+ case TUCHAR:
+ case TINT:
+ case TUINT:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TIND:
+ single:
+ if(a->op == OARRAY || a->op == OELEM)
+ return;
+
+ a = nextinit();
+ if(a == Z)
+ return;
+
+ if(t->nbits)
+ diag(Z, "cannot initialize bitfields");
+ if(0 && s->class == CAUTO)
+ return;
+
+ complex(a);
+ if(a->type == T)
+ return;
+
+ if(a->op == OCONST) {
+ if(!sametype(a->type, t)) {
+ /* hoop jumping to save malloc */
+ if(nodcast == Z)
+ nodcast = new(OCAST, Z, Z);
+ nod = *nodcast;
+ nod.left = a;
+ nod.type = t;
+ nod.lineno = a->lineno;
+ complex(&nod);
+ if(nod.type)
+ *a = nod;
+ }
+ if(a->op != OCONST) {
+/*
+ diag(a, "initializer is not a constant: %s",
+ s->name);
+*/
+ return;
+ }
+ if(vconst(a) == 0)
+ return;
+ return;
+ }
+ if(t->etype == TIND) {
+ while(a->op == OCAST) {
+ warn(a, "CAST in initialization ignored");
+ a = a->left;
+ }
+ if(0 && !sametype(t, a->type)) {
+ diag(a, "initialization of incompatible pointers: %s",
+ s->name);
+ print("%T and %T\n", t, a->type);
+ }
+/*
+ if(a->op == OADDR)
+ a = a->left;
+*/
+ return;
+ }
+
+ while(a->op == OCAST)
+ a = a->left;
+ if(a->op == OADDR) {
+ warn(a, "initialize pointer to an integer: %s", s->name);
+ /* a = a->left; */
+ return;
+ }
+ /* diag(a, "initializer is not a constant: %s", s->name); */
+ return;
+
+ case TARRAY:
+ w = t->link->width;
+ if(a->op == OSTRING || a->op == OLSTRING)
+ if(typei[t->link->etype]) {
+
+ /*
+ * get rid of null if sizes match exactly
+ */
+ a = nextinit();
+ /* mw = t->width/w; */
+ so = a->type->width/a->type->link->width;
+ if(t->width <= 0)
+ t->width = w*(so-1);
+ USED(a);
+ return;
+ }
+
+ mw = -w;
+ for(e=0;;) {
+ /*
+ * peek ahead for element initializer
+ */
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM && t->link->etype != TSTRUCT)
+ break;
+ if(a->op == OARRAY) {
+ if(e && exflag)
+ break;
+ a = nextinit();
+ r = a->left;
+ complex(r);
+ if(r->op != OCONST) {
+ diag(r, "initializer subscript must be constant");
+ return;
+ }
+ e = r->vconst;
+ if(t->width != 0)
+ if(e < 0 || e*w >= t->width) {
+ diag(a, "initialization index out of range: %ld", e);
+ continue;
+ }
+ }
+
+ so = e*w;
+ if(so > mw)
+ mw = so;
+ if(t->width != 0)
+ if(mw >= t->width)
+ break;
+ init1(s, t->link, o+so, 1);
+ e++;
+ }
+ if(t->width == 0)
+ t->width = mw+w;
+ return;
+
+ case TUNION:
+ case TSTRUCT:
+ /*
+ * peek ahead to find type of rhs.
+ * if its a structure, then treat
+ * this element as a variable
+ * rather than an aggregate.
+ */
+ if(isstruct(a, t))
+ goto single;
+
+ if(t->width <= 0) {
+ diag(Z, "incomplete structure: %s", s->name);
+ return;
+ }
+
+ again:
+ for(t1 = t->link; t1 != T; t1 = t1->down) {
+ if(a->op == OARRAY && t1->etype != TARRAY)
+ break;
+ if(a->op == OELEM) {
+ if(t1->sym != a->sym)
+ continue;
+ nextinit();
+ }
+ init1(s, t1, o+t1->offset, 1);
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM)
+ goto again;
+ }
+ if(a && a->op == OELEM)
+ diag(a, "structure element not found %F", a);
+ return;
+ }
+}
+
+/*
+Node*
+newlist(Node *l, Node *r)
+{
+ if(r == Z)
+ return l;
+ if(l == Z)
+ return r;
+ return new(OLIST, l, r);
+}
+*/
+
+void
+suallign(Type *t)
+{
+ Type *l;
+ long o, w;
+
+ o = 0;
+ switch(t->etype) {
+
+ case TSTRUCT:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->nbits) {
+ if(l->shift <= 0) {
+ l->shift = -l->shift;
+ w = round(w, tfield->width);
+ o = w;
+ w += tfield->width;
+ }
+ l->offset = o;
+ } else {
+ if(l->width <= 0)
+ if(l->sym)
+ diag(Z, "incomplete structure element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete structure element");
+ w = align(w, l, Ael1);
+ l->offset = w;
+ w = align(w, l, Ael2);
+ }
+ }
+ w = align(w, t, Asu2);
+ t->width = w;
+ acidtype(t);
+ ttgen(t);
+ return;
+
+ case TUNION:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->width <= 0)
+ if(l->sym)
+ diag(Z, "incomplete union element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete union element");
+ l->offset = 0;
+ l->shift = 0;
+ o = align(align(0, l, Ael1), l, Ael2);
+ if(o > w)
+ w = o;
+ }
+ w = align(w, t, Asu2);
+ t->width = w;
+ acidtype(t);
+ ttgen(t);
+ return;
+
+ default:
+ diag(Z, "unknown type in suallign: %T", t);
+ break;
+ }
+}
+
+long
+round(long v, int w)
+{
+ int r;
+
+ if(w <= 0 || w > 8) {
+ diag(Z, "rounding by %d", w);
+ w = 1;
+ }
+ r = v%w;
+ if(r)
+ v += w-r;
+ return v;
+}
+
+Type*
+ofnproto(Node *n)
+{
+ Type *tl, *tr, *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ tl = ofnproto(n->left);
+ tr = ofnproto(n->right);
+ if(tl == T)
+ return tr;
+ tl->down = tr;
+ return tl;
+
+ case ONAME:
+ if(n->type == T)
+ n->type = n->sym->type;
+ t = typ(TXXX, T);
+ *t = *n->sym->type;
+ t->down = T;
+ return t;
+ }
+ return T;
+}
+
+#define ANSIPROTO 1
+#define OLDPROTO 2
+
+void
+argmark(Node *n, int pass)
+{
+ Type *t;
+
+ autoffset = align(0, thisfn->link, Aarg0);
+ for(; n->left != Z; n = n->left) {
+ if(n->op != OFUNC || n->left->op != ONAME)
+ continue;
+ walkparam(n->right, pass);
+ if(pass != 0 && anyproto(n->right) == OLDPROTO) {
+ t = typ(TFUNC, n->left->sym->type->link);
+ t->down = typ(TOLD, T);
+ t->down->down = ofnproto(n->right);
+ tmerge(t, n->left->sym);
+ n->left->sym->type = t;
+ }
+ break;
+ }
+ autoffset = 0;
+}
+
+void
+walkparam(Node *n, int pass)
+{
+ Sym *s;
+ Node *n1;
+
+ if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
+ return;
+
+loop:
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ diag(n, "argument not a name/prototype: %O", n->op);
+ break;
+
+ case OLIST:
+ walkparam(n->left, pass);
+ n = n->right;
+ goto loop;
+
+ case OPROTO:
+ for(n1 = n; n1 != Z; n1=n1->left)
+ if(n1->op == ONAME) {
+ if(pass == 0) {
+ s = n1->sym;
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ dodecl(pdecl, CPARAM, n->type, n->left, 1);
+ break;
+ }
+ if(n1)
+ break;
+ if(pass == 0) {
+ /*
+ * extension:
+ * allow no name in argument declaration
+ diag(Z, "no name in argument declaration");
+ */
+ break;
+ }
+ dodecl(NODECL, CPARAM, n->type, n->left, 1);
+ pdecl(CPARAM, lastdcl, S);
+ break;
+
+ case ODOTDOT:
+ break;
+
+ case ONAME:
+ s = n->sym;
+ if(pass == 0) {
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ if(s->offset != -1) {
+ autoffset = align(autoffset, s->type, Aarg1);
+ s->offset = autoffset;
+ autoffset = align(autoffset, s->type, Aarg2);
+ } else
+ dodecl(pdecl, CXXX, types[TINT], n, 1);
+ break;
+ }
+}
+
+void
+markdcl(void)
+{
+ Decl *d;
+
+ blockno++;
+ d = push();
+ d->val = DMARK;
+ d->offset = autoffset;
+ d->block = autobn;
+ autobn = blockno;
+}
+
+Node*
+revertdcl(void)
+{
+ Decl *d;
+ Sym *s;
+
+ for(;;) {
+ d = dclstack;
+ if(d == D) {
+ diag(Z, "pop off dcl stack");
+ break;
+ }
+ dclstack = d->link;
+ s = d->sym;
+ switch(d->val) {
+ case DMARK:
+ autoffset = d->offset;
+ autobn = d->block;
+ free(d);
+ return Z;
+
+ case DAUTO:
+ if(0) {
+ if(s->class == CAUTO)
+ warn(Z, "auto declared and not used: %s", s->name);
+ if(s->class == CPARAM)
+ warn(Z, "param declared and not used: %s", s->name);
+ }
+ s->type = d->type;
+ s->class = d->class;
+ s->offset = d->offset;
+ s->block = d->block;
+ s->lineno = d->lineno;
+ break;
+
+ case DSUE:
+ s->suetag = d->type;
+ s->sueblock = d->block;
+ s->lineno = d->lineno;
+ break;
+
+ case DLABEL:
+ if(0 && s->label)
+ warn(s->label, "label declared and not used \"%s\"", s->name);
+ s->label = Z;
+ s->lineno = d->lineno;
+ break;
+ }
+ free(d);
+ }
+ return Z;
+}
+
+Type*
+fnproto(Node *n)
+{
+ int r;
+
+ r = anyproto(n->right);
+ if(r == 0 || (r & OLDPROTO)) {
+ if(r & ANSIPROTO)
+ diag(n, "mixed ansi/old function declaration: %F", n->left);
+ return T;
+ }
+ return fnproto1(n->right);
+}
+
+int
+anyproto(Node *n)
+{
+ int r;
+
+ r = 0;
+
+loop:
+ if(n == Z)
+ return r;
+ switch(n->op) {
+ case OLIST:
+ r |= anyproto(n->left);
+ n = n->right;
+ goto loop;
+
+ case ODOTDOT:
+ case OPROTO:
+ return r | ANSIPROTO;
+ }
+ return r | OLDPROTO;
+}
+
+Type*
+fnproto1(Node *n)
+{
+ Type *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ t = fnproto1(n->left);
+ if(t != T)
+ t->down = fnproto1(n->right);
+ return t;
+
+ case OPROTO:
+ lastdcl = T;
+ n = dodecl(NODECL, CXXX, n->type, n->left, 1);
+ t = typ(TXXX, T);
+ if(lastdcl != T)
+ *t = *paramconv(lastdcl, 1);
+ if(n != Z && n->op == ONAME)
+ t->sym = n->sym;
+ return t;
+
+ case ONAME:
+ diag(n, "incomplete argument prototype");
+ return typ(TINT, T);
+
+ case ODOTDOT:
+ return typ(TDOT, T);
+ }
+ diag(n, "unknown op in fnproto");
+ return T;
+}
+
+void
+dbgdecl(Sym *s)
+{
+
+ print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n",
+ s->name, cnames[s->class], s->block, s->offset, s->type);
+}
+
+Decl*
+push(void)
+{
+ static Decl zdecl;
+ Decl *d;
+
+ d = alloc(sizeof(*d));
+ *d = zdecl;
+ d->link = dclstack;
+ dclstack = d;
+ return d;
+}
+
+Decl*
+push1(Sym *s)
+{
+ Decl *d;
+
+ d = push();
+ d->sym = s;
+ d->val = DAUTO;
+ d->type = s->type;
+ d->class = s->class;
+ d->offset = s->offset;
+ d->block = s->block;
+ d->lineno = s->lineno;
+ return d;
+}
+
+int
+sametype(Type *t1, Type *t2)
+{
+
+ if(t1 == t2)
+ return 1;
+ return rsametype(t1, t2, 5, 1);
+}
+
+int
+rsametype(Type *t1, Type *t2, int n, int f)
+{
+ int et;
+
+ n--;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(n <= 0)
+ return 1;
+ et = t1->etype;
+ if(et != t2->etype)
+ return 0;
+ if(et == TFUNC) {
+ if(!rsametype(t1->link, t2->link, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ while(t1 != T && t2 != T) {
+ if(t1->etype == TOLD) {
+ t1 = t1->down;
+ continue;
+ }
+ if(t2->etype == TOLD) {
+ t2 = t2->down;
+ continue;
+ }
+ while(t1 != T || t2 != T) {
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ break;
+ }
+ return 1;
+ }
+ if(et == TARRAY)
+ if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
+ return 0;
+ if(typesu[et] || et == TTUPLE) {
+ if(t1->link == T)
+ snap(t1);
+ if(t2->link == T)
+ snap(t2);
+ t1 = t1->link;
+ t2 = t2->link;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ if((f || 1) && et == TIND) {
+ if(t1 != T && t1->etype == TVOID)
+ return 1;
+ if(t2 != T && t2->etype == TVOID)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ulong
+signature(Type *t, int n)
+{
+ Type *t1;
+ long s;
+
+ s = 0;
+ if(n > 0)
+ for(; t; t=t->link) {
+ s = s*thash1 + thash[t->etype];
+ switch(t->etype) {
+ default:
+ return s;
+ case TARRAY:
+ s = s*thash2 + t->width;
+ break;
+ case TFUNC:
+ case TSTRUCT:
+ case TUNION:
+ for(t1=t; t1; t1=t1->down)
+ s = s*thash3 + signature(t1, n-1);
+ case TIND:
+ break;
+ }
+ }
+ return s;
+}
+
+void
+snap(Type *t)
+{
+ if(typesu[t->etype])
+ if(t->link == T && t->tag && t->tag->suetag) {
+ t->link = t->tag->suetag->link;
+ t->width = t->tag->suetag->width;
+ }
+}
+
+Type*
+dotag(Sym *s, int et, int bn)
+{
+ Decl *d;
+
+ if(bn != 0 && bn != s->sueblock) {
+ d = push();
+ d->sym = s;
+ d->val = DSUE;
+ d->type = s->suetag;
+ d->block = s->sueblock;
+ d->lineno = s->lineno;
+ s->suetag = T;
+ }
+ if(s->suetag == T) {
+ s->suetag = typ(et, T);
+ s->sueblock = autobn;
+ }
+ if(s->suetag->etype != et)
+ diag(Z, "tag used for more than one type: %s",
+ s->name);
+ if(s->suetag->tag == S)
+ s->suetag->tag = s;
+ return s->suetag;
+}
+
+Node*
+dcllabel(Sym *s, int f)
+{
+ Decl *d, d1;
+ Node *n;
+
+ n = s->label;
+ if(n != Z) {
+ if(f) {
+ if(0)
+ diag(Z, "label reused: %s", s->name);
+ }
+ return n;
+ }
+
+ d = push();
+ d->sym = s;
+ d->val = DLABEL;
+ d->lineno = s->lineno;
+ dclstack = d->link;
+
+ d1 = *firstdcl;
+ *firstdcl = *d;
+ *d = d1;
+
+ firstdcl->link = d;
+ firstdcl = d;
+
+ n = new(OXXX, Z, Z);
+ n->sym = s;
+ s->label = n;
+ return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+ f = 1;
+ switch(t->etype) {
+ case TUNION:
+ case TSTRUCT:
+ if(t->width <= 0)
+ diag(Z, "incomplete structure: %s", t->tag->name);
+ break;
+
+ case TARRAY:
+ t = typ(TIND, t->link);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFUNC:
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFLOAT:
+ if(!f)
+ t = types[TDOUBLE];
+ break;
+
+ case TCHAR:
+ case TSHORT:
+ if(!f)
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ if(!f)
+ t = types[TUINT];
+ break;
+ }
+ return t;
+}
+
+void
+adecl(int c, Type *t, Sym *s)
+{
+
+ if(c == CSTATIC)
+ c = CLOCAL;
+ if(t->etype == TFUNC) {
+ if(c == CXXX)
+ c = CEXTERN;
+ if(c == CLOCAL)
+ c = CSTATIC;
+ if(c == CAUTO || c == CEXREG)
+ diag(Z, "function cannot be %s %s", cnames[c], s->name);
+ }
+ if(c == CXXX)
+ c = CAUTO;
+ if(s) {
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "just say static: %s", s->name);
+ c = CSTATIC;
+ }
+ if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
+ if(s->block == autobn)
+ diag(Z, "auto redeclaration of: %s", s->name);
+ if(c != CPARAM)
+ push1(s);
+ s->block = autobn;
+ s->offset = 0;
+ s->type = t;
+ s->class = c;
+ }
+ switch(c) {
+ case CAUTO:
+ autoffset = align(autoffset, t, Aaut3);
+ s->offset = -autoffset;
+ break;
+
+ case CPARAM:
+ autoffset = align(autoffset, t, Aarg1);
+ if(s)
+ s->offset = autoffset;
+ autoffset = align(autoffset, t, Aarg2);
+ break;
+ }
+ if(s)
+ s->lineno = lineno;
+}
+
+void
+pdecl(int c, Type *t, Sym *s)
+{
+ if(s && s->offset != -1) {
+ diag(Z, "not a parameter: %s", s->name);
+ return;
+ }
+ t = paramconv(t, c==CPARAM);
+ if(c == CXXX)
+ c = CPARAM;
+ if(c != CPARAM) {
+ diag(Z, "parameter cannot have class: %s", s->name);
+ c = CPARAM;
+ }
+ adecl(c, t, s);
+ if(s)
+ s->lineno = lineno;
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+ long o;
+
+ o = 0;
+ if(c == CEXREG)
+ c = CEXTERN;
+ if(c == CXXX) {
+ c = CGLOBL;
+ if(s->class == CEXTERN)
+ s->class = c;
+ }
+ if(c == CEXTERN)
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ if(c == CAUTO) {
+ diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CEXTERN;
+ }
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CSTATIC;
+ }
+ if(s->type != T)
+ if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
+ diag(Z, "external redeclaration of: %s", s->name);
+ print(" %s %T; %s %T\n", cnames[c], t, cnames[s->class], s->type);
+ }
+ tmerge(t, s);
+ s->type = t;
+ s->class = c;
+ s->block = 0;
+ s->offset = o;
+}
+
+void
+tmerge(Type *t1, Sym *s)
+{
+ Type *ta, *tb, *t2;
+
+ t2 = s->type;
+/*print("merge %T; %T\n", t1, t2);/**/
+ for(;;) {
+ if(t1 == T || t2 == T || t1 == t2)
+ break;
+ if(t1->etype != t2->etype)
+ break;
+ switch(t1->etype) {
+ case TFUNC:
+ ta = t1->down;
+ tb = t2->down;
+ if(ta == T) {
+ t1->down = tb;
+ break;
+ }
+ if(tb == T)
+ break;
+ while(ta != T && tb != T) {
+ if(ta == tb)
+ break;
+ /* ignore old-style flag */
+ if(ta->etype == TOLD) {
+ ta = ta->down;
+ continue;
+ }
+ if(tb->etype == TOLD) {
+ tb = tb->down;
+ continue;
+ }
+ /* checking terminated by ... */
+ if(ta->etype == TDOT && tb->etype == TDOT) {
+ ta = T;
+ tb = T;
+ break;
+ }
+ if(!sametype(ta, tb))
+ break;
+ ta = ta->down;
+ tb = tb->down;
+ }
+ if(ta != tb)
+ diag(Z, "function inconsistently declared: %s", s->name);
+
+ /* take new-style over old-style */
+ ta = t1->down;
+ tb = t2->down;
+ if(ta != T && ta->etype == TOLD)
+ if(tb != T && tb->etype != TOLD)
+ t1->down = tb;
+ break;
+
+ case TARRAY:
+ /* should we check array size change? */
+ if(t2->width > t1->width)
+ t1->width = t2->width;
+ break;
+
+ case TUNION:
+ case TSTRUCT:
+ return;
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ }
+}
+
+void
+edecl(int c, Type *t, Sym *s)
+{
+ long l;
+ Type *t1;
+
+ if(s == S) {
+ if(!typesu[t->etype])
+ diag(Z, "unnamed structure element must be struct/union");
+ if(c != CXXX)
+ diag(Z, "unnamed structure element cannot have class");
+ } else
+ if(c != CXXX)
+ diag(Z, "structure element cannot have class: %s", s->name);
+ t1 = t;
+ t = typ(TXXX, T);
+ l = t->lineno;
+ *t = *t1;
+ t->lineno = l;
+ t->sym = s;
+ t->down = T;
+ if(lastfield) {
+ t->shift = lastbit - lastfield;
+ t->nbits = lastfield;
+ if(firstbit)
+ t->shift = -t->shift;
+ if(typeu[t->etype])
+ t->etype = tufield->etype;
+ else
+ t->etype = tfield->etype;
+ }
+ if(strf == T)
+ strf = t;
+ else
+ strl->down = t;
+ strl = t;
+}
+
+/*
+ * this routine is very suspect.
+ * ansi requires the enum type to
+ * be represented as an 'int'
+ * this means that 0x81234567
+ * would be illegal. this routine
+ * makes signed and unsigned go
+ * to unsigned.
+ */
+Type*
+maxtype(Type *t1, Type *t2)
+{
+
+ if(t1 == T)
+ return t2;
+ if(t2 == T)
+ return t1;
+ if(t1->etype > t2->etype)
+ return t1;
+ return t2;
+}
+
+void
+doenum(Sym *s, Node *n)
+{
+ int k = KDEC;
+ Node *nc;
+
+ nc = Z;
+ if(n) {
+ k = n->kind;
+ complex(n);
+ if(n->op != OCONST && n->op != OSTRING && n->op != OLSTRING) {
+ diag(n, "enum not a constant: %s", s->name);
+ return;
+ }
+ nc = n->left;
+ en.cenum = n->type;
+ en.tenum = maxtype(en.cenum, en.tenum);
+
+ if(!typefd[en.cenum->etype])
+ en.lastenum = n->vconst;
+ else
+ en.floatenum = n->fconst;
+ }
+ if(dclstack)
+ push1(s);
+ xdecl(CXXX, types[TENUM], s);
+
+ if(en.cenum == T) {
+ en.tenum = types[TINT];
+ en.cenum = types[TINT];
+ en.lastenum = 0;
+ }
+ s->tenum = en.cenum;
+
+ if(s->tenum->etype == TIND){ /* string */
+ nc = n;
+ s->tenum = n->type;
+ }
+ else if(!typefd[s->tenum->etype]) {
+ s->vconst = convvtox(en.lastenum, s->tenum->etype);
+ en.lastenum++;
+ s->tenum = types[TINT];
+ } else {
+ s->fconst = en.floatenum;
+ if(n)
+ s->cstring = n->cstring;
+ else
+ s->cstring = nil;
+ en.floatenum++;
+ s->tenum = types[TDOUBLE];
+ }
+ s->nconst = nc;
+
+ acidvar(s);
+ s->kind = k;
+ etgen(s);
+}
+
+void
+symadjust(Sym *s, Node *n, long del)
+{
+
+ switch(n->op) {
+ default:
+ if(n->left)
+ symadjust(s, n->left, del);
+ if(n->right)
+ symadjust(s, n->right, del);
+ return;
+
+ case ONAME:
+ return;
+
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+ }
+}
diff --git a/utils/c2l/dpchk.c b/utils/c2l/dpchk.c
new file mode 100644
index 00000000..78865cb8
--- /dev/null
+++ b/utils/c2l/dpchk.c
@@ -0,0 +1,392 @@
+#include "cc.h"
+#include "y.tab.h"
+
+enum
+{
+ Fnone = 0,
+ Fl,
+ Fvl,
+ Fignor,
+ Fstar,
+ Fadj,
+
+ Fverb = 10,
+};
+
+typedef struct Tprot Tprot;
+struct Tprot
+{
+ Type* type;
+ Bits flag;
+ Tprot* link;
+};
+
+typedef struct Tname Tname;
+struct Tname
+{
+ char* name;
+ int param;
+ Tname* link;
+};
+
+static Type* indchar;
+static uchar flagbits[256];
+static char fmtbuf[100];
+static int lastadj;
+static int lastverb;
+static int nstar;
+static Tprot* tprot;
+static Tname* tname;
+
+void
+argflag(int c, int v)
+{
+
+ switch(v) {
+ case Fignor:
+ case Fstar:
+ case Fl:
+ case Fvl:
+ flagbits[c] = v;
+ break;
+ case Fverb:
+ flagbits[c] = lastverb;
+/*print("flag-v %c %d\n", c, lastadj);*/
+ lastverb++;
+ break;
+ case Fadj:
+ flagbits[c] = lastadj;
+/*print("flag-l %c %d\n", c, lastadj);*/
+ lastadj++;
+ break;
+ }
+}
+
+Bits
+getflag(char *s)
+{
+ Bits flag;
+ int c, f;
+ char *fmt;
+
+ fmt = fmtbuf;
+ flag = zbits;
+ nstar = 0;
+ while(c = *s++) {
+ *fmt++ = c;
+ f = flagbits[c];
+ switch(f) {
+ case Fnone:
+ argflag(c, Fverb);
+ f = flagbits[c];
+ break;
+ case Fstar:
+ nstar++;
+ case Fignor:
+ continue;
+ case Fl:
+ if(bset(flag, Fl))
+ flag = bor(flag, blsh(Fvl));
+ }
+ flag = bor(flag, blsh(f));
+ if(f >= Fverb)
+ break;
+ }
+ *fmt = 0;
+ return flag;
+}
+
+void
+newprot(Sym *m, Type *t, char *s)
+{
+ Bits flag;
+ Tprot *l;
+
+ if(t == T) {
+ warn(Z, "%s: newprot: type not defined", m->name);
+ return;
+ }
+ flag = getflag(s);
+ for(l=tprot; l; l=l->link)
+ if(beq(flag, l->flag) && sametype(t, l->type))
+ return;
+ l = alloc(sizeof(*l));
+ l->type = t;
+ l->flag = flag;
+ l->link = tprot;
+ tprot = l;
+}
+
+void
+newname(char *s, int p)
+{
+ Tname *l;
+
+ for(l=tname; l; l=l->link)
+ if(strcmp(l->name, s) == 0) {
+ if(l->param != p)
+ yyerror("vargck %s already defined\n", s);
+ return;
+ }
+ l = alloc(sizeof(*l));
+ l->name = s;
+ l->param = p;
+ l->link = tname;
+ tname = l;
+}
+
+void
+arginit(void)
+{
+ int i;
+
+ lastadj = Fadj;
+ lastverb = Fverb;
+ indchar = typ(TIND, types[TCHAR]);
+
+ memset(flagbits, Fnone, sizeof(flagbits));
+
+ for(i='0'; i<='9'; i++)
+ argflag(i, Fignor);
+ argflag('.', Fignor);
+ argflag('#', Fignor);
+ argflag('u', Fignor);
+ argflag('+', Fignor);
+ argflag('-', Fignor);
+
+ argflag('*', Fstar);
+ argflag('l', Fl);
+
+ argflag('o', Fverb);
+ flagbits['x'] = flagbits['o'];
+ flagbits['X'] = flagbits['o'];
+}
+
+void
+pragvararg(void)
+{
+ Sym *s;
+ int n, c;
+ char *t;
+
+ if(1)
+ goto out;
+ s = getsym();
+ if(s && strcmp(s->name, "argpos") == 0)
+ goto ckpos;
+ if(s && strcmp(s->name, "type") == 0)
+ goto cktype;
+ yyerror("syntax in #pragma varargck");
+ goto out;
+
+ckpos:
+/*#pragma varargck argpos warn 2*/
+ s = getsym();
+ if(s == S)
+ goto bad;
+ n = getnsn();
+ if(n < 0)
+ goto bad;
+ newname(s->name, n);
+ goto out;
+
+cktype:
+/*#pragma varargck type O int*/
+ c = getnsc();
+ if(c != '"')
+ goto bad;
+ t = fmtbuf;
+ for(;;) {
+ c = getc();
+ if(c == ' ' || c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ *t++ = c;
+ }
+ *t = 0;
+ t = strdup(fmtbuf);
+ s = getsym();
+ if(s == S)
+ goto bad;
+ c = getnsc();
+ unget(c);
+ if(c == '*')
+ newprot(s, typ(TIND, s->type), t);
+ else
+ newprot(s, s->type, t);
+ goto out;
+
+bad:
+ yyerror("syntax in #pragma varargck");
+
+out:
+ while(getnsc() != '\n')
+ ;
+}
+
+Node*
+nextarg(Node *n, Node **a)
+{
+ if(n == Z) {
+ *a = Z;
+ return Z;
+ }
+ if(n->op == OLIST) {
+ *a = n->left;
+ return n->right;
+ }
+ *a = n;
+ return Z;
+}
+
+void
+checkargs(Node *nn, char *s, int pos)
+{
+ Node *a, *n;
+ Bits flag;
+ Tprot *l;
+
+ if(1)
+ return;
+ n = nn;
+ for(;;) {
+ s = strchr(s, '%');
+ if(s == 0) {
+ nextarg(n, &a);
+ if(a != Z)
+ warn(nn, "more arguments than format %T",
+ a->type);
+ return;
+ }
+ s++;
+ flag = getflag(s);
+ while(nstar > 0) {
+ n = nextarg(n, &a);
+ pos++;
+ nstar--;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ fmtbuf);
+ return;
+ }
+ if(a->type == T)
+ continue;
+ if(!sametype(types[TINT], a->type) &&
+ !sametype(types[TUINT], a->type))
+ warn(nn, "format mismatch '*' in %s %T, arg %d",
+ fmtbuf, a->type, pos);
+ }
+ for(l=tprot; l; l=l->link)
+ if(sametype(types[TVOID], l->type)) {
+ if(beq(flag, l->flag)) {
+ s++;
+ goto loop;
+ }
+ }
+
+ n = nextarg(n, &a);
+ pos++;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ fmtbuf);
+ return;
+ }
+ if(a->type == 0)
+ continue;
+ for(l=tprot; l; l=l->link)
+ if(sametype(a->type, l->type))
+ if(beq(flag, l->flag))
+ goto loop;
+ warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
+ loop:;
+ }
+}
+
+void
+dpcheck(Node *n)
+{
+ char *s;
+ Node *a, *b;
+ Tname *l;
+ int i;
+
+ if(n == Z)
+ return;
+ b = n->left;
+ if(b == Z || b->op != ONAME)
+ return;
+ s = b->sym->name;
+ for(l=tname; l; l=l->link)
+ if(strcmp(s, l->name) == 0)
+ break;
+ if(l == 0)
+ return;
+
+ i = l->param;
+ b = n->right;
+ while(i > 0) {
+ b = nextarg(b, &a);
+ i--;
+ }
+ if(a == Z) {
+ warn(n, "cant find format arg");
+ return;
+ }
+ if(!sametype(indchar, a->type)) {
+ warn(n, "format arg type %T", a->type);
+ return;
+ }
+ if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
+/* warn(n, "format arg not constant string");*/
+ return;
+ }
+ s = a->left->cstring;
+ checkargs(b, s, l->param);
+}
+
+void
+praghjdicks(void)
+{
+ Sym *s;
+
+ hjdickflg = 0;
+ s = getsym();
+ if(s) {
+ hjdickflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0 ||
+ strcmp(s->name, "dick") == 0)
+ hjdickflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(0)
+ if(hjdickflg)
+ print("%4ld: hjdicks %d\n", lineno, hjdickflg);
+ else
+ print("%4ld: hjdicks off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+ Sym *s;
+
+ fproundflg = 0;
+ s = getsym();
+ if(s) {
+ hjdickflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0 ||
+ strcmp(s->name, "dick") == 0)
+ fproundflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(0)
+ if(fproundflg)
+ print("%4ld: fproundflg %d\n", lineno, fproundflg);
+ else
+ print("%4ld: fproundflg off\n", lineno);
+}
diff --git a/utils/c2l/lex.c b/utils/c2l/lex.c
new file mode 100644
index 00000000..5701dd99
--- /dev/null
+++ b/utils/c2l/lex.c
@@ -0,0 +1,1675 @@
+#include "cc.h"
+#include "y.tab.h"
+
+#ifndef CPP
+#define CPP "/bin/cpp"
+#endif
+
+static int ansip;
+
+void
+main(int argc, char *argv[])
+{
+ char *defs[50], *p;
+ int nproc, nout, status, i, c, ndef;
+
+ tinit();
+ cinit();
+ ginit();
+ arginit();
+
+ tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+ ndef = 0;
+ include[ninclude++] = ".";
+ strings = 1;
+ passes = 1;
+
+ ARGBEGIN {
+ default:
+ break;
+
+ case 'p':
+ ansip = 1;
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ defs[ndef++] = p;
+ dodefine(p);
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+
+ case 'm':
+ domod = 1;
+ break;
+
+ case 'i':
+ doinc = 1;
+ break;
+
+ case 'l':
+ doloc = 1;
+ break;
+
+ case 'c':
+ justcode = 1;
+ break;
+
+ case 'v':
+ comm = 1;
+ break;
+
+ case 's':
+ strings = 0;
+ break;
+
+ case 'S':
+ strings = 2;
+ break;
+
+ case 'M':
+ inmain = 1;
+ break;
+
+ case 'q':
+ passes = 0;
+ break;
+
+ case 'a':
+ doaddr = 1;
+ break;
+
+ case 'A':
+ doaddr = 1;
+ doalladdr = 1;
+ break;
+
+ } ARGEND
+
+ if(doinc)
+ domod = doloc = 0;
+
+ linit();
+
+ if(argc != 1) {
+ print("usage: c2l [-options] file\n");
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't compile multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0) {
+ print("cannot create a process\n");
+ errorexit();
+ }
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ fprint(2, "%s:\n", *argv);
+ if (compile(*argv, defs, ndef))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+
+ if(argc == 0)
+ c = compile("stdin", defs, ndef);
+ else
+ c = compile(argv[0], defs, ndef);
+
+ if(c)
+ errorexit();
+ exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+ char ofile[200], incfile[20];
+ char *p, *av[100], opt[256];
+ int i, c, fd[2];
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ *p++ = 0;
+ include[0] = strdup(ofile);
+ } else
+ p = ofile;
+
+ USED(p);
+ if(p = getenv("INCLUDE")) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile, "/%s/include", thestring);
+ setinclude(strdup(incfile));
+ setinclude("/sys/include");
+ }
+ }
+ newio();
+
+ /* Use an ANSI preprocessor */
+ if(ansip) {
+ if(systemtype(Windows)) {
+ diag(Z, "-p option not supported on windows");
+ errorexit();
+ }
+ if(mypipe(fd) < 0) {
+ diag(Z, "pipe failed");
+ errorexit();
+ }
+ switch(myfork()) {
+ case -1:
+ diag(Z, "fork failed");
+ errorexit();
+ case 0:
+ close(fd[0]);
+ mydup(fd[1], 1);
+ close(fd[1]);
+ av[0] = CPP;
+ i = 1;
+ for(c = 0; c < ndef; c++) {
+ sprint(opt, "-D%s", defs[c]);
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ninclude; c++) {
+ sprint(opt, "-I%s", include[c]);
+ av[i++] = strdup(opt);
+ }
+ if(strcmp(file, "stdin") != 0)
+ av[i++] = file;
+ av[i] = 0;
+ if(0) {
+ for(c = 0; c < i; c++)
+ fprint(2, "%s ", av[c]);
+ print("\n");
+ }
+ myexec(av[0], av);
+ fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+ errorexit();
+ default:
+ close(fd[1]);
+ newfile(file, fd[0]);
+ break;
+ }
+ } else {
+ if(strcmp(file, "stdin") == 0)
+ newfile(file, 0);
+ else
+ newfile(file, -1);
+ }
+
+ clbegin();
+ yyparse();
+ clend();
+ newsec(0);
+ return nerrors;
+}
+
+void
+errorexit(void)
+{
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ if(0)
+ print("%L: %s\n", lineno, s);
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("c2l: %r: %s", s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+ outpush(s);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ static Sym zsym;
+ Sym *s;
+ ulong h;
+ char *p;
+ int c, n;
+
+ h = 0;
+ for(p=symb; *p;) {
+ h = h * 3;
+ h += *p++;
+ }
+ n = (p - symb) + 1;
+ if((long)h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, symb) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ *s = zsym;
+ s->name = alloc(n);
+ memmove(s->name, symb, n);
+
+ strcpy(s->name, symb);
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+
+ return s;
+}
+
+void
+syminit(Sym *s)
+{
+ s->lexical = LNAME;
+ s->type = T;
+ s->suetag = T;
+ s->class = CXXX;
+ s->lname = s->mod = nil;
+ s->lineno = lineno;
+ s->tenum = T;
+}
+
+#define EOF (-1)
+#define IGN (-2)
+#define ESC (1<<20)
+#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+ Numdec = 1<<0,
+ Numlong = 1<<1,
+ Numuns = 1<<2,
+ Numvlong = 1<<3,
+ Numflt = 1<<4,
+};
+
+static int ypeek = 0;
+
+long
+yylex(void)
+{
+ vlong vv;
+ long c, c1;
+ char *cp;
+ Rune rune;
+ Sym *s;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c >= Runeself) {
+ /*
+ * extension --
+ * all multibyte runes are alpha
+ */
+ cp = symb;
+ goto talph;
+ }
+ if(isspace(c)) {
+ if(c == '\n')
+ lineno++;
+ goto l0;
+ }
+ if(isalpha(c)) {
+ cp = symb;
+ if(c != 'L')
+ goto talph;
+ *cp++ = c;
+ c = GETC();
+ if(c == '\'') {
+ /* L'x' */
+ c = escchar('\'', 1, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 1, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ yylval.vval = convvtox(c, TUSHORT);
+ return LUCONST;
+ }
+ if(c == '"') {
+ goto caselq;
+ }
+ goto talph;
+ }
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+
+ case EOF:
+ peekc = EOF;
+ return -1;
+
+ case '_':
+ cp = symb;
+ goto talph;
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c1 = GETC();
+ if(isdigit(c1)) {
+ cp = symb;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ strcpy(symb, "\"<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+
+ /* "..." */
+ for(;;) {
+ c = escchar('"', 0, 1);
+ if(c == EOF)
+ break;
+ if(c & ESC) {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = allocn(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LSTRING;
+
+ caselq:
+ /* L"..." */
+ strcpy(symb, "\"L<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+ for(;;) {
+ c = escchar('"', 1, 0);
+ if(c == EOF)
+ break;
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = c;
+ c1 += sizeof(ushort);
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = 0;
+ c1 += sizeof(ushort);
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LLSTRING;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', 0, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 0, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ vv = c;
+ yylval.vval = convvtox(vv, TUCHAR);
+ if(yylval.vval != vv)
+ yyerror("overflow in character constant: 0x%lx", c);
+ else
+ if(c & 0x80)
+ warn(Z, "sign-extended character constant");
+ yylval.vval = convvtox(vv, TCHAR);
+ return LCHARACTER;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '*') {
+ startcom(lineno);
+ for(;;) {
+ c = getr();
+ if(c == '*'){
+ while(c == '*') {
+ c = getr();
+ if(c == '/'){
+ endcom();
+ goto l0;
+ }
+ addcom('*');
+ }
+ addcom(c);
+ }
+ else
+ addcom(c);
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ startcom(lineno);
+ for(;;) {
+ c = getr();
+ if(c == '\n'){
+ endcom();
+ goto l0;
+ }
+ addcom(c);
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=')
+ return LDVE;
+ break;
+
+ case '*':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMLE;
+ break;
+
+ case '%':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMDE;
+ break;
+
+ case '+':
+ c1 = GETC();
+ if(c1 == '+')
+ return LPP;
+ if(c1 == '=')
+ return LPE;
+ break;
+
+ case '-':
+ c1 = GETC();
+ if(c1 == '-')
+ return LMM;
+ if(c1 == '=')
+ return LME;
+ if(c1 == '>')
+ return LMG;
+ break;
+
+ case '>':
+ c1 = GETC();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LRSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LGE;
+ break;
+
+ case '<':
+ c1 = GETC();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LLSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LLE;
+ break;
+
+ case '=':
+ c1 = GETC();
+ if(c1 == '=')
+ return LEQ;
+ break;
+
+ case '!':
+ c1 = GETC();
+ if(c1 == '=')
+ return LNE;
+ break;
+
+ case '&':
+ c1 = GETC();
+ if(c1 == '&')
+ return LANDAND;
+ if(c1 == '=')
+ return LANDE;
+ break;
+
+ case '|':
+ c1 = GETC();
+ if(c1 == '|')
+ return LOROR;
+ if(c1 == '=')
+ return LORE;
+ break;
+
+ case '^':
+ c1 = GETC();
+ if(c1 == '=')
+ return LXORE;
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+
+talph:
+ /*
+ * cp is set to symb and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = GETC();
+ }
+ cp += c1;
+ c = GETC();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ *cp = 0;
+ if(0)
+ print("%L: %s\n", lineno, symb);
+ peekc = c;
+ s = lookup();
+ if(s->macro && !ypeek) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ /* outpush(nil); */
+ goto l0;
+ }
+ yylval.sym = s;
+ if(s->class == CTYPEDEF) {
+ if(s->type && typesu[s->type->etype])
+ return LCTYPE;
+ return LSTYPE;
+ }
+ return s->lexical;
+
+tnum:
+ lastnumbase = KDEC;
+ c1 = 0;
+ cp = symb;
+ if(c != '0') {
+ c1 |= Numdec;
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = GETC();
+ if(c == 'x' || c == 'X'){
+ lastnumbase = KHEX;
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == symb+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ }
+ else
+ lastnumbase = KOCT;
+ if(c < '0' || c > '7'){
+ lastnumbase = KDEC;
+ goto dc;
+ }
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = GETC();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+ c = GETC();
+ c1 |= Numuns;
+ goto ncu;
+ }
+ if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+ c = GETC();
+ if(c1 & Numlong)
+ c1 |= Numvlong;
+ c1 |= Numlong;
+ goto ncu;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatov(symb, &yylval.vval))
+ yyerror("overflow in constant");
+
+ vv = yylval.vval;
+ if(c1 & Numvlong) {
+ if(c1 & Numuns) {
+ c = LUVLCONST;
+ goto nret;
+ }
+ yylval.vval = convvtox(yylval.vval, TVLONG);
+ if(yylval.vval < 0) {
+ c = LUVLCONST;
+ goto nret;
+ }
+ c = LVLCONST;
+ goto nret;
+ }
+ if(c1 & Numlong) {
+ if(c1 & Numuns) {
+ c = LULCONST;
+ goto nret;
+ }
+ yylval.vval = convvtox(yylval.vval, TLONG);
+ if(yylval.vval < 0) {
+ c = LULCONST;
+ goto nret;
+ }
+ c = LLCONST;
+ goto nret;
+ }
+ if(c1 & Numuns) {
+ c = LUCONST;
+ goto nret;
+ }
+ yylval.vval = convvtox(yylval.vval, TINT);
+ if(yylval.vval < 0) {
+ c = LUCONST;
+ goto nret;
+ }
+ c = LCONST;
+ goto nret;
+
+nret:
+ return c;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+caseout:
+ if(c == 'L' || c == 'l') {
+ c = GETC();
+ c1 |= Numlong;
+ } else
+ if(c == 'F' || c == 'f') {
+ c = GETC();
+ c1 |= Numflt;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatof(symb, &yylval.dval)) {
+ yyerror("overflow in float constant");
+ yylval.dval = 0;
+ }
+ if(c1 & Numflt)
+ return LFCONST;
+ return LDCONST;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+long
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ /* nearln = lineno; */
+ diag(Z, "illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ for(;;) {
+ if(!isspace(c))
+ return c;
+ if(c == '\n') {
+ lineno++;
+ return c;
+ }
+ c = GETC();
+ }
+ return 0;
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+long
+escchar(long e, int longflg, int escflg)
+{
+ long c, l;
+ int i;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ if(c == 'x') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 2 hex
+ */
+ i = 2;
+ if(longflg)
+ i = 4;
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ unget(c);
+ break;
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ if(c >= '0' && c <= '7') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 3 oct
+ */
+ i = 2;
+ if(longflg)
+ i = 5;
+ l = c - '0';
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ unget(c);
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return '\a';
+ case 'v': return '\v';
+ }
+ return c;
+}
+
+struct
+{
+ char *name;
+ ushort lexical;
+ ushort type;
+} itab[] =
+{
+ "auto", LAUTO, 0,
+ "break", LBREAK, 0,
+ "case", LCASE, 0,
+ "char", LCHAR, TCHAR,
+ "const", LCONSTNT, 0,
+ "continue", LCONTINUE, 0,
+ "default", LDEFAULT, 0,
+ "do", LDO, 0,
+ "double", LDOUBLE, TDOUBLE,
+ "else", LELSE, 0,
+ "enum", LENUM, 0,
+ "extern", LEXTERN, 0,
+ "float", LFLOAT, TFLOAT,
+ "for", LFOR, 0,
+ "goto", LGOTO, 0,
+ "if", LIF, 0,
+ "int", LINT, TINT,
+ "long", LLONG, TLONG,
+ "register", LREGISTER, 0,
+ "return", LRETURN, 0,
+ "SET", LSET, 0,
+ "short", LSHORT, TSHORT,
+ "signed", LSIGNED, 0,
+ "signof", LSIGNOF, 0,
+ "sizeof", LSIZEOF, 0,
+ "static", LSTATIC, 0,
+ "struct", LSTRUCT, 0,
+ "switch", LSWITCH, 0,
+ "typedef", LTYPEDEF, 0,
+ "union", LUNION, 0,
+ "unsigned", LUNSIGNED, 0,
+ "USED", LUSED, 0,
+ "void", LVOID, TVOID,
+ "volatile", LVOLATILE, 0,
+ "while", LWHILE, 0,
+ "__int64", LVLONG, TVLONG, /* for windows */
+ 0
+};
+
+static char *litab[] =
+{
+ "adt",
+ "alt",
+ "array",
+ "big",
+ "break",
+ "byte",
+ "case",
+ "chan",
+ "con",
+ "continue",
+ "cyclic",
+ "do",
+ "else",
+ "exit",
+ "fn",
+ "for",
+ "hd",
+ "if",
+ "implement",
+ "import",
+ "include",
+ "int",
+ "len",
+ "list",
+ "load",
+ "module",
+ "nil",
+ "of",
+ "or",
+ "pick",
+ "real",
+ "ref",
+ "return",
+ "self",
+ "spawn",
+ "string",
+ "tagof",
+ "tl",
+ "to",
+ "type",
+ "while",
+ 0,
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+ Type *t;
+
+ nerrors = 0;
+ lineno = 1;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+
+ types[TXXX] = T;
+ types[TCHAR] = typ(TCHAR, T);
+ types[TUCHAR] = typ(TUCHAR, T);
+ types[TSHORT] = typ(TSHORT, T);
+ types[TUSHORT] = typ(TUSHORT, T);
+ types[TINT] = typ(TINT, T);
+ types[TUINT] = typ(TUINT, T);
+ types[TLONG] = typ(TLONG, T);
+ types[TULONG] = typ(TULONG, T);
+ types[TVLONG] = typ(TVLONG, T);
+ types[TUVLONG] = typ(TUVLONG, T);
+ types[TFLOAT] = typ(TFLOAT, T);
+ types[TDOUBLE] = typ(TDOUBLE, T);
+ types[TVOID] = typ(TVOID, T);
+ types[TENUM] = typ(TENUM, T);
+ types[TFUNC] = typ(TFUNC, types[TINT]);
+ types[TIND] = typ(TIND, types[TVOID]);
+ stringtype = typ(TSTRING, T);
+ fdtype = typ(TSTRUCT, typ(TFD, T));
+ fdtype->width = 4;
+ pfdtype = typ(TIND, fdtype);
+
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->lexical = itab[i].lexical;
+ if(itab[i].type != 0)
+ s->type = types[itab[i].type];
+ }
+ for(i=0; litab[i]; i++){
+ s = slookup(litab[i]);
+ s->lkw = 1;
+ }
+ blockno = 0;
+ autobn = 0;
+ autoffset = 0;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+ symstring = slookup(".string");
+ symstring->class = CSTATIC;
+ symstring->type = t;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+
+ nodproto = new(OPROTO, Z, Z);
+ dclstack = D;
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+
+ fmtinstall('f', gfltconv);
+ fmtinstall('F', gfltconv);
+ fmtinstall('g', gfltconv);
+ fmtinstall('G', gfltconv);
+ fmtinstall('e', gfltconv);
+ fmtinstall('E', gfltconv);
+
+ fmtinstall('O', Oconv);
+ fmtinstall('T', Tconv);
+ fmtinstall('F', FNconv);
+ fmtinstall('L', Lconv);
+ fmtinstall('Q', Qconv);
+ fmtinstall('|', VBconv);
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0] & 0xff;
+
+pop:
+ if(i->f >= 0)
+ outpop(lineno);
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+ int a;
+ char s[STRINGSZ];
+
+ a = va_arg(fp->args, int);
+ if(a < OXXX || a > OEND) {
+ sprint(s, "***badO %d***", a);
+ fmtstrcpy(fp, s);
+ } else
+ fmtstrcpy(fp, onames[a]);
+ return 0;
+}
+
+int
+Lconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Hist *h;
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ long idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ long ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ long l, d;
+ int i, n;
+
+ l = va_arg(fp->args, long);
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset != 0) { /* #line directive, not #pragma */
+ if(n > 0 && n < HISTSZ && h->offset >= 0) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ if(n < HISTSZ) { /* beginning of file */
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ str[0] = 0;
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
+ break;
+ strcat(str, " ");
+ }
+ if(a[i].line)
+ snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+ a[i].line->name, l-a[i].ldel+1,
+ a[i].incl->name, l-a[i].idel+1);
+ else
+ snprint(s, STRINGSZ, "%s:%ld",
+ a[i].incl->name, l-a[i].idel+1);
+ if(strlen(s)+strlen(str) >= STRINGSZ-10)
+ break;
+ strcat(str, s);
+ l = a[i].incl->line - 1; /* now print out start of this file */
+ }
+ if(n == 0)
+ strcat(str, "<eof>");
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], s[STRINGSZ+20];
+ Type *t, *t1;
+ int et;
+ long n;
+
+ str[0] = 0;
+ for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+ et = t->etype;
+ if(str[0])
+ strcat(str, " ");
+ if(t->garb) {
+ sprint(s, "%s ", gnames[t->garb]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ sprint(s, "%s", tnames[et]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ if(et == TFUNC && (t1 = t->down)) {
+ sprint(s, "(%T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ while(t1 = t1->down) {
+ sprint(s, ", %T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, ")");
+ }
+ if(et == TARRAY) {
+ n = t->width;
+ if(t->link && t->link->width)
+ n /= t->link->width;
+ sprint(s, "[%ld]", n);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(t->nbits) {
+ sprint(s, " %d:%d", t->shift, t->nbits);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(typesu[et]) {
+ if(t->tag) {
+ strcat(str, " ");
+ if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+ strcat(str, t->tag->name);
+ } else
+ strcat(str, " {}");
+ break;
+ }
+ }
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+int
+FNconv(Fmt *fp)
+{
+ char *str;
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ str = "<indirect>";
+ if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+ str = n->sym->name;
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+int
+Qconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], *s;
+ long b;
+ int i;
+
+ str[0] = 0;
+ for(b = va_arg(fp->args, long); b;) {
+ i = bitno(b);
+ if(str[0])
+ strcat(str, " ");
+ s = qnames[i];
+ if(strlen(str) + strlen(s) >= STRINGSZ)
+ break;
+ strcat(str, s);
+ b &= ~(1L << i);
+ }
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+int
+VBconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int i, n, t, pc;
+
+ n = va_arg(fp->args, int);
+ pc = 0; /*was printcol */
+ i = 0;
+ while(pc < n) {
+ t = (pc+8) & ~7;
+ if(t <= n) {
+ str[i++] = '\t';
+ pc = t;
+ continue;
+ }
+ str[i++] = ' ';
+ pc++;
+ }
+ str[i] = 0;
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((ulong)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+ char *e;
+
+ while(*p != 0) {
+ e = strchr(p, ' ');
+ if(e != 0)
+ *e = '\0';
+
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ break;
+
+ if(i >= ninclude)
+ include[ninclude++] = p;
+
+ if(ninclude > nelem(include)) {
+ diag(Z, "ninclude too small %d", nelem(include));
+ exits("ninclude");
+ }
+
+ if(e == 0)
+ break;
+ p = e+1;
+ }
+}
+
+static void
+doio(char *s)
+{
+ char *cp;
+
+ newio();
+ cp = ionext->b;
+ strcpy(cp, s);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+}
+
+static void
+undoio(void)
+{
+ Io *i;
+
+ i = iostack;
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ fi.p = i->p;
+ fi.c = i->c;
+}
+
+/* rm // comment from a string */
+static void
+slashslash(char *s)
+{
+ for( ; *s != '\0'; s++)
+ if(*s == '/' && s[1] == '/'){
+ *s = '\0';
+ return;
+ }
+}
+
+int
+iscon(char *str)
+{
+ int olineno, opeekc, con, tok, t;
+ Sym *s;
+ char buf[1024];
+
+ if(str == nil || *str == 0 || strlen(str)+16 > 1024)
+ return 0;
+ ypeek = 1;
+ olineno = lineno;
+ opeekc = peekc;
+ peekc = IGN;
+ strcpy(buf, str);
+ slashslash(buf);
+ strcat(buf, " break break");
+ doio(buf);
+ tok = 0;
+ con = 1;
+ while(con){
+ t = yylex();
+ if(t == LBREAK)
+ break;
+ switch(t){
+ case LSTRING:
+ case LLSTRING:
+ tok = 1;
+ free(yylval.sval.s);
+ break;
+ case LNAME:
+ tok = 1;
+ s = yylval.sym;
+ if(s->macro || s->type == T || s->type->etype != TENUM)
+ con = 0;
+ break;
+ case LCHARACTER:
+ case LCONST:
+ case LLCONST:
+ case LUCONST:
+ case LULCONST:
+ case LVLCONST:
+ case LUVLCONST:
+ case LFCONST:
+ case LDCONST:
+ tok = 1;
+ break;
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case LPP:
+ case LMM:
+ case '<':
+ case '>':
+ case LGE:
+ case LLE:
+ case LEQ:
+ case LNE:
+ case LLSH:
+ case LRSH:
+ case '!':
+ case '~':
+ case '&':
+ case '|':
+ case '^':
+ case '(':
+ case ')':
+ break;
+ default:
+ con = 0;
+ break;
+ }
+ }
+ undoio();
+ peekc = opeekc;
+ lineno = olineno;
+ ypeek = 0;
+ return con && tok;
+}
+
+void
+doasenum(Sym *s)
+{
+ char *b, buf[1024];
+
+ b = s->macro;
+ s->macro = nil;
+ lineno--;
+ slashslash(b+1);
+ sprint(buf, "enum{ %s = %s };\n", s->name, b+1);
+ doio(buf);
+ /* outpush(nil); */
+ free(b);
+}
diff --git a/utils/c2l/lexbody b/utils/c2l/lexbody
new file mode 100644
index 00000000..ab7e2439
--- /dev/null
+++ b/utils/c2l/lexbody
@@ -0,0 +1,650 @@
+/*
+ * common code for all the assemblers
+ */
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((ulong)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+
+ if(p == 0)
+ return;
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ return;
+
+ if(ninclude >= nelem(include)) {
+ yyerror("ninclude too small %d", nelem(include));
+ exits("ninclude");
+ }
+ include[ninclude++] = p;
+}
+
+void
+errorexit(void)
+{
+
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%ca: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ static Sym zsym;
+ Sym *s;
+ long h;
+ char *p;
+ int c, l;
+
+ h = 0;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ *s = zsym;
+ s->name = alloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+ return s;
+}
+
+long
+yylex(void)
+{
+ int c, c1;
+ char *cp;
+ Sym *s;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c == EOF) {
+ peekc = EOF;
+ return -1;
+ }
+ if(isspace(c)) {
+ if(c == '\n') {
+ lineno++;
+ return ';';
+ }
+ goto l0;
+ }
+ if(isalpha(c))
+ goto talph;
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+ case '\n':
+ lineno++;
+ return ';';
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c = GETC();
+ if(isalpha(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto aloop;
+ }
+ if(isdigit(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto casedot;
+ }
+ peekc = c;
+ return '.';
+
+ talph:
+ case '_':
+ case '@':
+ cp = symb;
+
+ aloop:
+ *cp++ = c;
+ c = GETC();
+ if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
+ goto aloop;
+ *cp = 0;
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ if(s->type == 0)
+ s->type = LNAME;
+ if(s->type == LNAME ||
+ s->type == LVAR ||
+ s->type == LLAB) {
+ yylval.sym = s;
+ return s->type;
+ }
+ yylval.lval = s->value;
+ return s->type;
+
+ tnum:
+ cp = symb;
+ if(c != '0')
+ goto dc;
+ *cp++ = c;
+ c = GETC();
+ c1 = 3;
+ if(c == 'x' || c == 'X') {
+ c1 = 4;
+ c = GETC();
+ } else
+ if(c < '0' || c > '7')
+ goto dc;
+ yylval.lval = 0;
+ for(;;) {
+ if(c >= '0' && c <= '9') {
+ if(c > '7' && c1 == 3)
+ break;
+ yylval.lval <<= c1;
+ yylval.lval += c - '0';
+ c = GETC();
+ continue;
+ }
+ if(c1 == 3)
+ break;
+ if(c >= 'A' && c <= 'F')
+ c += 'a' - 'A';
+ if(c >= 'a' && c <= 'f') {
+ yylval.lval <<= c1;
+ yylval.lval += c - 'a' + 10;
+ c = GETC();
+ continue;
+ }
+ break;
+ }
+ goto ncu;
+
+ dc:
+ for(;;) {
+ if(!isdigit(c))
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+ *cp = 0;
+ yylval.lval = atol(symb);
+
+ ncu:
+ peekc = c;
+ return LCONST;
+
+ casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c == 'e' || c == 'E')
+ goto casee;
+ goto caseout;
+
+ casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+ caseout:
+ *cp = 0;
+ peekc = c;
+ if(FPCHIP) {
+ yylval.dval = atof(symb);
+ return LFCONST;
+ }
+ yyerror("assembler cannot interpret fp constants");
+ yylval.lval = 1L;
+ return LCONST;
+
+ case '"':
+ memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
+ cp = yylval.sval;
+ c1 = 0;
+ for(;;) {
+ c = escchar('"');
+ if(c == EOF)
+ break;
+ if(c1 < sizeof(yylval.sval))
+ *cp++ = c;
+ c1++;
+ }
+ if(c1 > sizeof(yylval.sval))
+ yyerror("string constant too long");
+ return LSCONST;
+
+ case '\'':
+ c = escchar('\'');
+ if(c == EOF)
+ c = '\'';
+ if(escchar('\'') != EOF)
+ yyerror("missing '");
+ yylval.lval = c;
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '/') {
+ for(;;) {
+ c = GETC();
+ if(c == '\n') {
+ lineno++;
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '*') {
+ for(;;) {
+ c = GETC();
+ while(c == '*') {
+ c = GETC();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ if(c == '\n')
+ lineno++;
+ }
+ }
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ return c;
+ }
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ for(;;) {
+ c = getc();
+ if(!isspace(c) || c == '\n')
+ return c;
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+int
+escchar(int e)
+{
+ int c, l;
+
+loop:
+ c = getc();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ return EOF;
+ return c;
+ }
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = c - '0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ return l;
+ }
+ }
+ peekc = c;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return 0x07;
+ case 'v': return 0x0b;
+ case 'z': return 0x00;
+ }
+ return c;
+}
+
+void
+pinit(char *f)
+{
+ int i;
+ Sym *s;
+
+ lineno = 1;
+ newio();
+ newfile(f, -1);
+ pc = 0;
+ peekc = IGN;
+ sym = 1;
+ for(i=0; i<NSYM; i++) {
+ h[i].type = 0;
+ h[i].sym = S;
+ }
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ s->macro = 0;
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0];
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++;
+}
+
+void
+yyerror(char *a, ...)
+{
+ char buf[200];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(a, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ prfile(lineno);
+ va_start(arg, a);
+ doprint(buf, buf+sizeof(buf), a, arg);
+ va_end(arg);
+ print("%s\n", buf);
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
+
+void
+prfile(long l)
+{
+ int i, n;
+ Hist a[HISTSZ], *h;
+ long d;
+
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset == 0) {
+ if(n >= 0 && n < HISTSZ)
+ a[n] = *h;
+ n++;
+ continue;
+ }
+ if(n > 0 && n < HISTSZ)
+ if(a[n-1].offset == 0) {
+ a[n] = *h;
+ n++;
+ } else
+ a[n-1] = *h;
+ continue;
+ }
+ n--;
+ if(n >= 0 && n < HISTSZ) {
+ d = h->line - a[n].line;
+ for(i=0; i<n; i++)
+ a[i].line += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ for(i=0; i<n; i++)
+ print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
diff --git a/utils/c2l/mac.c b/utils/c2l/mac.c
new file mode 100644
index 00000000..7ec6e393
--- /dev/null
+++ b/utils/c2l/mac.c
@@ -0,0 +1,3 @@
+#include "cc.h"
+
+#include "macbody"
diff --git a/utils/c2l/macbody b/utils/c2l/macbody
new file mode 100644
index 00000000..aacb1e6f
--- /dev/null
+++ b/utils/c2l/macbody
@@ -0,0 +1,773 @@
+
+long
+getnsn(void)
+{
+ long n;
+ int c;
+
+ c = getnsc();
+ if(c < '0' || c > '9')
+ return -1;
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + c-'0';
+ c = getc();
+ }
+ unget(c);
+ return n;
+}
+
+Sym*
+getsym(void)
+{
+ int c;
+ char *cp;
+
+ c = getnsc();
+ if(!isalpha(c) && c != '_') {
+ unget(c);
+ return S;
+ }
+ for(cp = symb;;) {
+ if(cp <= symb+NSYMB-4)
+ *cp++ = c;
+ c = getc();
+ if(isalnum(c) || c == '_')
+ continue;
+ unget(c);
+ break;
+ }
+ *cp = 0;
+ if(cp > symb+NSYMB-4)
+ yyerror("symbol too large: %s", symb);
+ return lookup();
+}
+
+int
+getcom(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c != '/')
+ break;
+ c = getc();
+ if(c == '/') {
+ while(c != '\n')
+ c = getc();
+ break;
+ }
+ if(c != '*')
+ break;
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment across newline");
+ break;
+ }
+ c = getc();
+ }
+ if(c == '\n')
+ break;
+ }
+ return c;
+}
+
+void
+dodefine(char *cp)
+{
+ Sym *s;
+ char *p;
+ long l;
+
+ strcpy(symb, cp);
+ p = strchr(symb, '=');
+ if(p) {
+ *p++ = 0;
+ s = lookup();
+ l = strlen(p) + 2; /* +1 null, +1 nargs */
+ while(l & 3)
+ l++;
+ while(nhunk < l)
+ gethunk();
+ *hunk = 0;
+ strcpy(hunk+1, p);
+ s->macro = hunk;
+ hunk += l;
+ nhunk -= l;
+ } else {
+ s = lookup();
+ s->macro = "\0001"; /* \000 is nargs */
+ }
+ if(0)
+ print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+ char *macname;
+ void (*macf)(void);
+} mactab[] =
+{
+ "ifdef", 0, /* macif(0) */
+ "ifndef", 0, /* macif(1) */
+ "else", 0, /* macif(2) */
+
+ "line", maclin,
+ "define", macdef,
+ "include", macinc,
+ "undef", macund,
+
+ "pragma", macprag,
+ "endif", macend,
+ 0
+};
+
+void
+domacro(void)
+{
+ int i;
+ Sym *s;
+
+ s = getsym();
+ if(s == S)
+ s = slookup("endif");
+ for(i=0; mactab[i].macname; i++)
+ if(strcmp(s->name, mactab[i].macname) == 0) {
+ if(mactab[i].macf)
+ (*mactab[i].macf)();
+ else
+ macif(i);
+ return;
+ }
+ yyerror("unknown #: %s", s->name);
+ macend();
+}
+
+void
+macund(void)
+{
+ Sym *s;
+
+ s = getsym();
+ macend();
+ if(s == S) {
+ yyerror("syntax in #undef");
+ return;
+ }
+ s->macro = 0;
+}
+
+#define NARG 25
+void
+macdef(void)
+{
+ Sym *s, *a;
+ char *args[NARG], *np, *base;
+ int n, i, c, len;
+
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(s->macro)
+ yyerror("macro redefined: %s", s->name);
+ c = getc();
+ n = -1;
+ if(c == '(') {
+ n++;
+ c = getnsc();
+ if(c != ')') {
+ unget(c);
+ for(;;) {
+ a = getsym();
+ if(a == S)
+ goto bad;
+ if(n >= NARG) {
+ yyerror("too many arguments in #define: %s", s->name);
+ goto bad;
+ }
+ args[n++] = a->name;
+ c = getnsc();
+ if(c == ')')
+ break;
+ if(c != ',')
+ goto bad;
+ }
+ }
+ c = getc();
+ }
+ if(isspace(c))
+ if(c != '\n')
+ c = getnsc();
+ base = hunk;
+ len = 1;
+ for(;;) {
+ if(isalpha(c) || c == '_') {
+ np = symb;
+ *np++ = c;
+ c = getc();
+ while(isalnum(c) || c == '_') {
+ *np++ = c;
+ c = getc();
+ }
+ *np = 0;
+ for(i=0; i<n; i++)
+ if(strcmp(symb, args[i]) == 0)
+ break;
+ if(i >= n) {
+ i = strlen(symb);
+ base = allocn(base, len, i);
+ memcpy(base+len, symb, i);
+ len += i;
+ continue;
+ }
+ base = allocn(base, len, 2);
+ base[len++] = '#';
+ base[len++] = 'a' + i;
+ continue;
+ }
+ if(c == '/') {
+ c = getc();
+ if(c != '*') {
+ base = allocn(base, len, 1);
+ base[len++] = '/';
+ continue;
+ }
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment and newline in define: %s", s->name);
+ break;
+ }
+ c = getc();
+ }
+ continue;
+ }
+ if(c == '\\') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ else if(c == '\r') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '\\';
+ continue;
+ }
+ if(c == '\n')
+ break;
+ if(c == '#')
+ if(n > 0) {
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+ if(c == '\n')
+ lineno++;
+ if(c == -1) {
+ yyerror("eof in a macro: %s", s->name);
+ break;
+ }
+ }
+ do {
+ base = allocn(base, len, 1);
+ base[len++] = 0;
+ } while(len & 3);
+
+ *base = n+1;
+ s->macro = base;
+ if(0)
+ print("#define %s %s\n", s->name, s->macro+1);
+ if(n == -1 && iscon(base+1))
+ doasenum(s);
+ return;
+
+bad:
+ if(s == S)
+ yyerror("syntax in #define");
+ else
+ yyerror("syntax in #define: %s", s->name);
+ macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+ char buf[2000];
+ int n, l, c, nargs;
+ char *arg[NARG], *cp, *ob, *ecp;
+
+ ob = b;
+ USED(ob);
+ nargs = *s->macro - 1;
+ if(nargs < 0) {
+ strcpy(b, s->macro+1);
+ if(0)
+ print("#expand %s %s\n", s->name, ob);
+ return;
+ }
+ c = getnsc();
+ if(c != '(')
+ goto bad;
+ n = 0;
+ c = getc();
+ if(c != ')') {
+ unget(c);
+ l = 0;
+ cp = buf;
+ ecp = cp + sizeof(buf)-4;
+ arg[n++] = cp;
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ c = getc();
+ if(c == '"')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ }
+ if(c == '\'')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '\'')
+ break;
+ }
+ if(l == 0) {
+ if(c == ',') {
+ *cp++ = 0;
+ arg[n++] = cp;
+ if(n > nargs)
+ break;
+ continue;
+ }
+ if(c == ')')
+ break;
+ }
+ if(c == '\n')
+ c = ' ';
+ *cp++ = c;
+ if(c == '(')
+ l++;
+ if(c == ')')
+ l--;
+ }
+ *cp = 0;
+ }
+ if(n != nargs) {
+ yyerror("argument mismatch expanding: %s", s->name);
+ *b = 0;
+ return;
+ }
+ cp = s->macro+1;
+ for(;;) {
+ c = *cp++;
+ if(c != '#') {
+ *b++ = c;
+ if(c == 0)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if(c == 0)
+ goto bad;
+ if(c == '#') {
+ *b++ = c;
+ continue;
+ }
+ c -= 'a';
+ if(c < 0 || c >= n)
+ continue;
+ strcpy(b, arg[c]);
+ b += strlen(arg[c]);
+ }
+ *b = 0;
+ if(0)
+ print("#expand %s %s\n", s->name, ob);
+ return;
+
+bad:
+ yyerror("syntax in macro expansion: %s", s->name);
+ *b = 0;
+ return;
+
+toobig:
+ yyerror("too much text in macro expansion: %s", s->name);
+ *b = 0;
+}
+
+void
+macinc(void)
+{
+ int c0, c, i, f;
+ char str[STRINGSZ], *hp;
+
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = str;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ f = -1;
+ for(i=0; i<ninclude; i++) {
+ if(i == 0 && c0 == '>')
+ continue;
+ strcpy(symb, include[i]);
+ strcat(symb, "/");
+ if(strcmp(symb, "./") == 0)
+ symb[0] = 0;
+ strcat(symb, str);
+ f = open(symb, 0);
+ if(f >= 0)
+ break;
+ }
+ if(f < 0)
+ strcpy(symb, str);
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ hp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += c;
+ newio();
+ pushio();
+ newfile(hp, f);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #include");
+ macend();
+}
+
+void
+maclin(void)
+{
+ char *cp;
+ int c;
+ long n;
+
+ n = getnsn();
+ c = getc();
+ if(n < 0)
+ goto bad;
+
+ for(;;) {
+ if(c == ' ' || c == '\t') {
+ c = getc();
+ continue;
+ }
+ if(c == '"')
+ break;
+ if(c == '\n') {
+ strcpy(symb, "<noname>");
+ goto nn;
+ }
+ goto bad;
+ }
+ cp = symb;
+ for(;;) {
+ c = getc();
+ if(c == '"')
+ break;
+ *cp++ = c;
+ }
+ *cp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+nn:
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ cp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += c;
+
+ linehist(cp, n);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #line");
+ macend();
+}
+
+void
+macif(int f)
+{
+ int c, l, bol;
+ Sym *s;
+
+ if(f == 2)
+ goto skip;
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(getcom() != '\n')
+ goto bad;
+ if(s->macro == 0 && s->type != T && s->type->etype == TENUM){
+ if(!f)
+ return;
+ }
+ else if((s->macro != 0) ^ f)
+ return;
+
+skip:
+ bol = 1;
+ l = 0;
+ for(;;) {
+ c = getc();
+ if(c != '#') {
+ if(!isspace(c))
+ bol = 0;
+ if(c == '\n')
+ bol = 1;
+ continue;
+ }
+ if(!bol)
+ continue;
+ s = getsym();
+ if(s == S)
+ continue;
+ if(strcmp(s->name, "endif") == 0) {
+ if(l) {
+ l--;
+ continue;
+ }
+ macend();
+ return;
+ }
+ if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+ l++;
+ continue;
+ }
+ if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+ macend();
+ return;
+ }
+ }
+
+bad:
+ yyerror("syntax in #if(n)def");
+ macend();
+}
+
+void
+macprag(void)
+{
+ Sym *s;
+ int c0, c;
+ char *hp;
+ Hist *h;
+
+ s = getsym();
+
+ if(s && strcmp(s->name, "lib") == 0)
+ goto praglib;
+ if(s && strcmp(s->name, "hjdicks") == 0) {
+ praghjdicks();
+ return;
+ }
+ if(s && strcmp(s->name, "fpround") == 0) {
+ pragfpround();
+ return;
+ }
+ if(s && strcmp(s->name, "varargck") == 0) {
+ pragvararg();
+ return;
+ }
+
+ while(getnsc() != '\n')
+ ;
+ return;
+
+praglib:
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = symb;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ /*
+ * put pragma-line in as a funny history
+ */
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ hp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += c;
+
+ h = alloc(sizeof(Hist));
+ h->name = hp;
+ h->line = lineno;
+ h->offset = -1;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #pragma lib");
+ macend();
+}
+
+void
+macend(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c < 0 || c == '\n')
+ return;
+ }
+}
+
+void
+linehist(char *f, int offset)
+{
+ Hist *h;
+
+ /*
+ * overwrite the last #line directive if
+ * no alloc has happened since the last one
+ */
+ if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
+ if(f && ehist->name && strcmp(f, ehist->name) == 0) {
+ ehist->line = lineno;
+ ehist->offset = offset;
+ return;
+ }
+
+ if(0)
+ if(f) {
+ if(offset)
+ print("%4ld: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4ld: %s\n", lineno, f);
+ } else
+ print("%4ld: <pop>\n", lineno);
+ newflag = 0;
+
+ h = alloc(sizeof(Hist));
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 10L*NHUNK)
+ nh = 10L*NHUNK;
+ h = (char*)mysbrk(nh);
+ if(h == (char*)-1) {
+ yyerror("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
diff --git a/utils/c2l/mkfile b/utils/c2l/mkfile
new file mode 100644
index 00000000..219d36e1
--- /dev/null
+++ b/utils/c2l/mkfile
@@ -0,0 +1,38 @@
+<../../mkconfig
+
+TARG=c2l
+
+OFILES=\
+ acid.$O\
+ bits.$O\
+ com.$O\
+ com64.$O\
+ $TARGMODEL.$O\
+ dcl.$O\
+ dpchk.$O\
+ lex.$O\
+ mac.$O\
+ mpatof.$O\
+ out.$O\
+ scon.$O\
+ sub.$O\
+ y.tab.$O\
+ c2l.$O\
+
+HFILES= cc.h\
+ y.tab.h\
+
+YFILES= cc.y\
+
+LIBS=math bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+mac.$O: macbody
+
+lex.$O: lex.c
+ $CC $CFLAGS '-DCPP="/bin/cpp"' lex.c
diff --git a/utils/c2l/mpatof.c b/utils/c2l/mpatof.c
new file mode 100644
index 00000000..d55ddab4
--- /dev/null
+++ b/utils/c2l/mpatof.c
@@ -0,0 +1,337 @@
+#include "cc.h"
+
+enum
+{
+ Mpscale = 29, /* safely smaller than bits in a long */
+ Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
+ Mpbase = 1L<<Mpscale,
+};
+
+typedef
+struct
+{
+ long a[Mpprec];
+ char ovf;
+} Mp;
+
+int mpatof(char*, double*);
+int mpatov(char *s, vlong *v);
+void mpint(Mp*, int);
+void mppow(Mp*, int, int);
+void mpmul(Mp*, int);
+void mpadd(Mp*, Mp*);
+int mptof(Mp*, double*);
+
+/*
+ * convert a string, s, to floating in *d
+ * return conversion overflow.
+ * required syntax is [+-]d*[.]d*[e[+-]d*]
+ */
+int
+mpatof(char *s, double *d)
+{
+ Mp a, b;
+ int dp, c, f, ef, ex, zer;
+ double d1, d2;
+
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ zer = 1; /* zero */
+ memset(&a, 0, sizeof(a));
+ for(;;) {
+ switch(c = *s++) {
+ default:
+ goto bad;
+ case '-':
+ f = 1;
+ case ' ':
+ case '\t':
+ case '+':
+ continue;
+ case '.':
+ dp = 1;
+ continue;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ zer = 0;
+ case '0':
+ mpint(&b, c-'0');
+ mpmul(&a, 10);
+ mpadd(&a, &b);
+ if(dp)
+ dp++;
+ continue;
+ case 'E':
+ case 'e':
+ ex = 0;
+ ef = 0;
+ for(;;) {
+ c = *s++;
+ if(c == '+' || c == ' ' || c == '\t')
+ continue;
+ if(c == '-') {
+ ef = 1;
+ continue;
+ }
+ if(c >= '0' && c <= '9') {
+ ex = ex*10 + (c-'0');
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+ case 0:
+ break;
+ }
+ break;
+ }
+ if(a.ovf)
+ goto bad;
+ if(zer) {
+ *d = 0;
+ return 0;
+ }
+ if(dp)
+ dp--;
+ dp -= ex;
+ if(dp > 0) {
+ /*
+ * must divide by 10**dp
+ */
+ if(mptof(&a, &d1))
+ goto bad;
+
+ /*
+ * trial exponent of 8**dp
+ * 8 (being between 5 and 10)
+ * should pick up all underflows
+ * in the division of 5**dp.
+ */
+ d2 = frexp(d1, &ex);
+ d2 = ldexp(d2, ex-3*dp);
+ if(d2 == 0)
+ goto bad;
+
+ /*
+ * decompose each 10 into 5*2.
+ * create 5**dp in fixed point
+ * and then play with the exponent
+ * for the remaining 2**dp.
+ * note that 5**dp will overflow
+ * with as few as 134 input digits.
+ */
+ mpint(&a, 1);
+ mppow(&a, 5, dp);
+ if(mptof(&a, &d2))
+ goto bad;
+ d1 = frexp(d1/d2, &ex);
+ d1 = ldexp(d1, ex-dp);
+ if(d1 == 0)
+ goto bad;
+ } else {
+ /*
+ * must multiply by 10**|dp| --
+ * just do it in fixed point.
+ */
+ mppow(&a, 10, -dp);
+ if(mptof(&a, &d1))
+ goto bad;
+ }
+ if(f)
+ d1 = -d1;
+ *d = d1;
+ return 0;
+
+bad:
+ return 1;
+}
+
+/*
+ * convert a to floating in *d
+ * return conversion overflow
+ */
+int
+mptof(Mp *a, double *d)
+{
+ double f, g;
+ long x, *a1;
+ int i;
+
+ if(a->ovf)
+ return 1;
+ a1 = a->a;
+ f = ldexp(*a1++, 0);
+ for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
+ if(x = *a1++) {
+ g = ldexp(x, i);
+ /*
+ * NOTE: the test (g==0) is plan9
+ * specific. ansi compliant overflow
+ * is signaled by HUGE and errno==ERANGE.
+ * change this for your particular ldexp.
+ */
+ if(g == 0)
+ return 1;
+ f += g; /* this could bomb! */
+ }
+ *d = f;
+ return 0;
+}
+
+/*
+ * return a += b
+ */
+void
+mpadd(Mp *a, Mp *b)
+{
+ int i, c;
+ long x, *a1, *b1;
+
+ if(b->ovf)
+ a->ovf = 1;
+ if(a->ovf)
+ return;
+ c = 0;
+ a1 = a->a;
+ b1 = b->a;
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 + *b1++ + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ a->ovf = c;
+}
+
+/*
+ * return a = c
+ */
+void
+mpint(Mp *a, int c)
+{
+
+ memset(a, 0, sizeof(*a));
+ a->a[0] = c;
+}
+
+/*
+ * return a *= c
+ */
+void
+mpmul(Mp *a, int c)
+{
+ Mp p;
+ int b;
+
+ memmove(&p, a, sizeof(p));
+ if(!(c & 1))
+ memset(a, 0, sizeof(*a));
+ c &= ~1;
+ for(b=2; c; b<<=1) {
+ mpadd(&p, &p);
+ if(c & b) {
+ mpadd(a, &p);
+ c &= ~b;
+ }
+ }
+}
+
+/*
+ * return a *= b**e
+ */
+void
+mppow(Mp *a, int b, int e)
+{
+ int b1;
+
+ b1 = b*b;
+ b1 = b1*b1;
+ while(e >= 4) {
+ mpmul(a, b1);
+ e -= 4;
+ if(a->ovf)
+ return;
+ }
+ while(e > 0) {
+ mpmul(a, b);
+ e--;
+ }
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
diff --git a/utils/c2l/out.c b/utils/c2l/out.c
new file mode 100644
index 00000000..ab81a995
--- /dev/null
+++ b/utils/c2l/out.c
@@ -0,0 +1,825 @@
+#include "cc.h"
+
+#define INCREMENT 8
+#define DEVNULL "/dev/null"
+
+static int indent = 0;
+static int fd = -1;
+static int nf = 0;
+static int mylineno = 1;
+
+typedef struct Com{
+ int lno;
+ char *s;
+ Node *n;
+ int tba;
+ struct Com *nxt;
+} Com;
+
+Com *hdc, *curc;
+
+typedef struct File{
+ char *s;
+ char *f;
+ char *m;
+ int b;
+ int loc;
+ int in;
+ int tg;
+ Node *n;
+ Com *c;
+ struct File *nxt;
+} File;
+
+typedef struct Create{
+ char *s;
+ struct Create *nxt;
+} Create;
+
+File *fs;
+Create *cs;
+
+static void genmsg(void);
+static int isloc(void);
+
+static void
+addcreate(char *s)
+{
+ Create *c;
+
+ if(strcmp(s, DEVNULL) == 0)
+ return;
+ c = (Create*)malloc(sizeof(Create));
+ c->s = malloc(strlen(s)+1);
+ strcpy(c->s, s);
+ c->nxt = cs;
+ cs = c;
+}
+
+static int
+created(char *s)
+{
+ Create *c;
+
+ for(c = cs; c != nil; c = c->nxt)
+ if(strcmp(s, c->s) == 0)
+ return 1;
+ return 0;
+}
+
+int
+dolog(void)
+{
+ if(justcode)
+ return 0;
+ return domod || !doinc || inmain;
+}
+
+static char*
+curf(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->s;
+ return nil;
+}
+
+static char*
+curm(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->m;
+ return nil;
+}
+
+void
+setmod(Sym *s)
+{
+ if(domod && s->mod == nil && ism() && !(doloc && !isloc()))
+ s->mod = curm();
+}
+
+char *
+outmod(char *buf, int up)
+{
+ char *s, *t;
+
+ s = curf();
+ if(s == nil)
+ return "";
+ t = strchr(s, '.');
+ if(t != nil)
+ *t = '\0';
+ strcpy(buf, s);
+ if(t != nil)
+ *t = '.';
+ if(up == 1 || (up < 0 && ism()))
+ buf[0] = toupper(buf[0]);
+ return buf;
+}
+
+int
+ism(void)
+{
+ return !isb();
+}
+
+int
+isb(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->b;
+ return 0;
+}
+
+static int
+isloc(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->loc;
+ return 0;
+}
+
+static File*
+pushf(void)
+{
+ static File zfile;
+ File *f;
+
+ f = (File*)malloc(sizeof(File));
+ *f = zfile;
+ f->s = nil;
+ f->f = nil;
+ f->m = nil;
+ f->nxt = fs;
+ fs = f;
+ return f;
+}
+
+static void
+popf(void)
+{
+ File *f;
+
+ f = fs;
+ fs = fs->nxt;
+ if(f->s != nil)
+ free(f->s);
+ free(f);
+}
+
+static void
+setf(File *f, char *s)
+{
+ int n;
+ char *t;
+
+ if(s != nil){
+ t = strrchr(s, '/');
+ f->loc = t == nil;
+ if(t != nil)
+ s = t+1;
+ n = strlen(s);
+ f->s = malloc(n+1);
+ strcpy(f->s, s);
+ s = f->s;
+ if(n > 2 && s[n-2] == '.'){
+ f->m = malloc(n-1);
+ strncpy(f->m, s, n-2);
+ if(s[n-1] == 'h')
+ s[n-1] = 'm';
+ else if(s[n-1] == 'c'){
+ s[n-1] = 'b';
+ f->b = 1;
+ }
+ else
+ s = nil;
+ }
+ else
+ s = nil;
+ if(s == nil){
+ free(f->s);
+ if(f->m != nil)
+ free(f->m);
+ f->s = nil;
+ f->m = nil;
+ }
+ }
+ f->f = f->s;
+ if(f->s != nil && nf > 0){
+ if(doinc || doloc && !f->loc)
+ f->f = DEVNULL;
+ else if(!domod)
+ f->f = nil;
+ }
+}
+
+void
+outpush0(char *s, Node *n)
+{
+ File *f;
+
+ f = pushf();
+ setf(f, s);
+ if(f->f != nil){
+ nf++;
+ f->tg = taggen;
+ taggen = 0;
+ f->n = n;
+ f->c = hdc;
+ hdc = nil;
+ }
+}
+
+void
+outpop0(int lno)
+{
+ File *f;
+
+ USED(lno);
+ f = fs;
+ if(f->f != nil){
+ nf--;
+ taggen = f->tg;
+ f->n->left = (void*)hdc;
+ hdc = f->c;
+ }
+ popf();
+}
+
+void
+outpush2(char *s, Node *n)
+{
+ File *f;
+
+ f = pushf();
+ setf(f, s);
+ if(f->f != nil){
+ if(fd >= 0){
+ newsec(0);
+ close(fd);
+ close(1);
+ fd = -1;
+ }
+ if(created(f->f))
+ f->f = DEVNULL; /* don't overwrite original if included again */
+ fd = create(f->f, OWRITE, 0664);
+ if(fd >= 0)
+ addcreate(f->f);
+ mydup(fd, 1);
+ nf++;
+ f->tg = taggen;
+ taggen = 0;
+ f->c = hdc;
+ if(n != Z)
+ hdc = (void*)n->left;
+ else
+ hdc = nil;
+ f->in = indent;
+ indent = 0;
+ genmsg();
+ pgen(f->b);
+ }
+}
+
+void
+outpop2(int lno)
+{
+ File *f, *g;
+
+ f = fs;
+ if(f->f != nil){
+ if(fd >= 0){
+ newsec(0);
+ output(lno, 1);
+ epgen(f->b);
+ close(fd);
+ close(1);
+ fd = -1;
+ }
+ for(g = fs->nxt; g != nil; g = g->nxt){
+ if(g->f != nil){
+ fd = open(g->f, OWRITE);
+ seek(fd, 0, 2);
+ mydup(fd, 1);
+ break;
+ }
+ }
+ nf--;
+ taggen = f->tg;
+ hdc = f->c;
+ indent = f->in;
+ }
+ popf();
+}
+
+static void
+xprint(char *s)
+{
+ if(nerrors == 0)
+ print(s);
+}
+
+static int tot = 0;
+
+static void
+doindent(int d)
+{
+ int i;
+
+ for(i = 0; i < d/8; i++)
+ xprint("\t");
+ for(i = 0; i < d%8; i++)
+ xprint(" ");
+}
+
+void
+incind(void)
+{
+ indent += INCREMENT;
+}
+
+void
+decind(void)
+{
+ indent -= INCREMENT;
+}
+
+int
+zeroind(void)
+{
+ int i = indent;
+
+ indent = 0;
+ return i;
+}
+
+void
+restoreind(int i)
+{
+ indent = i;
+}
+
+void
+newline0(void)
+{
+ xprint("\n");
+ tot = 0;
+ mylineno++;
+}
+
+void
+newline(void)
+{
+ if(!outcom(1)){
+ xprint("\n");
+ mylineno++;
+ }
+ tot = 0;
+}
+
+static void
+lprint(char *s)
+{
+ if(tot == 0) {
+ doindent(indent);
+ tot += indent;
+ }
+ xprint(s);
+ tot += strlen(s);
+}
+
+void
+prline(char *s)
+{
+ xprint(s);
+ xprint("\n");
+ mylineno++;
+}
+
+void
+prdelim(char *s)
+{
+ if(*s == '%'){
+ if(*++s == '=')
+ lprint("%%=");
+ else
+ lprint("%%");
+ return;
+ }
+ lprint(s);
+}
+
+void
+prkeywd(char *kw)
+{
+ lprint(kw);
+}
+
+void
+prid(char *s)
+{
+ lprint(s);
+}
+
+static void
+priddol(char *s, int dol)
+{
+ char *t;
+ char buf[128];
+
+ if(dol){
+ t = strchr(s, '$');
+ if(t != nil)
+ *t = '_';
+ lprint(s);
+ if(t != nil){
+ strcpy(buf, s);
+ while(slookup(buf)->type != T){
+ strcat(buf, "x");
+ lprint("x");
+ }
+ *t = '$';
+ }
+ }
+ else
+ lprint(s);
+}
+
+void
+prsym(Sym *s, int mod)
+{
+ char buf[128];
+ int c;
+
+ if(mod && s->mod && strcmp(s->mod, curm()) != 0 && (!s->limbo || s->class == CEXTERN)){
+ c = isconsym(s);
+ if(c >= 0){
+ if(c){
+ s->mod[0] = toupper(s->mod[0]);
+ lprint(s->mod);
+ s->mod[0] = tolower(s->mod[0]);
+ }
+ else
+ lprint(s->mod);
+ lprint("->");
+ usemod(s, !c);
+ }
+ }
+ if(s->lname)
+ prid(s->lname);
+ else{
+ priddol(s->name, s->class == CSTATIC);
+ if(s->lkw){
+ strcpy(buf, s->name);
+ for(;;){
+ strcat(buf, "x");
+ lprint("x");
+ s = slookup(buf);
+ if(s->type == T)
+ break;
+ }
+ }
+ }
+}
+
+int
+arrow(Sym *s)
+{
+ if(s->mod && strcmp(s->mod, curm()) != 0)
+ return isconsym(s) >= 0;
+ return 0;
+}
+
+void
+prsym0(Sym *s)
+{
+ int c;
+
+ if(s->mod && strcmp(s->mod, curm()) != 0){
+ c = isconsym(s);
+ if(c >= 0)
+ usemod(s, !c);
+ }
+}
+
+static int
+isprintable(int c)
+{
+ if(c >= 0x20 && c <= 0x7e)
+ return 1;
+ return c == '\0' || c == '\n' || c == '\t' || c == '\b' || c == '\r' || c == '\f' || c == '\a' || c == '\v';
+}
+
+static int
+hex(int c)
+{
+ if(c < 10)
+ return c+'0';
+ return c+'a'-10;
+}
+
+void
+prchar0(vlong x, int quote)
+{
+ int c, e, i = 0;
+ static char buf[16];
+
+ if(quote)
+ buf[i++] = '\'';
+ c = x;
+ if(c < 0 || c > 255 || !isprintable(c)){
+ if(c&0xffff0000)
+ diag(Z, "character too big");
+ buf[i++] = '\\';
+ buf[i++] = 'u';
+ buf[i++] = hex((c>>12)&0xf);
+ buf[i++] = hex((c>>8)&0xf);
+ buf[i++] = hex((c>>4)&0xf);
+ buf[i++] = hex((c>>0)&0xf);
+ }
+ else{
+ e = 0;
+ switch(c){
+ case '\n': e = 'n'; break;
+ case '\t': e = 't'; break;
+ case '\b': e = 'b'; break;
+ case '\r': e = 'r'; break;
+ case '\f': e = 'f'; break;
+ case '\a': e = 'a'; break;
+ case '\v': e = 'v'; break;
+ case '"': if(!quote) e = '"'; break;
+ case '\'': if(quote) e = '\''; break;
+ case '\\': e = '\\'; break;
+ case '%': buf[i++] = c; break;
+ case 0: e = '0'; if(strings) prcom("nul byte in string ?", Z); break;
+ }
+ if(e != 0){
+ buf[i++] = '\\';
+ c = e;
+ }
+ buf[i++] = c;
+ }
+ if(quote)
+ buf[i++] = '\'';
+ buf[i] = '\0';
+ lprint(buf);
+}
+
+void
+prchar(vlong x)
+{
+ prchar0(x, 1);
+}
+
+void
+prstr(char *s)
+{
+ uchar *t;
+ Rune r;
+
+ t = (uchar*)s;
+ lprint("\"");
+ while(*t != 0){
+ if(*t & 0x80){
+ t += chartorune(&r, (char*)t);
+ prchar0(r, 0);
+ }
+ else
+ prchar0(*t++, 0);
+ }
+ lprint("\"");
+}
+
+void
+prlstr(ushort *s)
+{
+ lprint("\"");
+ while(*s != 0)
+ prchar0(*s++, 0);
+ lprint("\"");
+}
+
+void
+prreal(double x, char *s, int b)
+{
+ static char buf[128];
+
+ if(b != KDEC)
+ diag(Z, "not base 10 in prreal");
+ if(s != nil)
+ lprint(s);
+ else{
+ sprint(buf, "%f", x);
+ lprint(buf);
+ }
+}
+
+void
+prnum(vlong x, int b, Type *t)
+{
+ static char buf[128];
+ int w;
+ vlong m;
+
+ w = 4;
+ if(t != T)
+ w = ewidth[t->etype];
+ m = MASK(8*w);
+ if(b == KHEX)
+ sprint(buf, "16r%llux", x&m);
+ else if(b == KOCT)
+ sprint(buf, "8r%lluo", x&m);
+ else
+ sprint(buf, "%lld", x);
+ lprint(buf);
+}
+
+char *cb;
+int cn, csz;
+
+static void
+outcom0(Com *c)
+{
+ Node *n;
+ char *s, *t, *u;
+
+ s = c->s;
+ n = c->n;
+ if(comm && c->tba){
+ t = strchr(s, '\n');
+ *t = '\0';
+ fprint(2, "%s:%d: %s", curf(), mylineno, s);
+ *t = '\n';
+ if(n != Z){
+ mydup(2, 1);
+ expgen(n);
+ mydup(fd, 1);
+ }
+ fprint(2, "\n");
+ }
+ while(*s != '\0'){
+ t = strchr(s, '\n');
+ *t = '\0';
+ if(tot != 0)
+ prdelim("\t");
+ prdelim("# ");
+ while((u = strchr(s, '%')) != nil){
+ /* do not let print interpret % ! */
+ *u = 0;
+ lprint(s);
+ *u = '%';
+ lprint("%%");
+ s = u+1;
+ }
+ lprint(s);
+ if(n == Z)
+ newline0();
+ *t = '\n';
+ s = t+1;
+ }
+ if(n != Z){
+ expgen(n);
+ newline0();
+ }
+}
+
+int
+outcom(int f)
+{
+ int lno, nl;
+ Com *c;
+
+ nl = 0;
+ lno = pline+f;
+ c = hdc;
+ while(c != nil && c->lno < lno){
+/* print("outcom: %d < %d (f=%d)\n", c->lno, lno, f); */
+ nl = 1;
+ outcom0(c);
+ hdc = hdc->nxt;
+ free(c->s);
+ free(c);
+ c = hdc;
+ }
+ return nl;
+}
+
+void
+startcom(int lno)
+{
+ Com *c, **ac;
+
+ c = (Com *)malloc(sizeof(Com));
+ c->lno = lno;
+ c->s = nil;
+ c->n = Z;
+ c->tba = 0;
+ c->nxt = nil;
+ for(ac = &hdc; *ac != nil && (*ac)->lno <= lno; ac = &(*ac)->nxt)
+ ;
+ c->nxt = *ac;
+ curc = *ac = c;
+}
+
+void
+addcom(int rr)
+{
+ int i, nb;
+ char *ncb;
+ char s[UTFmax];
+ Rune r[1];
+
+ if(rr >= Runeself){
+ r[0] = rr;
+ nb = runetochar(s, r);
+ }
+ else{
+ nb = 1;
+ s[0] = rr;
+ }
+ if(cn+nb-1 >= csz){
+ csz += 32;
+ ncb = malloc(csz);
+ memcpy(ncb, cb, cn);
+ free(cb);
+ cb = ncb;
+ }
+ for(i = 0; i < nb; i++)
+ cb[cn++] = s[i];
+}
+
+void
+endcom(void)
+{
+ char *s;
+
+ addcom('\n');
+ addcom('\0');
+ s = malloc(strlen(cb)+1);
+ strcpy(s, cb);
+ curc->s = s;
+/* print("com %d %s\n", curc->lno, s); */
+ cn = 0;
+}
+
+void
+linit()
+{
+ csz = 32;
+ cb = malloc(csz);
+ sysinit();
+}
+
+static void
+genmsg(void)
+{
+ prline("#");
+ prline("# initially generated by c2l");
+ prline("#");
+ prline("");
+}
+
+void
+prcom(char *s, Node *n)
+{
+ Com *c;
+
+ startcom(pline);
+ c = curc;
+ sprint(cb, "TBA %s", s);
+ cn = strlen(cb);
+ c->n = n;
+ c->tba = 1;
+ endcom();
+}
+
+void
+output(long lno, int com)
+{
+/* print("output(%ld)\n", lno); */
+ pline = lno;
+ if(com)
+ outcom(0);
+}
+
+int
+exists(char *f)
+{
+ int fd;
+
+ fd = open(f, OREAD);
+ close(fd);
+ return fd >= 0;
+}
diff --git a/utils/c2l/scon.c b/utils/c2l/scon.c
new file mode 100644
index 00000000..89f87332
--- /dev/null
+++ b/utils/c2l/scon.c
@@ -0,0 +1,250 @@
+#include "cc.h"
+
+void
+evconst(Node *n)
+{
+ Node *l, *r;
+ int et, isf;
+ vlong v;
+ double d;
+
+ if(n == Z || n->type == T)
+ return;
+
+ et = n->type->etype;
+ isf = typefd[et];
+
+ l = n->left;
+ r = n->right;
+
+ d = 0;
+ v = 0;
+
+ switch(n->op) {
+ default:
+ return;
+
+ case OCAST:
+ if(et == TVOID)
+ return;
+ et = l->type->etype;
+ if(isf) {
+ if(typefd[et])
+ d = l->fconst;
+ else
+ d = l->vconst;
+ } else {
+ if(typefd[et])
+ v = l->fconst;
+ else
+ v = convvtox(l->vconst, n->type->etype);
+ }
+ break;
+
+ case OCONST:
+ break;
+
+ case OADD:
+ if(isf)
+ d = l->fconst + r->fconst;
+ else {
+ v = l->vconst + r->vconst;
+ }
+ break;
+
+ case OSUB:
+ if(isf)
+ d = l->fconst - r->fconst;
+ else
+ v = l->vconst - r->vconst;
+ break;
+
+ case OMUL:
+ if(isf)
+ d = l->fconst * r->fconst;
+ else {
+ v = l->vconst * r->vconst;
+ }
+ break;
+
+ case OLMUL:
+ v = (uvlong)l->vconst * (uvlong)r->vconst;
+ break;
+
+
+ case ODIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ if(isf)
+ d = l->fconst / r->fconst;
+ else
+ v = l->vconst / r->vconst;
+ break;
+
+ case OLDIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ v = (uvlong)l->vconst / (uvlong)r->vconst;
+ break;
+
+ case OMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = l->vconst % r->vconst;
+ break;
+
+ case OLMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = (uvlong)l->vconst % (uvlong)r->vconst;
+ break;
+
+ case OAND:
+ v = l->vconst & r->vconst;
+ break;
+
+ case OOR:
+ v = l->vconst | r->vconst;
+ break;
+
+ case OXOR:
+ v = l->vconst ^ r->vconst;
+ break;
+
+ case OLSHR:
+ v = (uvlong)l->vconst >> r->vconst;
+ break;
+
+ case OASHR:
+ v = l->vconst >> r->vconst;
+ break;
+
+ case OASHL:
+ v = l->vconst << r->vconst;
+ break;
+
+ case OLO:
+ v = (uvlong)l->vconst < (uvlong)r->vconst;
+ break;
+
+ case OLT:
+ if(typefd[l->type->etype])
+ v = l->fconst < r->fconst;
+ else
+ v = l->vconst < r->vconst;
+ break;
+
+ case OHI:
+ v = (uvlong)l->vconst > (uvlong)r->vconst;
+ break;
+
+ case OGT:
+ if(typefd[l->type->etype])
+ v = l->fconst > r->fconst;
+ else
+ v = l->vconst > r->vconst;
+ break;
+
+ case OLS:
+ v = (uvlong)l->vconst <= (uvlong)r->vconst;
+ break;
+
+ case OLE:
+ if(typefd[l->type->etype])
+ v = l->fconst <= r->fconst;
+ else
+ v = l->vconst <= r->vconst;
+ break;
+
+ case OHS:
+ v = (uvlong)l->vconst >= (uvlong)r->vconst;
+ break;
+
+ case OGE:
+ if(typefd[l->type->etype])
+ v = l->fconst >= r->fconst;
+ else
+ v = l->vconst >= r->vconst;
+ break;
+
+ case OEQ:
+ if(typefd[l->type->etype])
+ v = l->fconst == r->fconst;
+ else
+ v = l->vconst == r->vconst;
+ break;
+
+ case ONE:
+ if(typefd[l->type->etype])
+ v = l->fconst != r->fconst;
+ else
+ v = l->vconst != r->vconst;
+ break;
+
+ case ONOT:
+ if(typefd[l->type->etype])
+ v = !l->fconst;
+ else
+ v = !l->vconst;
+ break;
+
+ case OANDAND:
+ if(typefd[l->type->etype])
+ v = l->fconst && r->fconst;
+ else
+ v = l->vconst && r->vconst;
+ break;
+
+ case OOROR:
+ if(typefd[l->type->etype])
+ v = l->fconst || r->fconst;
+ else
+ v = l->vconst || r->vconst;
+ break;
+
+ case OPOS:
+ if(isf)
+ d = l->fconst;
+ else
+ v = l->vconst;
+ break;
+
+ case ONEG:
+ if(isf)
+ d = -l->fconst;
+ else
+ v = -l->vconst;
+ break;
+
+ case OCOM:
+ if(typefd[l->type->etype])
+ v = 0; /* ~l->fconst */
+ else
+ v = ~l->vconst;
+ break;
+ }
+
+ n->left = ncopy(n);
+ n->op = OCONST;
+ /* n->left = Z; */
+ n->right = Z;
+ if(isf) {
+ n->fconst = d;
+ } else {
+ n->vconst = convvtox(v, n->type->etype);
+ }
+}
+
+void
+acom(Node *n)
+{
+ USED(n);
+}
diff --git a/utils/c2l/sub.c b/utils/c2l/sub.c
new file mode 100644
index 00000000..a696cb0f
--- /dev/null
+++ b/utils/c2l/sub.c
@@ -0,0 +1,1694 @@
+#include "cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+ static Node znode;
+ Node *n;
+
+ n = alloc(sizeof(*n));
+ *n = znode;
+ n->op = t;
+ n->left = l;
+ n->right = r;
+ n->lineno = lineno;
+ n->kind = KNIL;
+ newflag = 1;
+ return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+ Node *n;
+
+ n = new(o, l, r);
+ if(l != Z)
+ n->lineno = l->lineno;
+ else if(r != Z)
+ n->lineno = r->lineno;
+ else
+ n->lineno = nearln;
+ return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+ print(" == %s ==\n", s);
+ prtree1(n, 0, 0);
+ print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+ int i;
+
+ if(f)
+ for(i=0; i<d; i++)
+ print(" ");
+ if(n == Z) {
+ print("Z\n");
+ return;
+ }
+ if(n->op == OLIST) {
+ prtree1(n->left, d, 0);
+ prtree1(n->right, d, 1);
+ return;
+ }
+ d++;
+ print("%O", n->op);
+ i = 3;
+ switch(n->op)
+ {
+ case ONAME:
+ print(" \"%F\"", n);
+ i = 0;
+ break;
+
+ case OINDREG:
+ i = 0;
+ break;
+
+ case OREGISTER:
+ i = 0;
+ break;
+
+ case OSTRING:
+ print(" \"%s\"", n->cstring);
+ i = 0;
+ break;
+
+ case OLSTRING:
+ print(" \"%S\"", n->rstring);
+ i = 0;
+ break;
+
+ case ODOT:
+ case OELEM:
+ print(" \"%F\"", n);
+ break;
+
+ case OCONST:
+ if(typefd[n->type->etype])
+ print(" \"%.8e\"", n->fconst);
+ else
+ print(" \"%lld\"", n->vconst);
+ i = 0;
+ break;
+ }
+ if(n->type != T)
+ print(" %T", n->type);
+ print("\n");
+ if(i & 2)
+ prtree1(n->left, d, 1);
+ if(i & 1)
+ prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+ static Type ztype;
+ Type *t;
+
+ t = alloc(sizeof(*t));
+ *t = ztype;
+ t->etype = et;
+ t->link = d;
+ t->down = T;
+ t->sym = S;
+ t->width = ewidth[et];
+ t->nwidth = Z;
+ t->lineno = lineno;
+ return t;
+}
+
+Type*
+typ1(int et, Type *d)
+{
+ Type *t;
+
+ t = typ(et, d);
+ t->lineno = nearln;
+ return t;
+}
+
+Type*
+garbt(Type *t, long b)
+{
+ Type *t1;
+
+ if(b & BGARB) {
+ t1 = typ(TXXX, T);
+ *t1 = *t;
+ t1->garb = simpleg(b);
+ return t1;
+ }
+ return t;
+}
+
+int
+simpleg(long b)
+{
+
+ b &= BGARB;
+ switch(b) {
+ case BCONSTNT:
+ return GCONSTNT;
+ case BVOLATILE:
+ return GVOLATILE;
+ case BVOLATILE|BCONSTNT:
+ return GCONSTNT|GVOLATILE;
+ }
+ return GXXX;
+}
+
+int
+simplec(long b)
+{
+
+ b &= BCLASS;
+ switch(b) {
+ case 0:
+ case BREGISTER:
+ return CXXX;
+ case BAUTO:
+ case BAUTO|BREGISTER:
+ return CAUTO;
+ case BEXTERN:
+ return CEXTERN;
+ case BEXTERN|BREGISTER:
+ return CEXREG;
+ case BSTATIC:
+ return CSTATIC;
+ case BTYPEDEF:
+ return CTYPEDEF;
+ }
+ diag(Z, "illegal combination of classes %Q", b);
+ return CXXX;
+}
+
+Type*
+simplet(long b)
+{
+
+ b &= ~BCLASS & ~BGARB;
+ switch(b) {
+ case BCHAR:
+ case BCHAR|BSIGNED:
+ return types[TCHAR];
+
+ case BCHAR|BUNSIGNED:
+ return types[TUCHAR];
+
+ case BSHORT:
+ case BSHORT|BINT:
+ case BSHORT|BSIGNED:
+ case BSHORT|BINT|BSIGNED:
+ return types[TSHORT];
+
+ case BUNSIGNED|BSHORT:
+ case BUNSIGNED|BSHORT|BINT:
+ return types[TUSHORT];
+
+ case 0:
+ case BINT:
+ case BINT|BSIGNED:
+ case BSIGNED:
+ return types[TINT];
+
+ case BUNSIGNED:
+ case BUNSIGNED|BINT:
+ return types[TUINT];
+
+ case BLONG:
+ case BLONG|BINT:
+ case BLONG|BSIGNED:
+ case BLONG|BINT|BSIGNED:
+ return types[TLONG];
+
+ case BUNSIGNED|BLONG:
+ case BUNSIGNED|BLONG|BINT:
+ return types[TULONG];
+
+ case BVLONG|BLONG:
+ case BVLONG|BLONG|BINT:
+ case BVLONG|BLONG|BSIGNED:
+ case BVLONG|BLONG|BINT|BSIGNED:
+ return types[TVLONG];
+
+ case BVLONG|BLONG|BUNSIGNED:
+ case BVLONG|BLONG|BINT|BUNSIGNED:
+ return types[TUVLONG];
+
+ case BFLOAT:
+ return types[TFLOAT];
+
+ case BDOUBLE:
+ case BDOUBLE|BLONG:
+ case BFLOAT|BLONG:
+ return types[TDOUBLE];
+
+ case BVOID:
+ return types[TVOID];
+ }
+
+ diag(Z, "illegal combination of types %Q", b);
+ return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+ int i;
+ ulong b;
+
+ return 0;
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1L << i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ttab[i]) {
+ if(ttab == tasign)
+ if(b == BSTRUCT || b == BUNION)
+ if(!sametype(t1, t2))
+ return 1;
+ if(n->op != OCAST)
+ if(b == BIND && i == TIND)
+ if(!sametype(t1, t2))
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+
+ if(0 && stcompat(n, t1, t2, ttab)) {
+ if(t1 == T)
+ diag(n, "incompatible type: \"%T\" for op \"%O\"",
+ t2, n->op);
+ else
+ diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+ t1, t2, n->op);
+ return 1;
+ }
+ return 0;
+}
+
+void
+makedot(Node *n, Type *t, long o)
+{
+ USED(n);
+ USED(o);
+ USED(t);
+ return;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n)
+{
+ Type *t1, *xt;
+
+ xt = T;
+
+ /*
+ * look it up by name
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == s) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ if(xt != T)
+ return xt;
+
+ /*
+ * look it up by type
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(sametype(s->type, t1)) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ if(xt != T)
+ return xt;
+
+ /*
+ * look it up in unnamed substructures
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(dotsearch(s, t1->link, n) != T) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ return xt;
+
+ambig:
+ diag(n, "ambiguous structure element: %s", s->name);
+ return xt;
+}
+
+long
+dotoffset(Type *st, Type *lt, Node *n)
+{
+ Type *t;
+ Sym *g;
+ long o, o1;
+
+ o = -1;
+ /*
+ * first try matching at the top level
+ * for matching tag names
+ */
+ g = st->tag;
+ if(g != S)
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(g == t->tag) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * second try matching at the top level
+ * for similar types
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(sametype(st, t)) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * last try matching sub-levels
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(typesu[t->etype]) {
+ o1 = dotoffset(st, t, n);
+ if(o1 >= 0) {
+ if(o >= 0)
+ goto ambig;
+ o = o1 + t->offset;
+ }
+ }
+ return o;
+
+ambig:
+ diag(n, "ambiguous unnamed structure element");
+ return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+ if(n != Z) {
+ if(n->type->etype != TDOUBLE)
+ return 1;
+ switch(n->op) {
+ case OCONST:
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ case OADD: /* no need to get more exotic than this */
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ if(!allfloat(n->right, flag))
+ break;
+ case OCAST:
+ if(!allfloat(n->left, flag))
+ break;
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+ Type *l, *r;
+
+ l = il;
+ r = ir;
+
+ if(l == T)
+ return;
+ if(l->garb & GCONSTNT) {
+ warn(n, "assignment to a constant type (%T)", il);
+ return;
+ }
+ if(r == T)
+ return;
+ for(;;) {
+ if(l->etype != TIND || r->etype != TIND)
+ break;
+ l = l->link;
+ r = r->link;
+ if(l == T || r == T)
+ break;
+ if(r->garb & GCONSTNT)
+ if(!(l->garb & GCONSTNT)) {
+ warn(n, "assignment of a constant pointer type (%T)", ir);
+ break;
+ }
+ }
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+ if(st->etype == TFLOAT && allfloat(l, 0))
+ allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+ Type *lt;
+
+ lt = l->type;
+ if(lt == T)
+ return;
+ if(st->etype == TIND && vconst(l) == 0) {
+ l->type = st;
+ l->vconst = 0;
+ return;
+ }
+ typeext1(st, l);
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+ int i, b;
+
+ if(t1->nbits)
+ return 0;
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1<<i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ncast[i])
+ return 1;
+ return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+ int et1, et2;
+
+ if(t1 == T)
+ return 0;
+ if(t1->nbits)
+ return 0;
+ if(t2 == T)
+ return 0;
+ et1 = t1->etype;
+ et2 = t2->etype;
+ if(et1 == et2)
+ return 1;
+ if(typefd[et1] && typefd[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ if(typechlp[et1] && typechlp[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+ Type *t1, *t2;
+ int i, j, k;
+ long w;
+
+ t1 = n->left->type;
+ if(n->right == Z)
+ t2 = t1;
+ else
+ t2 = n->right->type;
+ i = TXXX;
+ if(t1 != T)
+ i = t1->etype;
+ j = TXXX;
+ if(t2 != T)
+ j = t2->etype;
+ k = tab[i][j];
+ if(k == TIND) {
+ if(i == TIND)
+ n->type = t1;
+ else
+ if(j == TIND)
+ n->type = t2;
+ } else {
+ /* convert up to at least int */
+ if(f == 1)
+ while(k < TINT)
+ k += 2;
+ n->type = types[k];
+ }
+ if(n->op == OSUB)
+ if(i == TIND && j == TIND) {
+ w = n->right->type->link->width;
+ if(w < 1)
+ goto bad;
+ n->type = types[TLONG];
+ return;
+ }
+ if(!sametype(n->type, n->left->type)) {
+ n->left = new1(OCAST, n->left, Z);
+ n->left->type = n->type;
+ }
+ if(n->right != Z)
+ if(!sametype(n->type, n->right->type)) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = n->type;
+ }
+ return;
+bad:
+ diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+int
+side(Node *n)
+{
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ case OCAST:
+ case ONOT:
+ case OADDR:
+ case OIND:
+ n = n->left;
+ goto loop;
+
+ case OCOND:
+ if(side(n->left))
+ break;
+ n = n->right;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OLMOD:
+ case OANDAND:
+ case OOROR:
+ case OCOMMA:
+ case ODOT:
+ if(side(n->left))
+ break;
+ n = n->right;
+ goto loop;
+
+ case OSIGN:
+ case OSIZE:
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case ONAME:
+ return 0;
+ }
+ return 1;
+}
+
+int
+vconst(Node *n)
+{
+ int i;
+
+ if(n == Z)
+ goto no;
+ if(n->op != OCONST)
+ goto no;
+ if(n->type == T)
+ goto no;
+ switch(n->type->etype)
+ {
+ case TFLOAT:
+ case TDOUBLE:
+ i = 100;
+ if(n->fconst > i || n->fconst < -i)
+ goto no;
+ i = n->fconst;
+ if(i != n->fconst)
+ goto no;
+ return i;
+
+ case TVLONG:
+ case TUVLONG:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+ }
+no:
+ return -159; /* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+vlog(Node *n)
+{
+ int s, i;
+ uvlong m, v;
+
+ if(n->op != OCONST)
+ goto bad;
+ if(typefd[n->type->etype])
+ goto bad;
+
+ v = n->vconst;
+
+ s = 0;
+ m = MASK(8*sizeof(uvlong));
+ for(i=32; i; i>>=1) {
+ m >>= i;
+ if(!(v & m)) {
+ v >>= i;
+ s += i;
+ }
+ }
+ if(v == 1)
+ return s;
+
+bad:
+ return -1;
+}
+
+int
+topbit(ulong v)
+{
+ int i;
+
+ for(i = -1; v; i++)
+ v >>= 1;
+ return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ * if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+ vlong v;
+ Node *t;
+
+ if(l->op != OCONST)
+ return;
+ if(r->op != OCAST)
+ return;
+ if(!nilcast(r->left->type, r->type))
+ return;
+ switch(r->type->etype) {
+ default:
+ return;
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ v = convvtox(l->vconst, r->type->etype);
+ if(v != l->vconst)
+ return;
+ break;
+ }
+ t = new1(OXXX, Z, Z);
+ *t = *l;
+ l->op = OCAST;
+ l->left = t;
+ l->right = Z;
+ l->type = r->left->type;
+ *r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+ switch(o) {
+ default:
+ diag(Z, "bad in relindex: %O", o);
+ case OEQ: return 0;
+ case ONE: return 1;
+ case OLE: return 2;
+ case OLS: return 3;
+ case OLT: return 4;
+ case OLO: return 5;
+ case OGE: return 6;
+ case OHS: return 7;
+ case OGT: return 8;
+ case OHI: return 9;
+ }
+}
+
+Node*
+invert(Node *n)
+{
+ Node *i;
+
+ if(n == Z || n->op != OLIST || n->blk)
+ return n;
+ i = n;
+ for(n = n->left; n != Z; n = n->left) {
+ if(n->op != OLIST || n->blk)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+int
+bitno(long b)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(b & (1L<<i))
+ return i;
+ diag(Z, "bad in bitno");
+ return 0;
+}
+
+long
+typebitor(long a, long b)
+{
+ long c;
+
+ c = a | b;
+ if(a & b)
+ if((a & b) == BLONG)
+ c |= BVLONG; /* long long => vlong */
+ else
+ warn(Z, "once is enough: %Q", a & b);
+ return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(0)
+ abort();
+ if(n != Z)
+ if(0)
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ if(nerrors > 10) {
+ fprint(2, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ if(0) {
+ fprint(2, "warning: ");
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(n != Z)
+ if(0)
+ prtree(n, "warning");
+ }
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%L %s\n", lineno, buf);
+ nerrors++;
+ if(nerrors > 10) {
+ fprint(2, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(0)
+ abort();
+ if(n != Z)
+ if(0)
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ errorexit();
+}
+
+ulong thash1 = 0x2edab8c9;
+ulong thash2 = 0x1dc74fb8;
+ulong thash3 = 0x1f241331;
+ulong thash[NALLTYPES];
+Init thashinit[] =
+{
+ TXXX, 0x17527bbd, 0,
+ TCHAR, 0x5cedd32b, 0,
+ TUCHAR, 0x552c4454, 0,
+ TSHORT, 0x63040b4b, 0,
+ TUSHORT, 0x32a45878, 0,
+ TINT, 0x4151d5bd, 0,
+ TUINT, 0x5ae707d6, 0,
+ TLONG, 0x5ef20f47, 0,
+ TULONG, 0x36d8eb8f, 0,
+ TVLONG, 0x6e5e9590, 0,
+ TUVLONG, 0x75910105, 0,
+ TFLOAT, 0x25fd7af1, 0,
+ TDOUBLE, 0x7c40a1b2, 0,
+ TIND, 0x1b832357, 0,
+ TFUNC, 0x6babc9cb, 0,
+ TARRAY, 0x7c50986d, 0,
+ TVOID, 0x44112eff, 0,
+ TSTRUCT, 0x7c2da3bf, 0,
+ TUNION, 0x3eb25e98, 0,
+ TENUM, 0x44b54f61, 0,
+ TFILE, 0x19242ac3, 0,
+ TOLD, 0x22b15988, 0,
+ TDOT, 0x0204f6b3, 0,
+ -1, 0, 0,
+};
+
+char* bnames[NALIGN];
+Init bnamesinit[] =
+{
+ Axxx, 0, "Axxx",
+ Ael1, 0, "el1",
+ Ael2, 0, "el2",
+ Asu2, 0, "su2",
+ Aarg0, 0, "arg0",
+ Aarg1, 0, "arg1",
+ Aarg2, 0, "arg2",
+ Aaut3, 0, "aut3",
+ -1, 0, 0,
+};
+
+char* tnames[NALLTYPES];
+Init tnamesinit[] =
+{
+ TXXX, 0, "xxx",
+ TCHAR, 0, "char",
+ TUCHAR, 0, "uchar",
+ TSHORT, 0, "short",
+ TUSHORT, 0, "ushort",
+ TINT, 0, "int",
+ TUINT, 0, "uint",
+ TLONG, 0, "long",
+ TULONG, 0, "ulong",
+ TVLONG, 0, "vlong",
+ TUVLONG, 0, "uvlong",
+ TFLOAT, 0, "float",
+ TDOUBLE, 0, "double",
+ TIND, 0, "pointer",
+ TFUNC, 0, "function",
+ TARRAY, 0, "array",
+ TVOID, 0, "void",
+ TSTRUCT, 0, "struct",
+ TUNION, 0, "union",
+ TENUM, 0, "enum",
+ TFILE, 0, "file",
+ TOLD, 0, "old",
+ TDOT, 0, "dot",
+ TSTRING, 0, "string",
+ TFD, 0, "fd",
+ TTUPLE, 0, "tuple",
+ -1, 0, 0,
+};
+
+char* gnames[NGTYPES];
+Init gnamesinit[] =
+{
+ GXXX, 0, "GXXX",
+ GCONSTNT, 0, "CONST",
+ GVOLATILE, 0, "VOLATILE",
+ GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
+ -1, 0, 0,
+};
+
+char* qnames[NALLTYPES];
+Init qnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+
+ TAUTO, 0, "AUTO",
+ TEXTERN, 0, "EXTERN",
+ TSTATIC, 0, "STATIC",
+ TTYPEDEF, 0, "TYPEDEF",
+ TREGISTER, 0, "REGISTER",
+ TCONSTNT, 0, "CONSTNT",
+ TVOLATILE, 0, "VOLATILE",
+ TUNSIGNED, 0, "UNSIGNED",
+ TSIGNED, 0, "SIGNED",
+ TDOT, 0, "DOT",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ -1, 0, 0,
+};
+char* cnames[NCTYPES];
+Init cnamesinit[] =
+{
+ CXXX, 0, "CXXX",
+ CAUTO, 0, "AUTO",
+ CEXTERN, 0, "EXTERN",
+ CGLOBL, 0, "GLOBL",
+ CSTATIC, 0, "STATIC",
+ CLOCAL, 0, "LOCAL",
+ CTYPEDEF, 0, "TYPEDEF",
+ CPARAM, 0, "PARAM",
+ CSELEM, 0, "SELEM",
+ CLABEL, 0, "LABEL",
+ CEXREG, 0, "EXREG",
+ -1, 0, 0,
+};
+
+char* onames[OEND+1];
+Init onamesinit[] =
+{
+ ONOOP, 0, "NOOP",
+ OXXX, 0, "OXXX",
+ OADD, 0, "ADD",
+ OADDR, 0, "ADDR",
+ OAND, 0, "AND",
+ OANDAND, 0, "ANDAND",
+ OARRAY, 0, "ARRAY",
+ OAS, 0, "AS",
+ OASI, 0, "ASI",
+ OASADD, 0, "ASADD",
+ OASAND, 0, "ASAND",
+ OASASHL, 0, "ASASHL",
+ OASASHR, 0, "ASASHR",
+ OASDIV, 0, "ASDIV",
+ OASHL, 0, "ASHL",
+ OASHR, 0, "ASHR",
+ OASLDIV, 0, "ASLDIV",
+ OASLMOD, 0, "ASLMOD",
+ OASLMUL, 0, "ASLMUL",
+ OASLSHR, 0, "ASLSHR",
+ OASMOD, 0, "ASMOD",
+ OASMUL, 0, "ASMUL",
+ OASOR, 0, "ASOR",
+ OASSUB, 0, "ASSUB",
+ OASXOR, 0, "ASXOR",
+ OBIT, 0, "BIT",
+ OBREAK, 0, "BREAK",
+ OCASE, 0, "CASE",
+ OCAST, 0, "CAST",
+ OCOMMA, 0, "COMMA",
+ OCOND, 0, "COND",
+ OCONST, 0, "CONST",
+ OCONTINUE, 0, "CONTINUE",
+ ODIV, 0, "DIV",
+ ODOT, 0, "DOT",
+ ODOTDOT, 0, "DOTDOT",
+ ODWHILE, 0, "DWHILE",
+ OENUM, 0, "ENUM",
+ OEQ, 0, "EQ",
+ OFOR, 0, "FOR",
+ OFUNC, 0, "FUNC",
+ OGE, 0, "GE",
+ OGOTO, 0, "GOTO",
+ OGT, 0, "GT",
+ OHI, 0, "HI",
+ OHS, 0, "HS",
+ OIF, 0, "IF",
+ OIND, 0, "IND",
+ OINDREG, 0, "INDREG",
+ OINIT, 0, "INIT",
+ OLABEL, 0, "LABEL",
+ OLDIV, 0, "LDIV",
+ OLE, 0, "LE",
+ OLIST, 0, "LIST",
+ OLMOD, 0, "LMOD",
+ OLMUL, 0, "LMUL",
+ OLO, 0, "LO",
+ OLS, 0, "LS",
+ OLSHR, 0, "LSHR",
+ OLT, 0, "LT",
+ OMOD, 0, "MOD",
+ OMUL, 0, "MUL",
+ ONAME, 0, "NAME",
+ ONE, 0, "NE",
+ ONOT, 0, "NOT",
+ OOR, 0, "OR",
+ OOROR, 0, "OROR",
+ OPOSTDEC, 0, "POSTDEC",
+ OPOSTINC, 0, "POSTINC",
+ OPREDEC, 0, "PREDEC",
+ OPREINC, 0, "PREINC",
+ OPROTO, 0, "PROTO",
+ OREGISTER, 0, "REGISTER",
+ ORETURN, 0, "RETURN",
+ OSET, 0, "SET",
+ OSIGN, 0, "SIGN",
+ OSIZE, 0, "SIZE",
+ OSTRING, 0, "STRING",
+ OLSTRING, 0, "LSTRING",
+ OSTRUCT, 0, "STRUCT",
+ OSUB, 0, "SUB",
+ OSWITCH, 0, "SWITCH",
+ OUNION, 0, "UNION",
+ OUSED, 0, "USED",
+ OWHILE, 0, "WHILE",
+ OXOR, 0, "XOR",
+ ONEG, 0, "NEG",
+ OCOM, 0, "COM",
+ OELEM, 0, "ELEM",
+ OTST, 0, "TST",
+ OINDEX, 0, "INDEX",
+ OFAS, 0, "FAS",
+ OBLK, 0, "BLK",
+ OPOS, 0, "POS",
+ ONUL, 0, "NUL",
+ ODOTIND, 0, "DOTIND",
+ OARRIND, 0, "ARRIND",
+ ODAS, 0, "ODAS",
+ OASD, 0, "OASD",
+ OIOTA, 0, "IOTA",
+ OLEN, 0, "LEN",
+ OBRACKET, 0, "BRACKET",
+ OREF, 0, "REF",
+ OARRAYOF, 0, "ARRAYOF",
+ OSLICE, 0, "SLICE",
+ OSADDR, 0, "SADDR",
+ ONIL, 0, "NIL",
+ OS2AB, 0, "S2AB",
+ OAB2S, 0, "AB2S",
+ OFILDES, 0, "FILDES",
+ OFD, 0, "FD",
+ OTUPLE, 0, "TUPLE",
+ OT0, 0, "T0",
+ ORETV, 0, "RETV",
+ OCAT, 0, "CAT",
+ OSBREAK, 0, "SBREAK",
+ OLDOT, 0, "LDOT",
+ OMDOT, 0, "MDOT",
+ OCODE, 0, "CODE",
+ ODECE, 0, "DECE",
+ ODECT, 0, "DECT",
+ ODECV, 0, "DECV",
+ ODECF, 0, "DECF",
+ OPUSH, 0, "PUSH",
+ OPOP, 0, "POP",
+ OEND, 0, "END",
+ -1, 0, 0,
+};
+
+char comrel[12] =
+{
+ ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+char invrel[12] =
+{
+ OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+char logrel[12] =
+{
+ OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+char typei[NTYPE];
+int typeiinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+char typeu[NTYPE];
+int typeuinit[] =
+{
+ TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+char typesuv[NTYPE];
+int typesuvinit[] =
+{
+ TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+char typeilp[NTYPE];
+int typeilpinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+char typechl[NTYPE];
+int typechlinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+char typechlp[NTYPE];
+int typechlpinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+char typechlpfd[NTYPE];
+int typechlpfdinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+char typec[NTYPE];
+int typecinit[] =
+{
+ TCHAR, TUCHAR, -1
+};
+
+char typeh[NTYPE];
+int typehinit[] =
+{
+ TSHORT, TUSHORT, -1,
+};
+
+char typeil[NTYPE];
+int typeilinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, -1,
+};
+
+char typev[NTYPE];
+int typevinit[] =
+{
+ TVLONG, TUVLONG, -1,
+};
+
+char typefd[NTYPE];
+int typefdinit[] =
+{
+ TFLOAT, TDOUBLE, -1,
+};
+
+char typeaf[NTYPE];
+int typeafinit[] =
+{
+ TFUNC, TARRAY, -1,
+};
+
+char typesu[NTYPE];
+int typesuinit[] =
+{
+ TSTRUCT, TUNION, -1,
+};
+
+long tasign[NTYPE];
+Init tasigninit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ TSTRUCT, BSTRUCT, 0,
+ TUNION, BUNION, 0,
+ -1, 0, 0,
+};
+
+long tasadd[NTYPE];
+Init tasaddinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long tcast[NTYPE];
+Init tcastinit[] =
+{
+ TCHAR, BNUMBER|BIND|BVOID, 0,
+ TUCHAR, BNUMBER|BIND|BVOID, 0,
+ TSHORT, BNUMBER|BIND|BVOID, 0,
+ TUSHORT, BNUMBER|BIND|BVOID, 0,
+ TINT, BNUMBER|BIND|BVOID, 0,
+ TUINT, BNUMBER|BIND|BVOID, 0,
+ TLONG, BNUMBER|BIND|BVOID, 0,
+ TULONG, BNUMBER|BIND|BVOID, 0,
+ TVLONG, BNUMBER|BIND|BVOID, 0,
+ TUVLONG, BNUMBER|BIND|BVOID, 0,
+ TFLOAT, BNUMBER|BVOID, 0,
+ TDOUBLE, BNUMBER|BVOID, 0,
+ TIND, BINTEGER|BIND|BVOID, 0,
+ TVOID, BVOID, 0,
+ TSTRUCT, BSTRUCT|BVOID, 0,
+ TUNION, BUNION|BVOID, 0,
+ -1, 0, 0,
+};
+
+long tadd[NTYPE];
+Init taddinit[] =
+{
+ TCHAR, BNUMBER|BIND, 0,
+ TUCHAR, BNUMBER|BIND, 0,
+ TSHORT, BNUMBER|BIND, 0,
+ TUSHORT, BNUMBER|BIND, 0,
+ TINT, BNUMBER|BIND, 0,
+ TUINT, BNUMBER|BIND, 0,
+ TLONG, BNUMBER|BIND, 0,
+ TULONG, BNUMBER|BIND, 0,
+ TVLONG, BNUMBER|BIND, 0,
+ TUVLONG, BNUMBER|BIND, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long tsub[NTYPE];
+Init tsubinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER|BIND, 0,
+ -1, 0, 0,
+};
+
+long tmul[NTYPE];
+Init tmulinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ -1, 0, 0,
+};
+
+long tand[NTYPE];
+Init tandinit[] =
+{
+ TCHAR, BINTEGER, 0,
+ TUCHAR, BINTEGER, 0,
+ TSHORT, BINTEGER, 0,
+ TUSHORT, BINTEGER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BINTEGER, 0,
+ TULONG, BINTEGER, 0,
+ TVLONG, BINTEGER, 0,
+ TUVLONG, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long trel[NTYPE];
+Init trelinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ -1, 0, 0,
+};
+
+long tfunct[1] =
+{
+ BFUNC,
+};
+
+long tindir[1] =
+{
+ BIND,
+};
+
+long tdot[1] =
+{
+ BSTRUCT|BUNION,
+};
+
+long tnot[1] =
+{
+ BNUMBER|BIND,
+};
+
+long targ[1] =
+{
+ BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+char tab[NTYPE][NTYPE] =
+{
+/*TXXX*/ { 0,
+ },
+
+/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+ TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+ TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+ TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+ },
+/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+ TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+ },
+/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+ TIND, TIND, TIND, TIND, TIND, TIND,
+ },
+};
+
+void
+urk(char *name, int max, int i)
+{
+ if(i >= max) {
+ fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+ exits("init");
+ }
+}
+
+void
+tinit(void)
+{
+ int i;
+ Init *p;
+
+ for(p=thashinit; p->code >= 0; p++) {
+ urk("thash", nelem(thash), p->code);
+ thash[p->code] = p->value;
+ }
+ for(p=bnamesinit; p->code >= 0; p++) {
+ urk("bnames", nelem(bnames), p->code);
+ bnames[p->code] = p->s;
+ }
+ for(p=tnamesinit; p->code >= 0; p++) {
+ urk("tnames", nelem(tnames), p->code);
+ tnames[p->code] = p->s;
+ }
+ for(p=gnamesinit; p->code >= 0; p++) {
+ urk("gnames", nelem(gnames), p->code);
+ gnames[p->code] = p->s;
+ }
+ for(p=qnamesinit; p->code >= 0; p++) {
+ urk("qnames", nelem(qnames), p->code);
+ qnames[p->code] = p->s;
+ }
+ for(p=cnamesinit; p->code >= 0; p++) {
+ urk("cnames", nelem(cnames), p->code);
+ cnames[p->code] = p->s;
+ }
+ for(p=onamesinit; p->code >= 0; p++) {
+ urk("onames", nelem(onames), p->code);
+ onames[p->code] = p->s;
+ }
+ for(i=0; typeiinit[i] >= 0; i++) {
+ urk("typei", nelem(typei), typeiinit[i]);
+ typei[typeiinit[i]] = 1;
+ }
+ for(i=0; typeuinit[i] >= 0; i++) {
+ urk("typeu", nelem(typeu), typeuinit[i]);
+ typeu[typeuinit[i]] = 1;
+ }
+ for(i=0; typesuvinit[i] >= 0; i++) {
+ urk("typesuv", nelem(typesuv), typesuvinit[i]);
+ typesuv[typesuvinit[i]] = 1;
+ }
+ for(i=0; typeilpinit[i] >= 0; i++) {
+ urk("typeilp", nelem(typeilp), typeilpinit[i]);
+ typeilp[typeilpinit[i]] = 1;
+ }
+ for(i=0; typechlinit[i] >= 0; i++) {
+ urk("typechl", nelem(typechl), typechlinit[i]);
+ typechl[typechlinit[i]] = 1;
+ }
+ for(i=0; typechlpinit[i] >= 0; i++) {
+ urk("typechlp", nelem(typechlp), typechlpinit[i]);
+ typechlp[typechlpinit[i]] = 1;
+ }
+ for(i=0; typechlpfdinit[i] >= 0; i++) {
+ urk("typechlpfd", nelem(typechlpfd), typechlpfdinit[i]);
+ typechlpfd[typechlpfdinit[i]] = 1;
+ }
+ for(i=0; typecinit[i] >= 0; i++) {
+ urk("typec", nelem(typec), typecinit[i]);
+ typec[typecinit[i]] = 1;
+ }
+ for(i=0; typehinit[i] >= 0; i++) {
+ urk("typeh", nelem(typeh), typehinit[i]);
+ typeh[typehinit[i]] = 1;
+ }
+ for(i=0; typeilinit[i] >= 0; i++) {
+ urk("typeil", nelem(typeil), typeilinit[i]);
+ typeil[typeilinit[i]] = 1;
+ }
+ for(i=0; typevinit[i] >= 0; i++) {
+ urk("typev", nelem(typev), typevinit[i]);
+ typev[typevinit[i]] = 1;
+ }
+ for(i=0; typefdinit[i] >= 0; i++) {
+ urk("typefd", nelem(typefd), typefdinit[i]);
+ typefd[typefdinit[i]] = 1;
+ }
+ for(i=0; typeafinit[i] >= 0; i++) {
+ urk("typeaf", nelem(typeaf), typeafinit[i]);
+ typeaf[typeafinit[i]] = 1;
+ }
+ for(i=0; typesuinit[i] >= 0; i++) {
+ urk("typesu", nelem(typesu), typesuinit[i]);
+ typesu[typesuinit[i]] = 1;
+ }
+ for(p=tasigninit; p->code >= 0; p++) {
+ urk("tasign", nelem(tasign), p->code);
+ tasign[p->code] = p->value;
+ }
+ for(p=tasaddinit; p->code >= 0; p++) {
+ urk("tasadd", nelem(tasadd), p->code);
+ tasadd[p->code] = p->value;
+ }
+ for(p=tcastinit; p->code >= 0; p++) {
+ urk("tcast", nelem(tcast), p->code);
+ tcast[p->code] = p->value;
+ }
+ for(p=taddinit; p->code >= 0; p++) {
+ urk("tadd", nelem(tadd), p->code);
+ tadd[p->code] = p->value;
+ }
+ for(p=tsubinit; p->code >= 0; p++) {
+ urk("tsub", nelem(tsub), p->code);
+ tsub[p->code] = p->value;
+ }
+ for(p=tmulinit; p->code >= 0; p++) {
+ urk("tmul", nelem(tmul), p->code);
+ tmul[p->code] = p->value;
+ }
+ for(p=tandinit; p->code >= 0; p++) {
+ urk("tand", nelem(tand), p->code);
+ tand[p->code] = p->value;
+ }
+ for(p=trelinit; p->code >= 0; p++) {
+ urk("trel", nelem(trel), p->code);
+ trel[p->code] = p->value;
+ }
+}
diff --git a/utils/cat/cat.c b/utils/cat/cat.c
new file mode 100644
index 00000000..22d8d354
--- /dev/null
+++ b/utils/cat/cat.c
@@ -0,0 +1,35 @@
+#include <lib9.h>
+
+void
+cat(int f, char *s)
+{
+ char buf[8192];
+ long n;
+
+ while((n=read(f, buf, (long)sizeof buf))>0)
+ if(write(1, buf, n)!=n)
+ sysfatal("write error copying %s: %r", s);
+ if(n < 0)
+ sysfatal("error reading %s: %r", s);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int f, i;
+
+ argv0 = "cat";
+ if(argc == 1)
+ cat(0, "<stdin>");
+ else for(i=1; i<argc; i++){
+ f = open(argv[i], OREAD);
+ if(f < 0)
+ sysfatal("can't open %s: %r", argv[i]);
+ else{
+ cat(f, argv[i]);
+ close(f);
+ }
+ }
+ exits(0);
+}
+
diff --git a/utils/cat/mkfile b/utils/cat/mkfile
new file mode 100644
index 00000000..48679b92
--- /dev/null
+++ b/utils/cat/mkfile
@@ -0,0 +1,10 @@
+<../../mkconfig
+
+TARG=cat
+
+OFILES= cat.$O\
+
+LIBS=9
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/cc/Nt.c b/utils/cc/Nt.c
new file mode 100644
index 00000000..11209ea4
--- /dev/null
+++ b/utils/cc/Nt.c
@@ -0,0 +1,135 @@
+#include <windows.h>
+#include <lib9.h>
+
+#define Windows (1<<2) /* hack - can't include cc.h because of clashes */
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ fprint(2, "mywait called\n");
+ abort();
+ return 0;
+}
+
+int
+mydup(int f1, int f2)
+{
+ fprint(2, "mydup called\n");
+ abort();
+ return 0;
+}
+
+int
+mypipe(int *fd)
+{
+ fprint(2, "mypipe called\n");
+ abort();
+ return 0;
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Windows;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getcwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ fprint(2, "myexec called\n");
+ abort();
+ return 0;
+}
+
+int
+myfork(void)
+{
+ fprint(2, "myfork called\n");
+ abort();
+ return 0;
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(uint n)
+{
+ return mysbrk(n);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ return mysbrk(m*n);
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+void
+free(void *p)
+{
+}
+
+int
+myaccess(char *f)
+{
+ int fd;
+
+ fd = open(f, OREAD);
+ if(fd < 0)
+ return -1;
+ close(fd);
+ return 0;
+}
diff --git a/utils/cc/Plan9.c b/utils/cc/Plan9.c
new file mode 100644
index 00000000..f4d80364
--- /dev/null
+++ b/utils/cc/Plan9.c
@@ -0,0 +1,114 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ int p;
+ Waitmsg *w;
+
+ if((w = wait()) == nil)
+ return -1;
+ else{
+ p = w->pid;
+ *s = 0;
+ if(w->msg[0])
+ *s = 1;
+ free(w);
+ return p;
+ }
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return exec(path, argv);
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myaccess(char *f)
+{
+ return access(f, AEXIST);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/cc/Posix.c b/utils/cc/Posix.c
new file mode 100644
index 00000000..dfe28d60
--- /dev/null
+++ b/utils/cc/Posix.c
@@ -0,0 +1,98 @@
+#include "cc.h"
+#include <sys/wait.h>
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ return wait(s);
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup2(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Unix;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return (char*)getcwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return execvp(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(size_t n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void *p)
+{
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
+
+int
+myaccess(char *f)
+{
+ return access(f, 0);
+}
diff --git a/utils/cc/acid.c b/utils/cc/acid.c
new file mode 100644
index 00000000..3d898883
--- /dev/null
+++ b/utils/cc/acid.c
@@ -0,0 +1,301 @@
+#include "cc.h"
+
+static char *kwd[] =
+{
+ "$adt", "$aggr", "$append", "$complex", "$defn",
+ "$delete", "$do", "$else", "$eval", "$head", "$if",
+ "$local", "$loop", "$return", "$tail", "$then",
+ "$union", "$whatis", "$while",
+};
+
+char*
+amap(char *s)
+{
+ int i, bot, top, new;
+
+ bot = 0;
+ top = bot + nelem(kwd) - 1;
+ while(bot <= top){
+ new = bot + (top - bot)/2;
+ i = strcmp(kwd[new]+1, s);
+ if(i == 0)
+ return kwd[new];
+
+ if(i < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return s;
+}
+
+Sym*
+acidsue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+Sym*
+acidfun(Type *t)
+{
+ int h;
+ Sym *s;
+
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == t)
+ return s;
+ return 0;
+}
+
+char acidchar[NTYPE];
+Init acidcinit[] =
+{
+ TCHAR, 'C', 0,
+ TUCHAR, 'b', 0,
+ TSHORT, 'd', 0,
+ TUSHORT, 'u', 0,
+ TLONG, 'D', 0,
+ TULONG, 'U', 0,
+ TVLONG, 'V', 0,
+ TUVLONG, 'W', 0,
+ TFLOAT, 'f', 0,
+ TDOUBLE, 'F', 0,
+ TARRAY, 'a', 0,
+ TIND, 'X', 0,
+ -1, 0, 0,
+};
+
+static void
+acidinit(void)
+{
+ Init *p;
+
+ for(p=acidcinit; p->code >= 0; p++)
+ acidchar[p->code] = p->value;
+
+ acidchar[TINT] = acidchar[TLONG];
+ acidchar[TUINT] = acidchar[TULONG];
+ if(types[TINT]->width != types[TLONG]->width) {
+ acidchar[TINT] = acidchar[TSHORT];
+ acidchar[TUINT] = acidchar[TUSHORT];
+ if(types[TINT]->width != types[TSHORT]->width)
+ warn(Z, "acidmember int not long or short");
+ }
+
+}
+
+void
+acidmember(Type *t, long off, int flag)
+{
+ Sym *s, *s1;
+ Type *l;
+ static int acidcharinit = 0;
+
+ if(acidcharinit == 0) {
+ acidinit();
+ acidcharinit = 1;
+ }
+ s = t->sym;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, " T%d\n", t->etype);
+ break;
+
+ case TIND:
+ if(s == S)
+ break;
+ if(flag) {
+ for(l=t; l->etype==TIND; l=l->link)
+ ;
+ if(typesu[l->etype]) {
+ s1 = acidsue(l->link);
+ if(s1 != S) {
+ Bprint(&outbuf, " 'A' %s %ld %s;\n",
+ amap(s1->name),
+ t->offset+off, amap(s->name));
+ break;
+ }
+ }
+ } else {
+ Bprint(&outbuf,
+ "\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n",
+ amap(s->name), amap(s->name));
+ break;
+ }
+
+ case TINT:
+ case TUINT:
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TARRAY:
+ if(s == S)
+ break;
+ if(flag) {
+ Bprint(&outbuf, " '%c' %ld %s;\n",
+ acidchar[t->etype], t->offset+off, amap(s->name));
+ } else {
+ Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n",
+ amap(s->name), amap(s->name));
+ }
+ break;
+
+ case TSTRUCT:
+ case TUNION:
+ s1 = acidsue(t->link);
+ if(s1 == S)
+ break;
+ if(flag) {
+ if(s == S) {
+ Bprint(&outbuf, " {\n");
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, t->offset+off, flag);
+ Bprint(&outbuf, " };\n");
+ } else {
+ Bprint(&outbuf, " %s %ld %s;\n",
+ amap(s1->name),
+ t->offset+off, amap(s->name));
+ }
+ } else {
+ if(s != S) {
+ Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n",
+ amap(s1->name), amap(s->name));
+ Bprint(&outbuf, "\t%s(addr.%s);\n",
+ amap(s1->name), amap(s->name));
+ Bprint(&outbuf, "\tprint(\"}\\n\");\n");
+ } else {
+ Bprint(&outbuf, "\tprint(\"%s {\\n\");\n",
+ amap(s1->name));
+ Bprint(&outbuf, "\t\t%s(addr+%ld);\n",
+ amap(s1->name), t->offset+off);
+ Bprint(&outbuf, "\tprint(\"}\\n\");\n");
+ }
+ }
+ break;
+ }
+}
+
+void
+acidtype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ Io *i;
+ int n;
+ char *an;
+
+ if(!debug['a'])
+ return;
+ if(debug['a'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ s = acidsue(t->link);
+ if(s == S)
+ return;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, "T%d\n", t->etype);
+ return;
+
+ case TUNION:
+ case TSTRUCT:
+ if(debug['s'])
+ goto asmstr;
+ an = amap(s->name);
+ Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width);
+ Bprint(&outbuf, "aggr %s\n{\n", an);
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, 0, 1);
+ Bprint(&outbuf, "};\n\n");
+
+ Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an);
+ for(l = t->link; l != T; l = l->down)
+ acidmember(l, 0, 0);
+ Bprint(&outbuf, "};\n\n");
+ break;
+ asmstr:
+ if(s == S)
+ break;
+ for(l = t->link; l != T; l = l->down)
+ if(l->sym != S)
+ Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ s->name,
+ l->sym->name,
+ l->offset);
+ break;
+ }
+}
+
+void
+acidvar(Sym *s)
+{
+ int n;
+ Io *i;
+ Type *t;
+ Sym *s1, *s2;
+
+ if(!debug['a'] || debug['s'])
+ return;
+ if(debug['a'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ t = s->type;
+ while(t && t->etype == TIND)
+ t = t->link;
+ if(t == T)
+ return;
+ if(t->etype == TENUM) {
+ Bprint(&outbuf, "%s = ", amap(s->name));
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "%lld;\n", s->vconst);
+ else
+ Bprint(&outbuf, "%f\n;", s->fconst);
+ return;
+ }
+ if(!typesu[t->etype])
+ return;
+ s1 = acidsue(t->link);
+ if(s1 == S)
+ return;
+ switch(s->class) {
+ case CAUTO:
+ case CPARAM:
+ s2 = acidfun(thisfn);
+ if(s2)
+ Bprint(&outbuf, "complex %s %s:%s;\n",
+ amap(s1->name), amap(s2->name), amap(s->name));
+ break;
+
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ case CLOCAL:
+ Bprint(&outbuf, "complex %s %s;\n",
+ amap(s1->name), amap(s->name));
+ break;
+ }
+}
diff --git a/utils/cc/bits.c b/utils/cc/bits.c
new file mode 100644
index 00000000..a22ba512
--- /dev/null
+++ b/utils/cc/bits.c
@@ -0,0 +1,89 @@
+#include "cc.h"
+
+Bits
+bor(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] | b.b[i];
+ return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = a.b[i] & b.b[i];
+ return c;
+}
+
+/*
+Bits
+bnot(Bits a)
+{
+ Bits c;
+ int i;
+
+ for(i=0; i<BITS; i++)
+ c.b[i] = ~a.b[i];
+ return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a->b[i])
+ return 1;
+ return 0;
+}
+
+int
+beq(Bits a, Bits b)
+{
+ int i;
+
+ for(i=0; i<BITS; i++)
+ if(a.b[i] != b.b[i])
+ return 0;
+ return 1;
+}
+
+int
+bnum(Bits a)
+{
+ int i;
+ long b;
+
+ for(i=0; i<BITS; i++)
+ if(b = a.b[i])
+ return 32*i + bitno(b);
+ diag(Z, "bad in bnum");
+ return 0;
+}
+
+Bits
+blsh(uint n)
+{
+ Bits c;
+
+ c = zbits;
+ c.b[n/32] = 1L << (n%32);
+ return c;
+}
+
+int
+bset(Bits a, uint n)
+{
+ if(a.b[n/32] & (1L << (n%32)))
+ return 1;
+ return 0;
+}
diff --git a/utils/cc/cc.h b/utils/cc/cc.h
new file mode 100644
index 00000000..d05b4397
--- /dev/null
+++ b/utils/cc/cc.h
@@ -0,0 +1,768 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Node Node;
+typedef struct Sym Sym;
+typedef struct Type Type;
+typedef struct Funct Funct;
+typedef struct Decl Decl;
+typedef struct Io Io;
+typedef struct Hist Hist;
+typedef struct Term Term;
+typedef struct Init Init;
+typedef struct Bits Bits;
+
+#define NHUNK 50000L
+#define BUFSIZ 8192
+#define NSYMB 500
+#define NHASH 1024
+#define STRINGSZ 200
+#define HISTSZ 20
+#define YYMAXDEPTH 500
+#define NTERM 10
+#define MAXALIGN 7
+
+#define SIGN(n) ((vlong)1<<(n-1))
+#define MASK(n) (SIGN(n)|(SIGN(n)-1))
+
+#define BITS 5
+#define NVAR (BITS*sizeof(ulong)*8)
+struct Bits
+{
+ ulong b[BITS];
+};
+
+struct Node
+{
+ Node* left;
+ Node* right;
+ void* label;
+ long pc;
+ int reg;
+ long xoffset;
+ double fconst; /* fp constant */
+ vlong vconst; /* non fp const */
+ char* cstring; /* character string */
+ ushort* rstring; /* rune string */
+
+ Sym* sym;
+ Type* type;
+ long lineno;
+ char op;
+
+ char oldop;
+ char xcast;
+ char class;
+ char etype;
+ char complex;
+ char addable;
+ char scale;
+ char garb;
+};
+#define Z ((Node*)0)
+
+struct Sym
+{
+ Sym* link;
+ Type* type;
+ Type* suetag;
+ Type* tenum;
+ char* macro;
+ long varlineno;
+ long offset;
+ vlong vconst;
+ double fconst;
+ Node* label;
+ ushort lexical;
+ char *name;
+ ushort block;
+ ushort sueblock;
+ char class;
+ char sym;
+ char aused;
+ char sig;
+};
+#define S ((Sym*)0)
+
+enum{
+ SIGNONE = 0,
+ SIGDONE = 1,
+ SIGINTERN = 2,
+
+ SIGNINTERN = 1729*325*1729,
+};
+
+struct Decl
+{
+ Decl* link;
+ Sym* sym;
+ Type* type;
+ long varlineno;
+ long offset;
+ short val;
+ ushort block;
+ char class;
+ char aused;
+};
+#define D ((Decl*)0)
+
+struct Type
+{
+ Sym* sym;
+ Sym* tag;
+ Funct* funct;
+ Type* link;
+ Type* down;
+ long width;
+ long offset;
+ long lineno;
+ char shift;
+ char nbits;
+ char etype;
+ char garb;
+};
+
+#define T ((Type*)0)
+#define NODECL ((void(*)(int, Type*, Sym*))0)
+
+struct Init /* general purpose initialization */
+{
+ int code;
+ ulong value;
+ char* s;
+};
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char* p;
+ char b[BUFSIZ];
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+EXTERN Hist* hist;
+
+struct Term
+{
+ vlong mult;
+ Node *node;
+};
+
+enum
+{
+ Axxx,
+ Ael1,
+ Ael2,
+ Asu2,
+ Aarg0,
+ Aarg1,
+ Aarg2,
+ Aaut3,
+ NALIGN,
+};
+
+enum /* also in ../{8a,0a}.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+enum
+{
+ DMARK,
+ DAUTO,
+ DSUE,
+ DLABEL,
+};
+enum
+{
+ OXXX,
+ OADD,
+ OADDR,
+ OAND,
+ OANDAND,
+ OARRAY,
+ OAS,
+ OASI,
+ OASADD,
+ OASAND,
+ OASASHL,
+ OASASHR,
+ OASDIV,
+ OASHL,
+ OASHR,
+ OASLDIV,
+ OASLMOD,
+ OASLMUL,
+ OASLSHR,
+ OASMOD,
+ OASMUL,
+ OASOR,
+ OASSUB,
+ OASXOR,
+ OBIT,
+ OBREAK,
+ OCASE,
+ OCAST,
+ OCOMMA,
+ OCOND,
+ OCONST,
+ OCONTINUE,
+ ODIV,
+ ODOT,
+ ODOTDOT,
+ ODWHILE,
+ OENUM,
+ OEQ,
+ OFOR,
+ OFUNC,
+ OGE,
+ OGOTO,
+ OGT,
+ OHI,
+ OHS,
+ OIF,
+ OIND,
+ OINDREG,
+ OINIT,
+ OLABEL,
+ OLDIV,
+ OLE,
+ OLIST,
+ OLMOD,
+ OLMUL,
+ OLO,
+ OLS,
+ OLSHR,
+ OLT,
+ OMOD,
+ OMUL,
+ ONAME,
+ ONE,
+ ONOT,
+ OOR,
+ OOROR,
+ OPOSTDEC,
+ OPOSTINC,
+ OPREDEC,
+ OPREINC,
+ OPROTO,
+ OREGISTER,
+ ORETURN,
+ OSET,
+ OSIGN,
+ OSIZE,
+ OSTRING,
+ OLSTRING,
+ OSTRUCT,
+ OSUB,
+ OSWITCH,
+ OUNION,
+ OUSED,
+ OWHILE,
+ OXOR,
+ ONEG,
+ OCOM,
+ OPOS,
+ OELEM,
+
+ OTST, /* used in some compilers */
+ OINDEX,
+ OFAS,
+ OREGPAIR,
+
+ OEND
+};
+enum
+{
+ TXXX,
+ TCHAR,
+ TUCHAR,
+ TSHORT,
+ TUSHORT,
+ TINT,
+ TUINT,
+ TLONG,
+ TULONG,
+ TVLONG,
+ TUVLONG,
+ TFLOAT,
+ TDOUBLE,
+ TIND,
+ TFUNC,
+ TARRAY,
+ TVOID,
+ TSTRUCT,
+ TUNION,
+ TENUM,
+ NTYPE,
+
+ TAUTO = NTYPE,
+ TEXTERN,
+ TSTATIC,
+ TTYPEDEF,
+ TTYPESTR,
+ TREGISTER,
+ TCONSTNT,
+ TVOLATILE,
+ TUNSIGNED,
+ TSIGNED,
+ TDOT,
+ TFILE,
+ TOLD,
+ NALLTYPES,
+};
+enum
+{
+ CXXX,
+ CAUTO,
+ CEXTERN,
+ CGLOBL,
+ CSTATIC,
+ CLOCAL,
+ CTYPEDEF,
+ CTYPESTR,
+ CPARAM,
+ CSELEM,
+ CLABEL,
+ CEXREG,
+ NCTYPES,
+};
+enum
+{
+ GXXX = 0,
+ GCONSTNT = 1<<0,
+ GVOLATILE = 1<<1,
+ NGTYPES = 1<<2,
+
+ GINCOMPLETE = 1<<2,
+};
+enum
+{
+ BCHAR = 1L<<TCHAR,
+ BUCHAR = 1L<<TUCHAR,
+ BSHORT = 1L<<TSHORT,
+ BUSHORT = 1L<<TUSHORT,
+ BINT = 1L<<TINT,
+ BUINT = 1L<<TUINT,
+ BLONG = 1L<<TLONG,
+ BULONG = 1L<<TULONG,
+ BVLONG = 1L<<TVLONG,
+ BUVLONG = 1L<<TUVLONG,
+ BFLOAT = 1L<<TFLOAT,
+ BDOUBLE = 1L<<TDOUBLE,
+ BIND = 1L<<TIND,
+ BFUNC = 1L<<TFUNC,
+ BARRAY = 1L<<TARRAY,
+ BVOID = 1L<<TVOID,
+ BSTRUCT = 1L<<TSTRUCT,
+ BUNION = 1L<<TUNION,
+ BENUM = 1L<<TENUM,
+ BFILE = 1L<<TFILE,
+ BDOT = 1L<<TDOT,
+ BCONSTNT = 1L<<TCONSTNT,
+ BVOLATILE = 1L<<TVOLATILE,
+ BUNSIGNED = 1L<<TUNSIGNED,
+ BSIGNED = 1L<<TSIGNED,
+ BAUTO = 1L<<TAUTO,
+ BEXTERN = 1L<<TEXTERN,
+ BSTATIC = 1L<<TSTATIC,
+ BTYPEDEF = 1L<<TTYPEDEF,
+ BTYPESTR = 1L<<TTYPESTR,
+ BREGISTER = 1L<<TREGISTER,
+
+ BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
+ BLONG|BULONG|BVLONG|BUVLONG,
+ BNUMBER = BINTEGER|BFLOAT|BDOUBLE,
+
+/* these can be overloaded with complex types */
+
+ BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
+ BGARB = BCONSTNT|BVOLATILE,
+};
+
+struct Funct
+{
+ Sym* sym[OEND];
+ Sym* castto[NTYPE];
+ Sym* castfr[NTYPE];
+};
+
+EXTERN struct
+{
+ Type* tenum; /* type of entire enum */
+ Type* cenum; /* type of current enum run */
+ vlong lastenum; /* value of current enum */
+ double floatenum; /* value of current enum */
+} en;
+
+EXTERN int autobn;
+EXTERN long autoffset;
+EXTERN int blockno;
+EXTERN Decl* dclstack;
+EXTERN char debug[256];
+EXTERN Hist* ehist;
+EXTERN long firstbit;
+EXTERN Sym* firstarg;
+EXTERN Type* firstargtype;
+EXTERN Decl* firstdcl;
+EXTERN int fperror;
+EXTERN Sym* hash[NHASH];
+EXTERN char* hunk;
+EXTERN char* include[20];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lastbit;
+EXTERN char lastclass;
+EXTERN Type* lastdcl;
+EXTERN long lastfield;
+EXTERN Type* lasttype;
+EXTERN long lineno;
+EXTERN long nearln;
+EXTERN int nerrors;
+EXTERN int newflag;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN Node* nodproto;
+EXTERN Node* nodcast;
+EXTERN Biobuf outbuf;
+EXTERN Biobuf diagbuf;
+EXTERN char* outfile;
+EXTERN char* pathname;
+EXTERN int peekc;
+EXTERN long stkoff;
+EXTERN Type* strf;
+EXTERN Type* strl;
+EXTERN char symb[NSYMB];
+EXTERN Sym* symstring;
+EXTERN int taggen;
+EXTERN Type* tfield;
+EXTERN Type* tufield;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN Type* thisfn;
+EXTERN long thunk;
+EXTERN Type* types[NTYPE];
+EXTERN Type* fntypes[NTYPE];
+EXTERN Node* initlist;
+EXTERN Term term[NTERM];
+EXTERN int nterm;
+EXTERN int packflg;
+EXTERN int fproundflg;
+EXTERN int profileflg;
+EXTERN Bits zbits;
+
+extern char *onames[], *tnames[], *gnames[];
+extern char *cnames[], *qnames[], *bnames[];
+extern char tab[NTYPE][NTYPE];
+extern char comrel[], invrel[], logrel[];
+extern long ncast[], tadd[], tand[];
+extern long targ[], tasadd[], tasign[], tcast[];
+extern long tdot[], tfunct[], tindir[], tmul[];
+extern long tnot[], trel[], tsub[];
+
+extern char typeaf[];
+extern char typefd[];
+extern char typei[];
+extern char typesu[];
+extern char typesuv[];
+extern char typeu[];
+extern char typev[];
+extern char typec[];
+extern char typeh[];
+extern char typeil[];
+extern char typeilp[];
+extern char typechl[];
+extern char typechlv[];
+extern char typechlvp[];
+extern char typechlp[];
+extern char typechlpfd[];
+
+extern ulong thash1;
+extern ulong thash2;
+extern ulong thash3;
+extern ulong thash[];
+
+/*
+ * Inferno.c/Posix.c/Nt.c
+ */
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+int myaccess(char*);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
+
+/*
+ * parser
+ */
+int yyparse(void);
+int mpatof(char*, double*);
+int mpatov(char*, vlong*);
+
+/*
+ * lex.c
+ */
+void* allocn(void*, long, long);
+void* alloc(long);
+void cinit(void);
+int compile(char*, char**, int);
+void errorexit(void);
+int filbuf(void);
+int getc(void);
+long getr(void);
+int getnsc(void);
+Sym* lookup(void);
+void main(int, char*[]);
+void newfile(char*, int);
+void newio(void);
+void pushio(void);
+long escchar(long, int, int);
+Sym* slookup(char*);
+void syminit(Sym*);
+void unget(int);
+long yylex(void);
+int Lconv(Fmt*);
+int Tconv(Fmt*);
+int FNconv(Fmt*);
+int Oconv(Fmt*);
+int Qconv(Fmt*);
+int VBconv(Fmt*);
+void setinclude(char*);
+
+/*
+ * mac.c
+ */
+void dodefine(char*);
+void domacro(void);
+Sym* getsym(void);
+long getnsn(void);
+void linehist(char*, int);
+void macdef(void);
+void macprag(void);
+void macend(void);
+void macexpand(Sym*, char*);
+void macif(int);
+void macinc(void);
+void maclin(void);
+void macund(void);
+
+/*
+ * dcl.c
+ */
+Node* doinit(Sym*, Type*, long, Node*);
+Type* tcopy(Type*);
+Node* init1(Sym*, Type*, long, int);
+Node* newlist(Node*, Node*);
+void adecl(int, Type*, Sym*);
+int anyproto(Node*);
+void argmark(Node*, int);
+void dbgdecl(Sym*);
+Node* dcllabel(Sym*, int);
+Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
+Sym* mkstatic(Sym*);
+void doenum(Sym*, Node*);
+void snap(Type*);
+Type* dotag(Sym*, int, int);
+void edecl(int, Type*, Sym*);
+Type* fnproto(Node*);
+Type* fnproto1(Node*);
+void markdcl(void);
+Type* paramconv(Type*, int);
+void pdecl(int, Type*, Sym*);
+Decl* push(void);
+Decl* push1(Sym*);
+Node* revertdcl(void);
+#undef round
+#define round ccround
+#undef log2
+#define log2 cclog2
+long round(long, int);
+int rsametype(Type*, Type*, int, int);
+int sametype(Type*, Type*);
+ulong sign(Sym*);
+ulong signature(Type*);
+void suallign(Type*);
+void tmerge(Type*, Sym*);
+void walkparam(Node*, int);
+void xdecl(int, Type*, Sym*);
+Node* contig(Sym*, Node*, long);
+
+/*
+ * com.c
+ */
+void ccom(Node*);
+void complex(Node*);
+int tcom(Node*);
+int tcoma(Node*, Node*, Type*, int);
+int tcomd(Node*);
+int tcomo(Node*, int);
+int tcomx(Node*);
+int tlvalue(Node*);
+void constas(Node*, Type*, Type*);
+
+/*
+ * con.c
+ */
+void acom(Node*);
+void acom1(vlong, Node*);
+void acom2(Node*, Type*);
+int acomcmp1(const void*, const void*);
+int acomcmp2(const void*, const void*);
+int addo(Node*);
+void evconst(Node*);
+
+/*
+ * funct.c
+ */
+int isfunct(Node*);
+void dclfunct(Type*, Sym*);
+
+/*
+ * sub.c
+ */
+void arith(Node*, int);
+int deadheads(Node*);
+Type* dotsearch(Sym*, Type*, Node*, long*);
+long dotoffset(Type*, Type*, Node*);
+void gethunk(void);
+Node* invert(Node*);
+int bitno(long);
+void makedot(Node*, Type*, long);
+int mixedasop(Type*, Type*);
+Node* new(int, Node*, Node*);
+Node* new1(int, Node*, Node*);
+int nilcast(Type*, Type*);
+int nocast(Type*, Type*);
+void prtree(Node*, char*);
+void prtree1(Node*, int, int);
+void relcon(Node*, Node*);
+int relindex(int);
+int simpleg(long);
+Type* garbt(Type*, long);
+int simplec(long);
+Type* simplet(long);
+int stcompat(Node*, Type*, Type*, long[]);
+int tcompat(Node*, Type*, Type*, long[]);
+void tinit(void);
+Type* typ(int, Type*);
+Type* copytyp(Type*);
+void typeext(Type*, Node*);
+void typeext1(Type*, Node*);
+int side(Node*);
+int vconst(Node*);
+int log2(uvlong);
+int vlog(Node*);
+int topbit(ulong);
+void simplifyshift(Node*);
+long typebitor(long, long);
+void diag(Node*, char*, ...);
+void warn(Node*, char*, ...);
+void yyerror(char*, ...);
+void fatal(Node*, char*, ...);
+
+/*
+ * acid.c
+ */
+void acidtype(Type*);
+void acidvar(Sym*);
+
+/*
+ * pickle.c
+ */
+void pickletype(Type*);
+
+/*
+ * bits.c
+ */
+Bits bor(Bits, Bits);
+Bits band(Bits, Bits);
+Bits bnot(Bits);
+int bany(Bits*);
+int bnum(Bits);
+Bits blsh(uint);
+int beq(Bits, Bits);
+int bset(Bits, uint);
+
+/*
+ * dpchk.c
+ */
+void dpcheck(Node*);
+void arginit(void);
+void pragvararg(void);
+void pragpack(void);
+void pragfpround(void);
+void pragprofile(void);
+void pragincomplete(void);
+
+/*
+ * calls to machine depend part
+ */
+void codgen(Node*, Node*);
+void gclean(void);
+void gextern(Sym*, Node*, long, long);
+void ginit(void);
+long outstring(char*, long);
+long outlstring(ushort*, long);
+void sextern(Sym*, Node*, long, long);
+void xcom(Node*);
+long exreg(Type*);
+long align(long, Type*, int);
+long maxround(long, long);
+
+extern schar ewidth[];
+
+/*
+ * com64
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+double convvtof(vlong);
+vlong convftov(double);
+double convftox(double, int);
+vlong convvtox(vlong, int);
+
+/*
+ * machcap
+ */
+int machcap(Node*);
+
+#pragma varargck argpos warn 2
+#pragma varargck argpos diag 2
+#pragma varargck argpos yyerror 1
+
+#pragma varargck type "F" Node*
+#pragma varargck type "L" long
+#pragma varargck type "Q" long
+#pragma varargck type "O" int
+#pragma varargck type "T" Type*
+#pragma varargck type "|" int
diff --git a/utils/cc/cc.y b/utils/cc/cc.y
new file mode 100644
index 00000000..9ddb1976
--- /dev/null
+++ b/utils/cc/cc.y
@@ -0,0 +1,1167 @@
+%{
+#include "cc.h"
+%}
+%union {
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ char c;
+ } tycl;
+ struct
+ {
+ Type* t1;
+ Type* t2;
+ } tyty;
+ struct
+ {
+ char* s;
+ long l;
+ } sval;
+ long lval;
+ double dval;
+ vlong vval;
+}
+%type <sym> ltag
+%type <lval> gctname gcname cname gname tname
+%type <lval> gctnlist gcnlist zgnlist
+%type <type> tlist sbody complex
+%type <tycl> types
+%type <node> zarglist arglist zcexpr
+%type <node> name block stmnt cexpr expr xuexpr pexpr
+%type <node> zelist elist adecl slist uexpr string lstring
+%type <node> xdecor xdecor2 labels label ulstmnt
+%type <node> adlist edecor tag qual qlist
+%type <node> abdecor abdecor1 abdecor2 abdecor3
+%type <node> zexpr lexpr init ilist
+
+%left ';'
+%left ','
+%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
+%right '?' ':'
+%left LOROR
+%left LANDAND
+%left '|'
+%left '^'
+%left '&'
+%left LEQ LNE
+%left '<' '>' LLE LGE
+%left LLSH LRSH
+%left '+' '-'
+%left '*' '/' '%'
+%right LMM LPP LMG '.' '[' '('
+
+%token <sym> LNAME LTYPE
+%token <dval> LFCONST LDCONST
+%token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
+%token <sval> LSTRING LLSTRING
+%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
+%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
+%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED
+%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
+%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
+%%
+prog:
+| prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+ zctlist ';'
+ {
+ dodecl(xdecl, lastclass, lasttype, Z);
+ }
+| zctlist xdlist ';'
+| zctlist xdecor
+ {
+ lastdcl = T;
+ firstarg = S;
+ dodecl(xdecl, lastclass, lasttype, $2);
+ if(lastdcl == T || lastdcl->etype != TFUNC) {
+ diag($2, "not a function");
+ lastdcl = types[TFUNC];
+ }
+ thisfn = lastdcl;
+ markdcl();
+ firstdcl = dclstack;
+ argmark($2, 0);
+ }
+ pdecl
+ {
+ argmark($2, 1);
+ }
+ block
+ {
+ Node *n;
+
+ n = revertdcl();
+ if(n)
+ $6 = new(OLIST, n, $6);
+ if(!debug['a'] && !debug['Z'])
+ codgen($6, $2);
+ }
+
+xdlist:
+ xdecor
+ {
+ dodecl(xdecl, lastclass, lasttype, $1);
+ }
+| xdecor
+ {
+ $1 = dodecl(xdecl, lastclass, lasttype, $1);
+ }
+ '=' init
+ {
+ doinit($1->sym, $1->type, 0L, $4);
+ }
+| xdlist ',' xdlist
+
+xdecor:
+ xdecor2
+| '*' zgnlist xdecor
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+
+xdecor2:
+ tag
+| '(' xdecor ')'
+ {
+ $$ = $2;
+ }
+| xdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| xdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+/*
+ * automatic declarator
+ */
+adecl:
+ {
+ $$ = Z;
+ }
+| adecl ctlist ';'
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, Z);
+ if($1 != Z)
+ if($$ != Z)
+ $$ = new(OLIST, $1, $$);
+ else
+ $$ = $1;
+ }
+| adecl ctlist adlist ';'
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+adlist:
+ xdecor
+ {
+ dodecl(adecl, lastclass, lasttype, $1);
+ $$ = Z;
+ }
+| xdecor
+ {
+ $1 = dodecl(adecl, lastclass, lasttype, $1);
+ }
+ '=' init
+ {
+ long w;
+
+ w = $1->sym->type->width;
+ $$ = doinit($1->sym, $1->type, 0L, $4);
+ $$ = contig($1->sym, $$, w);
+ }
+| adlist ',' adlist
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+/*
+ * parameter declarator
+ */
+pdecl:
+| pdecl ctlist pdlist ';'
+
+pdlist:
+ xdecor
+ {
+ dodecl(pdecl, lastclass, lasttype, $1);
+ }
+| pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+ tlist
+ {
+ lasttype = $1;
+ }
+ zedlist ';'
+| edecl tlist
+ {
+ lasttype = $2;
+ }
+ zedlist ';'
+
+zedlist: /* extension */
+ {
+ lastfield = 0;
+ edecl(CXXX, lasttype, S);
+ }
+| edlist
+
+edlist:
+ edecor
+ {
+ dodecl(edecl, CXXX, lasttype, $1);
+ }
+| edlist ',' edlist
+
+edecor:
+ xdecor
+ {
+ lastbit = 0;
+ firstbit = 1;
+ }
+| tag ':' lexpr
+ {
+ $$ = new(OBIT, $1, $3);
+ }
+| ':' lexpr
+ {
+ $$ = new(OBIT, Z, $2);
+ }
+
+/*
+ * abstract declarator
+ */
+abdecor:
+ {
+ $$ = (Z);
+ }
+| abdecor1
+
+abdecor1:
+ '*' zgnlist
+ {
+ $$ = new(OIND, (Z), Z);
+ $$->garb = simpleg($2);
+ }
+| '*' zgnlist abdecor1
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+| abdecor2
+
+abdecor2:
+ abdecor3
+| abdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ }
+| abdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+abdecor3:
+ '(' ')'
+ {
+ $$ = new(OFUNC, (Z), Z);
+ }
+| '[' zexpr ']'
+ {
+ $$ = new(OARRAY, (Z), $2);
+ }
+| '(' abdecor1 ')'
+ {
+ $$ = $2;
+ }
+
+init:
+ expr
+| '{' ilist '}'
+ {
+ $$ = new(OINIT, invert($2), Z);
+ }
+
+qual:
+ '[' lexpr ']'
+ {
+ $$ = new(OARRAY, $2, Z);
+ }
+| '.' ltag
+ {
+ $$ = new(OELEM, Z, Z);
+ $$->sym = $2;
+ }
+| qual '='
+
+qlist:
+ init ','
+| qlist init ','
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+| qual
+| qlist qual
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ilist:
+ qlist
+| init
+| qlist init
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+zarglist:
+ {
+ $$ = Z;
+ }
+| arglist
+ {
+ $$ = invert($1);
+ }
+
+
+arglist:
+ name
+| tlist abdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| tlist xdecor
+ {
+ $$ = new(OPROTO, $2, Z);
+ $$->type = $1;
+ }
+| '.' '.' '.'
+ {
+ $$ = new(ODOTDOT, Z, Z);
+ }
+| arglist ',' arglist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+block:
+ '{' adecl slist '}'
+ {
+ $$ = invert($3);
+ if($2 != Z)
+ $$ = new(OLIST, $2, $$);
+ if($$ == Z)
+ $$ = new(OLIST, Z, Z);
+ }
+
+slist:
+ {
+ $$ = Z;
+ }
+| slist stmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+labels:
+ label
+| labels label
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+label:
+ LCASE expr ':'
+ {
+ $$ = new(OCASE, $2, Z);
+ }
+| LDEFAULT ':'
+ {
+ $$ = new(OCASE, Z, Z);
+ }
+| LNAME ':'
+ {
+ $$ = new(OLABEL, dcllabel($1, 1), Z);
+ }
+
+stmnt:
+ error ';'
+ {
+ $$ = Z;
+ }
+| ulstmnt
+| labels ulstmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ulstmnt:
+ zcexpr ';'
+| {
+ markdcl();
+ }
+ block
+ {
+ $$ = revertdcl();
+ if($$)
+ $$ = new(OLIST, $$, $2);
+ else
+ $$ = $2;
+ }
+| LIF '(' cexpr ')' stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, Z));
+ if($5 == Z)
+ warn($3, "empty if body");
+ }
+| LIF '(' cexpr ')' stmnt LELSE stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, $7));
+ if($5 == Z)
+ warn($3, "empty if body");
+ if($7 == Z)
+ warn($3, "empty else body");
+ }
+| LFOR '(' zcexpr ';' zcexpr ';' zcexpr ')' stmnt
+ {
+ $$ = new(OFOR, new(OLIST, $5, new(OLIST, $3, $7)), $9);
+ }
+| LWHILE '(' cexpr ')' stmnt
+ {
+ $$ = new(OWHILE, $3, $5);
+ }
+| LDO stmnt LWHILE '(' cexpr ')' ';'
+ {
+ $$ = new(ODWHILE, $5, $2);
+ }
+| LRETURN zcexpr ';'
+ {
+ $$ = new(ORETURN, $2, Z);
+ $$->type = thisfn->link;
+ }
+| LSWITCH '(' cexpr ')' stmnt
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->vconst = 0;
+ $$->type = types[TINT];
+ $3 = new(OSUB, $$, $3);
+
+ $$ = new(OCONST, Z, Z);
+ $$->vconst = 0;
+ $$->type = types[TINT];
+ $3 = new(OSUB, $$, $3);
+
+ $$ = new(OSWITCH, $3, $5);
+ }
+| LBREAK ';'
+ {
+ $$ = new(OBREAK, Z, Z);
+ }
+| LCONTINUE ';'
+ {
+ $$ = new(OCONTINUE, Z, Z);
+ }
+| LGOTO ltag ';'
+ {
+ $$ = new(OGOTO, dcllabel($2, 0), Z);
+ }
+| LUSED '(' zelist ')' ';'
+ {
+ $$ = new(OUSED, $3, Z);
+ }
+| LSET '(' zelist ')' ';'
+ {
+ $$ = new(OSET, $3, Z);
+ }
+
+zcexpr:
+ {
+ $$ = Z;
+ }
+| cexpr
+
+zexpr:
+ {
+ $$ = Z;
+ }
+| lexpr
+
+lexpr:
+ expr
+ {
+ $$ = new(OCAST, $1, Z);
+ $$->type = types[TLONG];
+ }
+
+cexpr:
+ expr
+| cexpr ',' cexpr
+ {
+ $$ = new(OCOMMA, $1, $3);
+ }
+
+expr:
+ xuexpr
+| expr '*' expr
+ {
+ $$ = new(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = new(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = new(OMOD, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = new(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = new(OSUB, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = new(OASHR, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = new(OASHL, $1, $3);
+ }
+| expr '<' expr
+ {
+ $$ = new(OLT, $1, $3);
+ }
+| expr '>' expr
+ {
+ $$ = new(OGT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = new(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = new(OGE, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = new(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = new(ONE, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = new(OAND, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = new(OXOR, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = new(OOR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = new(OANDAND, $1, $3);
+ }
+| expr LOROR expr
+ {
+ $$ = new(OOROR, $1, $3);
+ }
+| expr '?' cexpr ':' expr
+ {
+ $$ = new(OCOND, $1, new(OLIST, $3, $5));
+ }
+| expr '=' expr
+ {
+ $$ = new(OAS, $1, $3);
+ }
+| expr LPE expr
+ {
+ $$ = new(OASADD, $1, $3);
+ }
+| expr LME expr
+ {
+ $$ = new(OASSUB, $1, $3);
+ }
+| expr LMLE expr
+ {
+ $$ = new(OASMUL, $1, $3);
+ }
+| expr LDVE expr
+ {
+ $$ = new(OASDIV, $1, $3);
+ }
+| expr LMDE expr
+ {
+ $$ = new(OASMOD, $1, $3);
+ }
+| expr LLSHE expr
+ {
+ $$ = new(OASASHL, $1, $3);
+ }
+| expr LRSHE expr
+ {
+ $$ = new(OASASHR, $1, $3);
+ }
+| expr LANDE expr
+ {
+ $$ = new(OASAND, $1, $3);
+ }
+| expr LXORE expr
+ {
+ $$ = new(OASXOR, $1, $3);
+ }
+| expr LORE expr
+ {
+ $$ = new(OASOR, $1, $3);
+ }
+
+xuexpr:
+ uexpr
+| '(' tlist abdecor ')' xuexpr
+ {
+ $$ = new(OCAST, $5, Z);
+ dodecl(NODECL, CXXX, $2, $3);
+ $$->type = lastdcl;
+ $$->xcast = 1;
+ }
+| '(' tlist abdecor ')' '{' ilist '}' /* extension */
+ {
+ $$ = new(OSTRUCT, $6, Z);
+ dodecl(NODECL, CXXX, $2, $3);
+ $$->type = lastdcl;
+ }
+
+uexpr:
+ pexpr
+| '*' xuexpr
+ {
+ $$ = new(OIND, $2, Z);
+ }
+| '&' xuexpr
+ {
+ $$ = new(OADDR, $2, Z);
+ }
+| '+' xuexpr
+ {
+ $$ = new(OPOS, $2, Z);
+ }
+| '-' xuexpr
+ {
+ $$ = new(ONEG, $2, Z);
+ }
+| '!' xuexpr
+ {
+ $$ = new(ONOT, $2, Z);
+ }
+| '~' xuexpr
+ {
+ $$ = new(OCOM, $2, Z);
+ }
+| LPP xuexpr
+ {
+ $$ = new(OPREINC, $2, Z);
+ }
+| LMM xuexpr
+ {
+ $$ = new(OPREDEC, $2, Z);
+ }
+| LSIZEOF uexpr
+ {
+ $$ = new(OSIZE, $2, Z);
+ }
+| LSIGNOF uexpr
+ {
+ $$ = new(OSIGN, $2, Z);
+ }
+
+pexpr:
+ '(' cexpr ')'
+ {
+ $$ = $2;
+ }
+| LSIZEOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIZE, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4);
+ $$->type = lastdcl;
+ }
+| LSIGNOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIGN, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4);
+ $$->type = lastdcl;
+ }
+| pexpr '(' zelist ')'
+ {
+ $$ = new(OFUNC, $1, Z);
+ if($1->op == ONAME)
+ if($1->type == T)
+ dodecl(xdecl, CXXX, types[TINT], $$);
+ $$->right = invert($3);
+ }
+| pexpr '[' cexpr ']'
+ {
+ $$ = new(OIND, new(OADD, $1, $3), Z);
+ }
+| pexpr LMG ltag
+ {
+ $$ = new(ODOT, new(OIND, $1, Z), Z);
+ $$->sym = $3;
+ }
+| pexpr '.' ltag
+ {
+ $$ = new(ODOT, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr LPP
+ {
+ $$ = new(OPOSTINC, $1, Z);
+ }
+| pexpr LMM
+ {
+ $$ = new(OPOSTDEC, $1, Z);
+ }
+| name
+| LCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LUCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUINT];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LULCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TULONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LDCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TDOUBLE];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LFCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TFLOAT];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TVLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| LUVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUVLONG];
+ $$->vconst = $1;
+ $$->cstring = strdup(symb);
+ }
+| string
+| lstring
+
+string:
+ LSTRING
+ {
+ $$ = new(OSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TCHAR]);
+ $$->type->width = $1.l + 1;
+ $$->cstring = $1.s;
+ $$->sym = symstring;
+ $$->etype = TARRAY;
+ $$->class = CSTATIC;
+ }
+| string LSTRING
+ {
+ char *s;
+ int n;
+
+ n = $1->type->width - 1;
+ s = alloc(n+$2.l+MAXALIGN);
+
+ memcpy(s, $1->cstring, n);
+ memcpy(s+n, $2.s, $2.l);
+ s[n+$2.l] = 0;
+
+ $$ = $1;
+ $$->type->width += $2.l;
+ $$->cstring = s;
+ }
+
+lstring:
+ LLSTRING
+ {
+ $$ = new(OLSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TUSHORT]);
+ $$->type->width = $1.l + sizeof(ushort);
+ $$->rstring = (ushort*)$1.s;
+ $$->sym = symstring;
+ $$->etype = TARRAY;
+ $$->class = CSTATIC;
+ }
+| lstring LLSTRING
+ {
+ char *s;
+ int n;
+
+ n = $1->type->width - sizeof(ushort);
+ s = alloc(n+$2.l+MAXALIGN);
+
+ memcpy(s, $1->rstring, n);
+ memcpy(s+n, $2.s, $2.l);
+ *(ushort*)(s+n+$2.l) = 0;
+
+ $$ = $1;
+ $$->type->width += $2.l;
+ $$->rstring = (ushort*)s;
+ }
+
+zelist:
+ {
+ $$ = Z;
+ }
+| elist
+
+elist:
+ expr
+| elist ',' elist
+ {
+ $$ = new(OLIST, $1, $3);
+ }
+
+sbody:
+ '{'
+ {
+ $<tyty>$.t1 = strf;
+ $<tyty>$.t2 = strl;
+ strf = T;
+ strl = T;
+ lastbit = 0;
+ firstbit = 1;
+ }
+ edecl '}'
+ {
+ $$ = strf;
+ strf = $<tyty>2.t1;
+ strl = $<tyty>2.t2;
+ }
+
+zctlist:
+ {
+ lastclass = CXXX;
+ lasttype = types[TINT];
+ }
+| ctlist
+
+types:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| tname
+ {
+ $$.t = simplet($1);
+ $$.c = CXXX;
+ }
+| gcnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| complex gctnlist
+ {
+ $$.t = $1;
+ $$.c = simplec($2);
+ $$.t = garbt($$.t, $2);
+ if($2 & ~BCLASS & ~BGARB)
+ diag(Z, "duplicate types given: %T and %Q", $1, $2);
+ }
+| tname gctnlist
+ {
+ $$.t = simplet(typebitor($1, $2));
+ $$.c = simplec($2);
+ $$.t = garbt($$.t, $2);
+ }
+| gcnlist complex zgnlist
+ {
+ $$.t = $2;
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1|$3);
+ }
+| gcnlist tname
+ {
+ $$.t = simplet($2);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| gcnlist tname gctnlist
+ {
+ $$.t = simplet(typebitor($2, $3));
+ $$.c = simplec($1|$3);
+ $$.t = garbt($$.t, $1|$3);
+ }
+
+tlist:
+ types
+ {
+ $$ = $1.t;
+ if($1.c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
+ }
+
+ctlist:
+ types
+ {
+ lasttype = $1.t;
+ lastclass = $1.c;
+ }
+
+complex:
+ LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, 0);
+ $$ = $2->suetag;
+ }
+| LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, autobn);
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ suallign($$);
+ }
+| LSTRUCT sbody
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ $$ = dotag(lookup(), TSTRUCT, autobn);
+ $$->link = $2;
+ suallign($$);
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, 0);
+ $$ = $2->suetag;
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, autobn);
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ suallign($$);
+ }
+| LUNION sbody
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ $$ = dotag(lookup(), TUNION, autobn);
+ $$->link = $2;
+ suallign($$);
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, 0);
+ $$ = $2->suetag;
+ if($$->link == T)
+ $$->link = types[TINT];
+ $$ = $$->link;
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, autobn);
+ }
+ '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ if(en.tenum == T) {
+ diag(Z, "enum type ambiguous: %s", $2->name);
+ en.tenum = types[TINT];
+ }
+ $$->link = en.tenum;
+ $$ = en.tenum;
+ }
+| LENUM '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = en.tenum;
+ }
+| LTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+
+gctnlist:
+ gctname
+| gctnlist gctname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+zgnlist:
+ {
+ $$ = 0;
+ }
+| zgnlist gname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctname:
+ tname
+| gname
+| cname
+
+gcnlist:
+ gcname
+| gcnlist gcname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gcname:
+ gname
+| cname
+
+enum:
+ LNAME
+ {
+ doenum($1, Z);
+ }
+| LNAME '=' expr
+ {
+ doenum($1, $3);
+ }
+| enum ','
+| enum ',' enum
+
+tname: /* type words */
+ LCHAR { $$ = BCHAR; }
+| LSHORT { $$ = BSHORT; }
+| LINT { $$ = BINT; }
+| LLONG { $$ = BLONG; }
+| LSIGNED { $$ = BSIGNED; }
+| LUNSIGNED { $$ = BUNSIGNED; }
+| LFLOAT { $$ = BFLOAT; }
+| LDOUBLE { $$ = BDOUBLE; }
+| LVOID { $$ = BVOID; }
+
+cname: /* class words */
+ LAUTO { $$ = BAUTO; }
+| LSTATIC { $$ = BSTATIC; }
+| LEXTERN { $$ = BEXTERN; }
+| LTYPEDEF { $$ = BTYPEDEF; }
+| LTYPESTR { $$ = BTYPESTR; }
+| LREGISTER { $$ = BREGISTER; }
+
+gname: /* garbage words */
+ LCONSTNT { $$ = BCONSTNT; }
+| LVOLATILE { $$ = BVOLATILE; }
+
+name:
+ LNAME
+ {
+ $$ = new(ONAME, Z, Z);
+ if($1->class == CLOCAL)
+ $1 = mkstatic($1);
+ $$->sym = $1;
+ $$->type = $1->type;
+ $$->etype = TVOID;
+ if($$->type != T)
+ $$->etype = $$->type->etype;
+ $$->xoffset = $1->offset;
+ $$->class = $1->class;
+ $1->aused = 1;
+ }
+tag:
+ ltag
+ {
+ $$ = new(ONAME, Z, Z);
+ $$->sym = $1;
+ $$->type = $1->type;
+ $$->etype = TVOID;
+ if($$->type != T)
+ $$->etype = $$->type->etype;
+ $$->xoffset = $1->offset;
+ $$->class = $1->class;
+ }
+ltag:
+ LNAME
+| LTYPE
+%%
diff --git a/utils/cc/com.c b/utils/cc/com.c
new file mode 100644
index 00000000..af16e8d9
--- /dev/null
+++ b/utils/cc/com.c
@@ -0,0 +1,1164 @@
+#include "cc.h"
+
+void
+complex(Node *n)
+{
+
+ if(n == Z)
+ return;
+
+ nearln = n->lineno;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "pre complex");
+ if(tcom(n))
+ return;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "t complex");
+ ccom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "c complex");
+ acom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "a complex");
+ xcom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "x complex");
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+ ADDROF = 1<<0,
+ CASTOF = 1<<1,
+ ADDROP = 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+ return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+ Node *l, *r;
+ Type *t;
+ int o;
+
+ if(n == Z) {
+ diag(Z, "Z in tcom");
+ errorexit();
+ }
+ n->addable = 0;
+ l = n->left;
+ r = n->right;
+
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in type complex: %O", n->op);
+ goto bad;
+
+ case ODOTDOT:
+ /*
+ * tcom has already been called on this subtree
+ */
+ *n = *n->left;
+ if(n->type == T)
+ goto bad;
+ break;
+
+ case OCAST:
+ if(n->type == T)
+ break;
+ if(n->type->width == types[TLONG]->width) {
+ if(tcomo(l, ADDROF|CASTOF))
+ goto bad;
+ } else
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, n->type, tcast))
+ goto bad;
+ break;
+
+ case ORETURN:
+ if(l == Z) {
+ if(n->type->etype != TVOID)
+ warn(n, "null return of a typed function");
+ break;
+ }
+ if(tcom(l))
+ goto bad;
+ typeext(n->type, l);
+ if(tcompat(n, n->type, l->type, tasign))
+ break;
+ constas(n, n->type, l->type);
+ if(!sametype(n->type, l->type)) {
+ l = new1(OCAST, l, Z);
+ l->type = n->type;
+ n->left = l;
+ }
+ break;
+
+ case OASI: /* same as as, but no test for const */
+ n->op = OAS;
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+
+ typeext(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OAS:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ if(tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ constas(n, l->type, r->type);
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OASADD:
+ case OASSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tasadd))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASDIV)
+ n->op = OASLDIV;
+ if(n->op == OASMUL)
+ n->op = OASLMUL;
+ }
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->type = l->type;
+ if(typeu[n->type->etype]) {
+ if(n->op == OASASHR)
+ n->op = OASLSHR;
+ }
+ break;
+
+ case OASMOD:
+ case OASLMOD:
+ case OASOR:
+ case OASAND:
+ case OASXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASMOD)
+ n->op = OASLMOD;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(tcom(l))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, types[TINT], tadd))
+ goto bad;
+ n->type = l->type;
+ if(n->type->etype == TIND)
+ if(n->type->link->width < 1)
+ diag(n, "inc/dec of a void pointer");
+ break;
+
+ case OEQ:
+ case ONE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ typeext(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ n->type = types[TINT];
+ break;
+
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ typeext1(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ if(typeu[n->type->etype])
+ n->op = logrel[relindex(n->op)];
+ n->type = types[TINT];
+ break;
+
+ case OCOND:
+ o = tcom(l);
+ o |= tcom(r->left);
+ if(o | tcom(r->right))
+ goto bad;
+ if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+ r->left->type = r->right->type;
+ r->left->vconst = 0;
+ }
+ if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+ r->right->type = r->left->type;
+ r->right->vconst = 0;
+ }
+ if(sametype(r->right->type, r->left->type)) {
+ r->type = r->right->type;
+ n->type = r->type;
+ break;
+ }
+ if(tcompat(r, r->left->type, r->right->type, trel))
+ goto bad;
+ arith(r, 0);
+ n->type = r->type;
+ break;
+
+ case OADD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tadd))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype]) {
+ if(n->op == ODIV)
+ n->op = OLDIV;
+ if(n->op == OMUL)
+ n->op = OLMUL;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->right = Z;
+ arith(n, 1);
+ n->right = new1(OCAST, r, Z);
+ n->right->type = types[TINT];
+ if(typeu[n->type->etype])
+ if(n->op == OASHR)
+ n->op = OLSHR;
+ break;
+
+ case OAND:
+ case OOR:
+ case OXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMOD:
+ case OLMOD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype])
+ n->op = OLMOD;
+ break;
+
+ case OPOS:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OADD;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case ONEG:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OSUB;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case OCOM:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = -1;
+ l->type = types[TINT];
+ n->op = OXOR;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case ONOT:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, T, l->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OANDAND:
+ case OOROR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot) |
+ tcompat(n, T, r->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OCOMMA:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ n->type = r->type;
+ break;
+
+
+ case OSIGN: /* extension signof(type) returns a hash */
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "signof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width < 0) {
+ diag(n, "signof undefined type");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(signature(n->type), TULONG);
+ n->type = types[TULONG];
+ break;
+
+ case OSIZE:
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "sizeof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width <= 0) {
+ diag(n, "sizeof undefined type");
+ goto bad;
+ }
+ if(n->type->etype == TFUNC) {
+ diag(n, "sizeof function");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(n->type->width, TINT);
+ n->type = types[TINT];
+ break;
+
+ case OFUNC:
+ o = tcomo(l, 0);
+ if(o)
+ goto bad;
+ if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+ l = new1(OIND, l, Z);
+ l->type = l->left->type->link;
+ n->left = l;
+ }
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(o | tcoma(l, r, l->type->down, 1))
+ goto bad;
+ n->type = l->type->link;
+ if(!debug['B'])
+ if(l->type->down == T || l->type->down->etype == TOLD) {
+ nerrors--;
+ diag(n, "function args not checked: %F", l);
+ }
+ dpcheck(n);
+ break;
+
+ case ONAME:
+ if(n->type == T) {
+ diag(n, "name not declared: %F", n);
+ goto bad;
+ }
+ if(n->type->etype == TENUM) {
+ n->op = OCONST;
+ n->type = n->sym->tenum;
+ if(!typefd[n->type->etype])
+ n->vconst = n->sym->vconst;
+ else
+ n->fconst = n->sym->fconst;
+ break;
+ }
+ n->addable = 1;
+ if(n->class == CEXREG) {
+ n->op = OREGISTER;
+ n->reg = n->sym->offset;
+ n->xoffset = 0;
+ break;
+ }
+ break;
+
+ case OLSTRING:
+ if(n->type->link != types[TUSHORT]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ outlstring(L"", sizeof(ushort));
+ o = outlstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outlstring(n->rstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OSTRING:
+ if(n->type->link != types[TCHAR]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ outstring("", 1);
+ o = outstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outstring(n->cstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OCONST:
+ break;
+
+ case ODOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tdot))
+ goto bad;
+ if(tcomd(n))
+ goto bad;
+ break;
+
+ case OADDR:
+ if(tcomo(l, ADDROP))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(l->type->nbits) {
+ diag(n, "address of a bit field");
+ goto bad;
+ }
+ if(l->op == OREGISTER) {
+ diag(n, "address of a register");
+ goto bad;
+ }
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ break;
+
+ case OIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ n->addable = 1;
+ break;
+
+ case OSTRUCT:
+ if(tcomx(n))
+ goto bad;
+ break;
+ }
+ t = n->type;
+ if(t == T)
+ goto bad;
+ if(t->width < 0) {
+ snap(t);
+ if(t->width < 0) {
+ if(typesu[t->etype] && t->tag)
+ diag(n, "structure not fully declared %s", t->tag->name);
+ else
+ diag(n, "structure not fully declared");
+ goto bad;
+ }
+ }
+ if(typeaf[t->etype]) {
+ if(f & ADDROF)
+ goto addaddr;
+ if(f & ADDROP)
+ warn(n, "address of array/func ignored");
+ }
+ return 0;
+
+addaddr:
+ if(tlvalue(n))
+ goto bad;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OADDR;
+ if(l->type->etype == TARRAY)
+ l->type = l->type->link;
+ n->left = l;
+ n->right = Z;
+ n->addable = 0;
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ return 0;
+
+bad:
+ n->type = T;
+ return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+ Node *n1;
+ int o;
+
+ if(t != T)
+ if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */
+ t = T;
+ if(n == Z) {
+ if(t != T && !sametype(t, types[TVOID])) {
+ diag(n, "not enough function arguments: %F", l);
+ return 1;
+ }
+ return 0;
+ }
+ if(n->op == OLIST) {
+ o = tcoma(l, n->left, t, 0);
+ if(t != T) {
+ t = t->down;
+ if(t == T)
+ t = types[TVOID];
+ }
+ return o | tcoma(l, n->right, t, 1);
+ }
+ if(f && t != T)
+ tcoma(l, Z, t->down, 0);
+ if(tcom(n) || tcompat(n, T, n->type, targ))
+ return 1;
+ if(sametype(t, types[TVOID])) {
+ diag(n, "too many function arguments: %F", l);
+ return 1;
+ }
+ if(t != T) {
+ typeext(t, n);
+ if(stcompat(nodproto, t, n->type, tasign)) {
+ diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+ n->type, t, l);
+ return 1;
+ }
+ switch(t->etype) {
+ case TCHAR:
+ case TSHORT:
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ t = types[TUINT];
+ break;
+ }
+ } else
+ switch(n->type->etype)
+ {
+ case TCHAR:
+ case TSHORT:
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ t = types[TUINT];
+ break;
+
+ case TFLOAT:
+ t = types[TDOUBLE];
+ }
+ if(t != T && !sametype(t, n->type)) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = 0;
+ }
+ return 0;
+}
+
+int
+tcomd(Node *n)
+{
+ Type *t;
+ long o;
+
+ o = 0;
+ t = dotsearch(n->sym, n->left->type->link, n, &o);
+ if(t == T) {
+ diag(n, "not a member of struct/union: %F", n);
+ return 1;
+ }
+ makedot(n, t, o);
+ return 0;
+}
+
+int
+tcomx(Node *n)
+{
+ Type *t;
+ Node *l, *r, **ar, **al;
+ int e;
+
+ e = 0;
+ if(n->type->etype != TSTRUCT) {
+ diag(n, "constructor must be a structure");
+ return 1;
+ }
+ l = invert(n->left);
+ n->left = l;
+ al = &n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ if(l == Z) {
+ diag(n, "constructor list too short");
+ return 1;
+ }
+ if(l->op == OLIST) {
+ r = l->left;
+ ar = &l->left;
+ al = &l->right;
+ l = l->right;
+ } else {
+ r = l;
+ ar = al;
+ l = Z;
+ }
+ if(tcom(r))
+ e++;
+ typeext(t, r);
+ if(tcompat(n, t, r->type, tasign))
+ e++;
+ constas(n, t, r->type);
+ if(!e && !sametype(t, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = t;
+ *ar = r;
+ }
+ }
+ if(l != Z) {
+ diag(n, "constructor list too long");
+ return 1;
+ }
+ return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+ if(!n->addable) {
+ diag(n, "not an l-value");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * general rewrite
+ * (IND(ADDR x)) ==> x
+ * (ADDR(IND x)) ==> x
+ * remove some zero operands
+ * remove no op casts
+ * evaluate constants
+ */
+void
+ccom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+loop:
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ case OAS:
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ case OASMOD:
+ case OASLMOD:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMUL:
+ case OASLMUL:
+ case OASSUB:
+ case OASADD:
+ ccom(l);
+ ccom(r);
+ if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst < 0)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ break;
+
+ case OCAST:
+ ccom(l);
+ if(l->op == OCONST) {
+ evconst(n);
+ if(n->op == OCONST)
+ break;
+ }
+ if(nocast(l->type, n->type)) {
+ l->type = n->type;
+ *n = *l;
+ }
+ break;
+
+ case OCOND:
+ ccom(l);
+ ccom(r);
+ if(l->op == OCONST)
+ if(vconst(l) == 0)
+ *n = *r->right;
+ else
+ *n = *r->left;
+ break;
+
+ case OREGISTER:
+ case OINDREG:
+ case OCONST:
+ case ONAME:
+ break;
+
+ case OADDR:
+ ccom(l);
+ l->etype = TVOID;
+ if(l->op == OIND) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OIND:
+ ccom(l);
+ if(l->op == OADDR) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OEQ:
+ case ONE:
+
+ case OLE:
+ case OGE:
+ case OLT:
+ case OGT:
+
+ case OLS:
+ case OHS:
+ case OLO:
+ case OHI:
+ ccom(l);
+ ccom(r);
+ relcon(l, r);
+ relcon(r, l);
+ goto common;
+
+ case OASHR:
+ case OASHL:
+ case OLSHR:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst <= -t)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ goto common;
+
+ case OMUL:
+ case OLMUL:
+ ccom(l);
+ t = vconst(l);
+ if(t == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(t == 1) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case ODIV:
+ case OLDIV:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0) {
+ diag(n, "divide check");
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case OSUB:
+ ccom(r);
+ if(r->op == OCONST) {
+ if(typefd[r->type->etype]) {
+ n->op = OADD;
+ r->fconst = -r->fconst;
+ goto loop;
+ } else {
+ n->op = OADD;
+ r->vconst = -r->vconst;
+ goto loop;
+ }
+ }
+ ccom(l);
+ goto common;
+
+ case OXOR:
+ case OOR:
+ case OADD:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ goto commun;
+
+ case OAND:
+ ccom(l);
+ ccom(r);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(vconst(r) == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+
+ commun:
+ /* look for commutative constant */
+ if(r->op == OCONST) {
+ if(l->op == n->op) {
+ if(l->left->op == OCONST) {
+ n->right = l->right;
+ l->right = r;
+ goto loop;
+ }
+ if(l->right->op == OCONST) {
+ n->right = l->left;
+ l->left = r;
+ goto loop;
+ }
+ }
+ }
+ if(l->op == OCONST) {
+ if(r->op == n->op) {
+ if(r->left->op == OCONST) {
+ n->left = r->right;
+ r->right = l;
+ goto loop;
+ }
+ if(r->right->op == OCONST) {
+ n->left = r->left;
+ r->left = l;
+ goto loop;
+ }
+ }
+ }
+ goto common;
+
+ case OANDAND:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ case OOROR:
+ ccom(l);
+ if(l->op == OCONST && l->vconst != 0) {
+ *n = *l;
+ n->vconst = 1;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ default:
+ if(l != Z)
+ ccom(l);
+ if(r != Z)
+ ccom(r);
+ common:
+ if(l != Z)
+ if(l->op != OCONST)
+ break;
+ if(r != Z)
+ if(r->op != OCONST)
+ break;
+ evconst(n);
+ }
+}
diff --git a/utils/cc/com64.c b/utils/cc/com64.c
new file mode 100644
index 00000000..88bf11bf
--- /dev/null
+++ b/utils/cc/com64.c
@@ -0,0 +1,611 @@
+#include "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+#define FNX 100 /* botch -- redefinition */
+
+Node* nodaddv;
+Node* nodsubv;
+Node* nodmulv;
+Node* noddivv;
+Node* noddivvu;
+Node* nodmodv;
+Node* nodmodvu;
+Node* nodlshv;
+Node* nodrshav;
+Node* nodrshlv;
+Node* nodandv;
+Node* nodorv;
+Node* nodxorv;
+Node* nodnegv;
+Node* nodcomv;
+
+Node* nodtestv;
+Node* nodeqv;
+Node* nodnev;
+Node* nodlev;
+Node* nodltv;
+Node* nodgev;
+Node* nodgtv;
+Node* nodhiv;
+Node* nodhsv;
+Node* nodlov;
+Node* nodlsv;
+
+Node* nodf2v;
+Node* nodd2v;
+Node* nodp2v;
+Node* nodsi2v;
+Node* nodui2v;
+Node* nodsl2v;
+Node* nodul2v;
+Node* nodsh2v;
+Node* noduh2v;
+Node* nodsc2v;
+Node* noduc2v;
+
+Node* nodv2f;
+Node* nodv2d;
+Node* nodv2ui;
+Node* nodv2si;
+Node* nodv2ul;
+Node* nodv2sl;
+Node* nodv2uh;
+Node* nodv2sh;
+Node* nodv2uc;
+Node* nodv2sc;
+
+Node* nodvpp;
+Node* nodppv;
+Node* nodvmm;
+Node* nodmmv;
+
+Node* nodvasop;
+
+char etconv[NTYPE]; /* for _vasop */
+Init initetconv[] =
+{
+ TCHAR, 1, 0,
+ TUCHAR, 2, 0,
+ TSHORT, 3, 0,
+ TUSHORT, 4, 0,
+ TLONG, 5, 0,
+ TULONG, 6, 0,
+ TVLONG, 7, 0,
+ TUVLONG, 8, 0,
+ TINT, 9, 0,
+ TUINT, 10, 0,
+ -1, 0, 0,
+};
+
+Node*
+fvn(char *name, int type)
+{
+ Node *n;
+
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(name);
+ n->sym->sig = SIGINTERN;
+ if(fntypes[type] == 0)
+ fntypes[type] = typ(TFUNC, types[type]);
+ n->type = fntypes[type];
+ n->etype = type;
+ n->class = CGLOBL;
+ n->addable = 10;
+ n->complex = 0;
+ return n;
+}
+
+void
+com64init(void)
+{
+ Init *p;
+
+ nodaddv = fvn("_addv", TVLONG);
+ nodsubv = fvn("_subv", TVLONG);
+ nodmulv = fvn("_mulv", TVLONG);
+ noddivv = fvn("_divv", TVLONG);
+ noddivvu = fvn("_divvu", TVLONG);
+ nodmodv = fvn("_modv", TVLONG);
+ nodmodvu = fvn("_modvu", TVLONG);
+ nodlshv = fvn("_lshv", TVLONG);
+ nodrshav = fvn("_rshav", TVLONG);
+ nodrshlv = fvn("_rshlv", TVLONG);
+ nodandv = fvn("_andv", TVLONG);
+ nodorv = fvn("_orv", TVLONG);
+ nodxorv = fvn("_xorv", TVLONG);
+ nodnegv = fvn("_negv", TVLONG);
+ nodcomv = fvn("_comv", TVLONG);
+
+ nodtestv = fvn("_testv", TLONG);
+ nodeqv = fvn("_eqv", TLONG);
+ nodnev = fvn("_nev", TLONG);
+ nodlev = fvn("_lev", TLONG);
+ nodltv = fvn("_ltv", TLONG);
+ nodgev = fvn("_gev", TLONG);
+ nodgtv = fvn("_gtv", TLONG);
+ nodhiv = fvn("_hiv", TLONG);
+ nodhsv = fvn("_hsv", TLONG);
+ nodlov = fvn("_lov", TLONG);
+ nodlsv = fvn("_lsv", TLONG);
+
+ nodf2v = fvn("_f2v", TVLONG);
+ nodd2v = fvn("_d2v", TVLONG);
+ nodp2v = fvn("_p2v", TVLONG);
+ nodsi2v = fvn("_si2v", TVLONG);
+ nodui2v = fvn("_ui2v", TVLONG);
+ nodsl2v = fvn("_sl2v", TVLONG);
+ nodul2v = fvn("_ul2v", TVLONG);
+ nodsh2v = fvn("_sh2v", TVLONG);
+ noduh2v = fvn("_uh2v", TVLONG);
+ nodsc2v = fvn("_sc2v", TVLONG);
+ noduc2v = fvn("_uc2v", TVLONG);
+
+ nodv2f = fvn("_v2f", TFLOAT);
+ nodv2d = fvn("_v2d", TDOUBLE);
+ nodv2sl = fvn("_v2sl", TLONG);
+ nodv2ul = fvn("_v2ul", TULONG);
+ nodv2si = fvn("_v2si", TINT);
+ nodv2ui = fvn("_v2ui", TUINT);
+ nodv2sh = fvn("_v2sh", TSHORT);
+ nodv2uh = fvn("_v2ul", TUSHORT);
+ nodv2sc = fvn("_v2sc", TCHAR);
+ nodv2uc = fvn("_v2uc", TUCHAR);
+
+ nodvpp = fvn("_vpp", TVLONG);
+ nodppv = fvn("_ppv", TVLONG);
+ nodvmm = fvn("_vmm", TVLONG);
+ nodmmv = fvn("_mmv", TVLONG);
+
+ nodvasop = fvn("_vasop", TVLONG);
+
+ for(p = initetconv; p->code >= 0; p++)
+ etconv[p->code] = p->value;
+}
+
+int
+com64(Node *n)
+{
+ Node *l, *r, *a, *t;
+ int lv, rv;
+
+ if(n->type == 0)
+ return 0;
+
+ l = n->left;
+ r = n->right;
+
+ lv = 0;
+ if(l && l->type && typev[l->type->etype])
+ lv = 1;
+ rv = 0;
+ if(r && r->type && typev[r->type->etype])
+ rv = 1;
+
+ if(lv) {
+ switch(n->op) {
+ case OEQ:
+ a = nodeqv;
+ goto setbool;
+ case ONE:
+ a = nodnev;
+ goto setbool;
+ case OLE:
+ a = nodlev;
+ goto setbool;
+ case OLT:
+ a = nodltv;
+ goto setbool;
+ case OGE:
+ a = nodgev;
+ goto setbool;
+ case OGT:
+ a = nodgtv;
+ goto setbool;
+ case OHI:
+ a = nodhiv;
+ goto setbool;
+ case OHS:
+ a = nodhsv;
+ goto setbool;
+ case OLO:
+ a = nodlov;
+ goto setbool;
+ case OLS:
+ a = nodlsv;
+ goto setbool;
+
+ case OANDAND:
+ case OOROR:
+ if(machcap(n))
+ return 1;
+
+ if(rv) {
+ r = new(OFUNC, nodtestv, r);
+ n->right = r;
+ r->complex = FNX;
+ r->op = OFUNC;
+ r->type = types[TLONG];
+ }
+
+ case OCOND:
+ case ONOT:
+ if(machcap(n))
+ return 1;
+
+ l = new(OFUNC, nodtestv, l);
+ n->left = l;
+ l->complex = FNX;
+ l->op = OFUNC;
+ l->type = types[TLONG];
+ n->complex = FNX;
+ return 1;
+ }
+ }
+
+ if(rv) {
+ if(machcap(n))
+ return 1;
+ switch(n->op) {
+ case OANDAND:
+ case OOROR:
+ r = new(OFUNC, nodtestv, r);
+ n->right = r;
+ r->complex = FNX;
+ r->op = OFUNC;
+ r->type = types[TLONG];
+ return 1;
+ }
+ }
+
+ if(typev[n->type->etype]) {
+ if(machcap(n))
+ return 1;
+ switch(n->op) {
+ default:
+ diag(n, "unknown vlong %O", n->op);
+ case OFUNC:
+ n->complex = FNX;
+ case ORETURN:
+ case OAS:
+ case OIND:
+ return 1;
+ case OADD:
+ a = nodaddv;
+ goto setbop;
+ case OSUB:
+ a = nodsubv;
+ goto setbop;
+ case OMUL:
+ case OLMUL:
+ a = nodmulv;
+ goto setbop;
+ case ODIV:
+ a = noddivv;
+ goto setbop;
+ case OLDIV:
+ a = noddivvu;
+ goto setbop;
+ case OMOD:
+ a = nodmodv;
+ goto setbop;
+ case OLMOD:
+ a = nodmodvu;
+ goto setbop;
+ case OASHL:
+ a = nodlshv;
+ goto setbop;
+ case OASHR:
+ a = nodrshav;
+ goto setbop;
+ case OLSHR:
+ a = nodrshlv;
+ goto setbop;
+ case OAND:
+ a = nodandv;
+ goto setbop;
+ case OOR:
+ a = nodorv;
+ goto setbop;
+ case OXOR:
+ a = nodxorv;
+ goto setbop;
+ case OPOSTINC:
+ a = nodvpp;
+ goto setvinc;
+ case OPOSTDEC:
+ a = nodvmm;
+ goto setvinc;
+ case OPREINC:
+ a = nodppv;
+ goto setvinc;
+ case OPREDEC:
+ a = nodmmv;
+ goto setvinc;
+ case ONEG:
+ a = nodnegv;
+ goto setfnx;
+ case OCOM:
+ a = nodcomv;
+ goto setfnx;
+ case OCAST:
+ switch(l->type->etype) {
+ case TCHAR:
+ a = nodsc2v;
+ goto setfnxl;
+ case TUCHAR:
+ a = noduc2v;
+ goto setfnxl;
+ case TSHORT:
+ a = nodsh2v;
+ goto setfnxl;
+ case TUSHORT:
+ a = noduh2v;
+ goto setfnxl;
+ case TINT:
+ a = nodsi2v;
+ goto setfnx;
+ case TUINT:
+ a = nodui2v;
+ goto setfnx;
+ case TLONG:
+ a = nodsl2v;
+ goto setfnx;
+ case TULONG:
+ a = nodul2v;
+ goto setfnx;
+ case TFLOAT:
+ a = nodf2v;
+ goto setfnx;
+ case TDOUBLE:
+ a = nodd2v;
+ goto setfnx;
+ case TIND:
+ a = nodp2v;
+ goto setfnx;
+ }
+ diag(n, "unknown %T->vlong cast", l->type);
+ return 1;
+ case OASADD:
+ a = nodaddv;
+ goto setasop;
+ case OASSUB:
+ a = nodsubv;
+ goto setasop;
+ case OASMUL:
+ case OASLMUL:
+ a = nodmulv;
+ goto setasop;
+ case OASDIV:
+ a = noddivv;
+ goto setasop;
+ case OASLDIV:
+ a = noddivvu;
+ goto setasop;
+ case OASMOD:
+ a = nodmodv;
+ goto setasop;
+ case OASLMOD:
+ a = nodmodvu;
+ goto setasop;
+ case OASASHL:
+ a = nodlshv;
+ goto setasop;
+ case OASASHR:
+ a = nodrshav;
+ goto setasop;
+ case OASLSHR:
+ a = nodrshlv;
+ goto setasop;
+ case OASAND:
+ a = nodandv;
+ goto setasop;
+ case OASOR:
+ a = nodorv;
+ goto setasop;
+ case OASXOR:
+ a = nodxorv;
+ goto setasop;
+ }
+ }
+
+ if(typefd[n->type->etype] && l && l->op == OFUNC) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMOD:
+ case OASLMOD:
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ if(l->right && typev[l->right->etype]) {
+ diag(n, "sorry float <asop> vlong not implemented\n");
+ }
+ }
+ }
+
+ if(n->op == OCAST) {
+ if(l->type && typev[l->type->etype]) {
+ if(machcap(n))
+ return 1;
+ switch(n->type->etype) {
+ case TDOUBLE:
+ a = nodv2d;
+ goto setfnx;
+ case TFLOAT:
+ a = nodv2f;
+ goto setfnx;
+ case TLONG:
+ a = nodv2sl;
+ goto setfnx;
+ case TULONG:
+ a = nodv2ul;
+ goto setfnx;
+ case TINT:
+ a = nodv2si;
+ goto setfnx;
+ case TUINT:
+ a = nodv2ui;
+ goto setfnx;
+ case TSHORT:
+ a = nodv2sh;
+ goto setfnx;
+ case TUSHORT:
+ a = nodv2uh;
+ goto setfnx;
+ case TCHAR:
+ a = nodv2sc;
+ goto setfnx;
+ case TUCHAR:
+ a = nodv2uc;
+ goto setfnx;
+ case TIND: // small pun here
+ a = nodv2ul;
+ goto setfnx;
+ }
+ diag(n, "unknown vlong->%T cast", n->type);
+ return 1;
+ }
+ }
+
+ return 0;
+
+setbop:
+ n->left = a;
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setfnxl:
+ l = new(OCAST, l, 0);
+ l->type = types[TLONG];
+ l->complex = l->left->complex;
+
+setfnx:
+ n->left = a;
+ n->right = l;
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setvinc:
+ n->left = a;
+ l = new(OADDR, l, Z);
+ l->type = typ(TIND, l->left->type);
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ return 1;
+
+setbool:
+ if(machcap(n))
+ return 1;
+ n->left = a;
+ n->right = new(OLIST, l, r);
+ n->complex = FNX;
+ n->op = OFUNC;
+ n->type = types[TLONG];
+ return 1;
+
+setasop:
+ if(l->op == OFUNC) {
+ l = l->right;
+ goto setasop;
+ }
+
+ t = new(OCONST, 0, 0);
+ t->vconst = etconv[l->type->etype];
+ t->type = types[TLONG];
+ t->addable = 20;
+ r = new(OLIST, t, r);
+
+ t = new(OADDR, a, 0);
+ t->type = typ(TIND, a->type);
+ r = new(OLIST, t, r);
+
+ t = new(OADDR, l, 0);
+ t->type = typ(TIND, l->type);
+ r = new(OLIST, t, r);
+
+ n->left = nodvasop;
+ n->right = r;
+ n->complex = FNX;
+ n->op = OFUNC;
+
+ return 1;
+}
+
+void
+bool64(Node *n)
+{
+ Node *n1;
+
+ if(typev[n->type->etype]) {
+ n1 = new(OXXX, 0, 0);
+ *n1 = *n;
+
+ n->right = n1;
+ n->left = nodtestv;
+ n->complex = FNX;
+ n->addable = 0;
+ n->op = OFUNC;
+ n->type = types[TLONG];
+ }
+}
+
+/*
+ * more machine depend stuff.
+ * this is common for 8,16,32,64 bit machines.
+ * this is common for ieee machines.
+ */
+double
+convvtof(vlong v)
+{
+ double d;
+
+ d = v; /* BOTCH */
+ return d;
+}
+
+vlong
+convftov(double d)
+{
+ vlong v;
+
+
+ v = d; /* BOTCH */
+ return v;
+}
+
+double
+convftox(double d, int et)
+{
+
+ if(!typefd[et])
+ diag(Z, "bad type in castftox %s", tnames[et]);
+ return d;
+}
+
+vlong
+convvtox(vlong c, int et)
+{
+ int n;
+
+ n = 8 * ewidth[et];
+ c &= MASK(n);
+ if(!typeu[et])
+ if(c & SIGN(n))
+ c |= ~MASK(n);
+ return c;
+}
diff --git a/utils/cc/dcl.c b/utils/cc/dcl.c
new file mode 100644
index 00000000..71925701
--- /dev/null
+++ b/utils/cc/dcl.c
@@ -0,0 +1,1630 @@
+#include "cc.h"
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
+{
+ Sym *s;
+ Node *n1;
+ long v;
+
+ nearln = lineno;
+ lastfield = 0;
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ default:
+ diag(n, "unknown declarator: %O", n->op);
+ break;
+
+ case OARRAY:
+ t = typ(TARRAY, t);
+ t->width = 0;
+ n1 = n->right;
+ n = n->left;
+ if(n1 != Z) {
+ complex(n1);
+ v = -1;
+ if(n1->op == OCONST)
+ v = n1->vconst;
+ if(v <= 0) {
+ diag(n, "array size must be a positive constant");
+ v = 1;
+ }
+ t->width = v * t->link->width;
+ }
+ goto loop;
+
+ case OIND:
+ t = typ(TIND, t);
+ t->garb = n->garb;
+ n = n->left;
+ goto loop;
+
+ case OFUNC:
+ t = typ(TFUNC, t);
+ t->down = fnproto(n);
+ n = n->left;
+ goto loop;
+
+ case OBIT:
+ n1 = n->right;
+ complex(n1);
+ lastfield = -1;
+ if(n1->op == OCONST)
+ lastfield = n1->vconst;
+ if(lastfield < 0) {
+ diag(n, "field width must be non-negative constant");
+ lastfield = 1;
+ }
+ if(lastfield == 0) {
+ lastbit = 0;
+ firstbit = 1;
+ if(n->left != Z) {
+ diag(n, "zero width named field");
+ lastfield = 1;
+ }
+ }
+ if(!typei[t->etype]) {
+ diag(n, "field type must be int-like");
+ t = types[TINT];
+ lastfield = 1;
+ }
+ if(lastfield > tfield->width*8) {
+ diag(n, "field width larger than field unit");
+ lastfield = 1;
+ }
+ lastbit += lastfield;
+ if(lastbit > tfield->width*8) {
+ lastbit = lastfield;
+ firstbit = 1;
+ }
+ n = n->left;
+ goto loop;
+
+ case ONAME:
+ if(f == NODECL)
+ break;
+ s = n->sym;
+ (*f)(c, t, s);
+ if(s->class == CLOCAL)
+ s = mkstatic(s);
+ firstbit = 0;
+ n->sym = s;
+ n->type = s->type;
+ n->xoffset = s->offset;
+ n->class = s->class;
+ n->etype = TVOID;
+ if(n->type != T)
+ n->etype = n->type->etype;
+ if(debug['d'])
+ dbgdecl(s);
+ acidvar(s);
+ s->varlineno = lineno;
+ break;
+ }
+ lastdcl = t;
+ return n;
+}
+
+Sym*
+mkstatic(Sym *s)
+{
+ Sym *s1;
+
+ if(s->class != CLOCAL)
+ return s;
+ snprint(symb, NSYMB, "%s$%d", s->name, s->block);
+ s1 = lookup();
+ if(s1->class != CSTATIC) {
+ s1->type = s->type;
+ s1->offset = s->offset;
+ s1->block = s->block;
+ s1->class = CSTATIC;
+ }
+ return s1;
+}
+
+/*
+ * make a copy of a typedef
+ * the problem is to split out incomplete
+ * arrays so that it is in the variable
+ * rather than the typedef.
+ */
+Type*
+tcopy(Type *t)
+{
+ Type *tl, *tx;
+ int et;
+
+ if(t == T)
+ return t;
+ et = t->etype;
+ if(typesu[et])
+ return t;
+ tl = tcopy(t->link);
+ if(tl != t->link ||
+ (et == TARRAY && t->width == 0)) {
+ tx = copytyp(t);
+ tx->link = tl;
+ return tx;
+ }
+ return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, long o, Node *a)
+{
+ Node *n;
+
+ if(t == T)
+ return Z;
+ if(s->class == CEXTERN) {
+ s->class = CGLOBL;
+ if(debug['d'])
+ dbgdecl(s);
+ }
+ if(debug['i']) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "doinit value");
+ }
+
+
+ n = initlist;
+ if(a->op == OINIT)
+ a = a->left;
+ initlist = a;
+
+ a = init1(s, t, o, 0);
+ if(initlist != Z)
+ diag(initlist, "more initializers than structure: %s",
+ s->name);
+ initlist = n;
+
+ return a;
+}
+
+/*
+ * get next major operator,
+ * dont advance initlist.
+ */
+Node*
+peekinit(void)
+{
+ Node *a;
+
+ a = initlist;
+
+loop:
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ a = a->left;
+ goto loop;
+ }
+ return a;
+}
+
+/*
+ * consume and return next element on
+ * initlist. expand strings.
+ */
+Node*
+nextinit(void)
+{
+ Node *a, *b, *n;
+
+ a = initlist;
+ n = Z;
+
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ n = a->right;
+ a = a->left;
+ }
+ if(a->op == OUSED) {
+ a = a->left;
+ b = new(OCONST, Z, Z);
+ b->type = a->type->link;
+ if(a->op == OSTRING) {
+ b->vconst = convvtox(*a->cstring, TCHAR);
+ a->cstring++;
+ }
+ if(a->op == OLSTRING) {
+ b->vconst = convvtox(*a->rstring, TUSHORT);
+ a->rstring++;
+ }
+ a->type->width -= b->type->width;
+ if(a->type->width <= 0)
+ initlist = n;
+ return b;
+ }
+ initlist = n;
+ return a;
+}
+
+int
+isstruct(Node *a, Type *t)
+{
+ Node *n;
+
+ switch(a->op) {
+ case ODOTDOT:
+ n = a->left;
+ if(n && n->type && sametype(n->type, t))
+ return 1;
+ case OSTRING:
+ case OLSTRING:
+ case OCONST:
+ case OINIT:
+ case OELEM:
+ return 0;
+ }
+
+ n = new(ODOTDOT, Z, Z);
+ *n = *a;
+
+ /*
+ * ODOTDOT is a flag for tcom
+ * a second tcom will not be performed
+ */
+ a->op = ODOTDOT;
+ a->left = n;
+ a->right = Z;
+
+ if(tcom(n))
+ return 0;
+
+ if(sametype(n->type, t))
+ return 1;
+ return 0;
+}
+
+Node*
+init1(Sym *s, Type *t, long o, int exflag)
+{
+ Node *a, *l, *r, nod;
+ Type *t1;
+ long e, w, so, mw;
+
+ a = peekinit();
+ if(a == Z)
+ return Z;
+
+ if(debug['i']) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "init1 value");
+ }
+
+ if(exflag && a->op == OINIT)
+ return doinit(s, t, o, nextinit());
+
+ switch(t->etype) {
+ default:
+ diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+ return Z;
+
+ case TCHAR:
+ case TUCHAR:
+ case TINT:
+ case TUINT:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ case TIND:
+ single:
+ if(a->op == OARRAY || a->op == OELEM)
+ return Z;
+
+ a = nextinit();
+ if(a == Z)
+ return Z;
+
+ if(t->nbits)
+ diag(Z, "cannot initialize bitfields");
+ if(s->class == CAUTO) {
+ l = new(ONAME, Z, Z);
+ l->sym = s;
+ l->type = t;
+ l->etype = TVOID;
+ if(s->type)
+ l->etype = s->type->etype;
+ l->xoffset = s->offset + o;
+ l->class = s->class;
+
+ l = new(OASI, l, a);
+ return l;
+ }
+
+ complex(a);
+ if(a->type == T)
+ return Z;
+
+ if(a->op == OCONST) {
+ if(!sametype(a->type, t)) {
+ /* hoop jumping to save malloc */
+ if(nodcast == Z)
+ nodcast = new(OCAST, Z, Z);
+ nod = *nodcast;
+ nod.left = a;
+ nod.type = t;
+ nod.lineno = a->lineno;
+ complex(&nod);
+ if(nod.type)
+ *a = nod;
+ }
+ if(a->op != OCONST) {
+ diag(a, "initializer is not a constant: %s",
+ s->name);
+ return Z;
+ }
+ if(vconst(a) == 0)
+ return Z;
+ goto gext;
+ }
+ if(t->etype == TIND) {
+ while(a->op == OCAST) {
+ warn(a, "CAST in initialization ignored");
+ a = a->left;
+ }
+ if(!sametype(t, a->type)) {
+ diag(a, "initialization of incompatible pointers: %s\n%T and %T",
+ s->name, t, a->type);
+ }
+ if(a->op == OADDR)
+ a = a->left;
+ goto gext;
+ }
+
+ while(a->op == OCAST)
+ a = a->left;
+ if(a->op == OADDR) {
+ warn(a, "initialize pointer to an integer: %s", s->name);
+ a = a->left;
+ goto gext;
+ }
+ diag(a, "initializer is not a constant: %s", s->name);
+ return Z;
+
+ gext:
+ gextern(s, a, o, t->width);
+
+ return Z;
+
+ case TARRAY:
+ w = t->link->width;
+ if(a->op == OSTRING || a->op == OLSTRING)
+ if(typei[t->link->etype]) {
+ /*
+ * get rid of null if sizes match exactly
+ */
+ a = nextinit();
+ mw = t->width/w;
+ so = a->type->width/a->type->link->width;
+ if(mw && so > mw) {
+ if(so != mw+1)
+ diag(a, "string initialization larger than array");
+ a->type->width -= a->type->link->width;
+ }
+
+ /*
+ * arrange strings to be expanded
+ * inside OINIT braces.
+ */
+ a = new(OUSED, a, Z);
+ return doinit(s, t, o, a);
+ }
+
+ mw = -w;
+ l = Z;
+ for(e=0;;) {
+ /*
+ * peek ahead for element initializer
+ */
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM && t->link->etype != TSTRUCT)
+ break;
+ if(a->op == OARRAY) {
+ if(e && exflag)
+ break;
+ a = nextinit();
+ r = a->left;
+ complex(r);
+ if(r->op != OCONST) {
+ diag(r, "initializer subscript must be constant");
+ return Z;
+ }
+ e = r->vconst;
+ if(t->width != 0)
+ if(e < 0 || e*w >= t->width) {
+ diag(a, "initialization index out of range: %ld", e);
+ continue;
+ }
+ }
+
+ so = e*w;
+ if(so > mw)
+ mw = so;
+ if(t->width != 0)
+ if(mw >= t->width)
+ break;
+ r = init1(s, t->link, o+so, 1);
+ l = newlist(l, r);
+ e++;
+ }
+ if(t->width == 0)
+ t->width = mw+w;
+ return l;
+
+ case TUNION:
+ case TSTRUCT:
+ /*
+ * peek ahead to find type of rhs.
+ * if its a structure, then treat
+ * this element as a variable
+ * rather than an aggregate.
+ */
+ if(isstruct(a, t))
+ goto single;
+
+ if(t->width <= 0) {
+ diag(Z, "incomplete structure: %s", s->name);
+ return Z;
+ }
+ l = Z;
+
+ again:
+ for(t1 = t->link; t1 != T; t1 = t1->down) {
+ if(a->op == OARRAY && t1->etype != TARRAY)
+ break;
+ if(a->op == OELEM) {
+ if(t1->sym != a->sym)
+ continue;
+ nextinit();
+ }
+ r = init1(s, t1, o+t1->offset, 1);
+ l = newlist(l, r);
+ a = peekinit();
+ if(a == Z)
+ break;
+ if(a->op == OELEM)
+ goto again;
+ }
+ if(a && a->op == OELEM)
+ diag(a, "structure element not found %F", a);
+ return l;
+ }
+}
+
+Node*
+newlist(Node *l, Node *r)
+{
+ if(r == Z)
+ return l;
+ if(l == Z)
+ return r;
+ return new(OLIST, l, r);
+}
+
+void
+suallign(Type *t)
+{
+ Type *l;
+ long o, w;
+
+ o = 0;
+ switch(t->etype) {
+
+ case TSTRUCT:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->nbits) {
+ if(l->shift <= 0) {
+ l->shift = -l->shift;
+ w = round(w, tfield->width);
+ o = w;
+ w += tfield->width;
+ }
+ l->offset = o;
+ } else {
+ if(l->width <= 0)
+ if(l->sym)
+ diag(Z, "incomplete structure element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete structure element");
+ w = align(w, l, Ael1);
+ l->offset = w;
+ w = align(w, l, Ael2);
+ }
+ }
+ w = align(w, t, Asu2);
+ t->width = w;
+ acidtype(t);
+ pickletype(t);
+ return;
+
+ case TUNION:
+ t->offset = 0;
+ w = 0;
+ for(l = t->link; l != T; l = l->down) {
+ if(l->width <= 0)
+ if(l->sym)
+ diag(Z, "incomplete union element: %s",
+ l->sym->name);
+ else
+ diag(Z, "incomplete union element");
+ l->offset = 0;
+ l->shift = 0;
+ o = align(align(0, l, Ael1), l, Ael2);
+ if(o > w)
+ w = o;
+ }
+ w = align(w, t, Asu2);
+ t->width = w;
+ acidtype(t);
+ pickletype(t);
+ return;
+
+ default:
+ diag(Z, "unknown type in suallign: %T", t);
+ break;
+ }
+}
+
+long
+round(long v, int w)
+{
+ int r;
+
+ if(w <= 0 || w > 8) {
+ diag(Z, "rounding by %d", w);
+ w = 1;
+ }
+ r = v%w;
+ if(r)
+ v += w-r;
+ return v;
+}
+
+Type*
+ofnproto(Node *n)
+{
+ Type *tl, *tr, *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ tl = ofnproto(n->left);
+ tr = ofnproto(n->right);
+ if(tl == T)
+ return tr;
+ tl->down = tr;
+ return tl;
+
+ case ONAME:
+ t = copytyp(n->sym->type);
+ t->down = T;
+ return t;
+ }
+ return T;
+}
+
+#define ANSIPROTO 1
+#define OLDPROTO 2
+
+void
+argmark(Node *n, int pass)
+{
+ Type *t;
+
+ autoffset = align(0, thisfn->link, Aarg0);
+ stkoff = 0;
+ for(; n->left != Z; n = n->left) {
+ if(n->op != OFUNC || n->left->op != ONAME)
+ continue;
+ walkparam(n->right, pass);
+ if(pass != 0 && anyproto(n->right) == OLDPROTO) {
+ t = typ(TFUNC, n->left->sym->type->link);
+ t->down = typ(TOLD, T);
+ t->down->down = ofnproto(n->right);
+ tmerge(t, n->left->sym);
+ n->left->sym->type = t;
+ }
+ break;
+ }
+ autoffset = 0;
+ stkoff = 0;
+}
+
+void
+walkparam(Node *n, int pass)
+{
+ Sym *s;
+ Node *n1;
+
+ if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
+ return;
+
+loop:
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ diag(n, "argument not a name/prototype: %O", n->op);
+ break;
+
+ case OLIST:
+ walkparam(n->left, pass);
+ n = n->right;
+ goto loop;
+
+ case OPROTO:
+ for(n1 = n; n1 != Z; n1=n1->left)
+ if(n1->op == ONAME) {
+ if(pass == 0) {
+ s = n1->sym;
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ dodecl(pdecl, CPARAM, n->type, n->left);
+ break;
+ }
+ if(n1)
+ break;
+ if(pass == 0) {
+ /*
+ * extension:
+ * allow no name in argument declaration
+ diag(Z, "no name in argument declaration");
+ */
+ break;
+ }
+ dodecl(NODECL, CPARAM, n->type, n->left);
+ pdecl(CPARAM, lastdcl, S);
+ break;
+
+ case ODOTDOT:
+ break;
+
+ case ONAME:
+ s = n->sym;
+ if(pass == 0) {
+ push1(s);
+ s->offset = -1;
+ break;
+ }
+ if(s->offset != -1) {
+ if(autoffset == 0) {
+ firstarg = s;
+ firstargtype = s->type;
+ }
+ autoffset = align(autoffset, s->type, Aarg1);
+ s->offset = autoffset;
+ autoffset = align(autoffset, s->type, Aarg2);
+ } else
+ dodecl(pdecl, CXXX, types[TINT], n);
+ break;
+ }
+}
+
+void
+markdcl(void)
+{
+ Decl *d;
+
+ blockno++;
+ d = push();
+ d->val = DMARK;
+ d->offset = autoffset;
+ d->block = autobn;
+ autobn = blockno;
+}
+
+Node*
+revertdcl(void)
+{
+ Decl *d;
+ Sym *s;
+ Node *n, *n1;
+
+ n = Z;
+ for(;;) {
+ d = dclstack;
+ if(d == D) {
+ diag(Z, "pop off dcl stack");
+ break;
+ }
+ dclstack = d->link;
+ s = d->sym;
+ switch(d->val) {
+ case DMARK:
+ autoffset = d->offset;
+ autobn = d->block;
+ return n;
+
+ case DAUTO:
+ if(debug['d'])
+ print("revert1 \"%s\"\n", s->name);
+ if(s->aused == 0) {
+ nearln = s->varlineno;
+ if(s->class == CAUTO)
+ warn(Z, "auto declared and not used: %s", s->name);
+ if(s->class == CPARAM)
+ warn(Z, "param declared and not used: %s", s->name);
+ }
+ if(s->type && (s->type->garb & GVOLATILE)) {
+ n1 = new(ONAME, Z, Z);
+ n1->sym = s;
+ n1->type = s->type;
+ n1->etype = TVOID;
+ if(n1->type != T)
+ n1->etype = n1->type->etype;
+ n1->xoffset = s->offset;
+ n1->class = s->class;
+
+ n1 = new(OADDR, n1, Z);
+ n1 = new(OUSED, n1, Z);
+ if(n == Z)
+ n = n1;
+ else
+ n = new(OLIST, n1, n);
+ }
+ s->type = d->type;
+ s->class = d->class;
+ s->offset = d->offset;
+ s->block = d->block;
+ s->varlineno = d->varlineno;
+ s->aused = d->aused;
+ break;
+
+ case DSUE:
+ if(debug['d'])
+ print("revert2 \"%s\"\n", s->name);
+ s->suetag = d->type;
+ s->sueblock = d->block;
+ break;
+
+ case DLABEL:
+ if(debug['d'])
+ print("revert3 \"%s\"\n", s->name);
+ if(s->label && s->label->addable == 0)
+ warn(s->label, "label declared and not used \"%s\"", s->name);
+ s->label = Z;
+ break;
+ }
+ }
+ return n;
+}
+
+Type*
+fnproto(Node *n)
+{
+ int r;
+
+ r = anyproto(n->right);
+ if(r == 0 || (r & OLDPROTO)) {
+ if(r & ANSIPROTO)
+ diag(n, "mixed ansi/old function declaration: %F", n->left);
+ return T;
+ }
+ return fnproto1(n->right);
+}
+
+int
+anyproto(Node *n)
+{
+ int r;
+
+ r = 0;
+
+loop:
+ if(n == Z)
+ return r;
+ switch(n->op) {
+ case OLIST:
+ r |= anyproto(n->left);
+ n = n->right;
+ goto loop;
+
+ case ODOTDOT:
+ case OPROTO:
+ return r | ANSIPROTO;
+ }
+ return r | OLDPROTO;
+}
+
+Type*
+fnproto1(Node *n)
+{
+ Type *t;
+
+ if(n == Z)
+ return T;
+ switch(n->op) {
+ case OLIST:
+ t = fnproto1(n->left);
+ if(t != T)
+ t->down = fnproto1(n->right);
+ return t;
+
+ case OPROTO:
+ lastdcl = T;
+ dodecl(NODECL, CXXX, n->type, n->left);
+ t = typ(TXXX, T);
+ if(lastdcl != T)
+ *t = *paramconv(lastdcl, 1);
+ return t;
+
+ case ONAME:
+ diag(n, "incomplete argument prototype");
+ return typ(TINT, T);
+
+ case ODOTDOT:
+ return typ(TDOT, T);
+ }
+ diag(n, "unknown op in fnproto");
+ return T;
+}
+
+void
+dbgdecl(Sym *s)
+{
+ print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n",
+ s->name, cnames[s->class], s->block, s->offset, s->type);
+}
+
+Decl*
+push(void)
+{
+ Decl *d;
+
+ d = alloc(sizeof(*d));
+ d->link = dclstack;
+ dclstack = d;
+ return d;
+}
+
+Decl*
+push1(Sym *s)
+{
+ Decl *d;
+
+ d = push();
+ d->sym = s;
+ d->val = DAUTO;
+ d->type = s->type;
+ d->class = s->class;
+ d->offset = s->offset;
+ d->block = s->block;
+ d->varlineno = s->varlineno;
+ d->aused = s->aused;
+ return d;
+}
+
+int
+sametype(Type *t1, Type *t2)
+{
+
+ if(t1 == t2)
+ return 1;
+ return rsametype(t1, t2, 5, 1);
+}
+
+int
+rsametype(Type *t1, Type *t2, int n, int f)
+{
+ int et;
+
+ n--;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(n <= 0)
+ return 1;
+ et = t1->etype;
+ if(et != t2->etype)
+ return 0;
+ if(et == TFUNC) {
+ if(!rsametype(t1->link, t2->link, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ while(t1 != T && t2 != T) {
+ if(t1->etype == TOLD) {
+ t1 = t1->down;
+ continue;
+ }
+ if(t2->etype == TOLD) {
+ t2 = t2->down;
+ continue;
+ }
+ while(t1 != T || t2 != T) {
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ break;
+ }
+ return 1;
+ }
+ if(et == TARRAY)
+ if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
+ return 0;
+ if(typesu[et]) {
+ if(t1->link == T)
+ snap(t1);
+ if(t2->link == T)
+ snap(t2);
+ t1 = t1->link;
+ t2 = t2->link;
+ for(;;) {
+ if(t1 == t2)
+ return 1;
+ if(!rsametype(t1, t2, n, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ if((f || !debug['V']) && et == TIND) {
+ if(t1 != T && t1->etype == TVOID)
+ return 1;
+ if(t2 != T && t2->etype == TVOID)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+typedef struct Typetab Typetab;
+
+struct Typetab{
+ int n;
+ Type **a;
+};
+
+static int
+sigind(Type *t, Typetab *tt)
+{
+ int n;
+ Type **a, **na, **p, **e;
+
+ n = tt->n;
+ a = tt->a;
+ e = a+n;
+ /* linear search seems ok */
+ for(p = a ; p < e; p++)
+ if(sametype(*p, t))
+ return p-a;
+ if((n&15) == 0){
+ na = malloc((n+16)*sizeof(Type*));
+ memmove(na, a, n*sizeof(Type*));
+ free(a);
+ a = tt->a = na;
+ }
+ a[tt->n++] = t;
+ return -1;
+}
+
+static ulong
+signat(Type *t, Typetab *tt)
+{
+ int i;
+ Type *t1;
+ long s;
+
+ s = 0;
+ for(; t; t=t->link) {
+ s = s*thash1 + thash[t->etype];
+ if(t->garb&GINCOMPLETE)
+ return s;
+ switch(t->etype) {
+ default:
+ return s;
+ case TARRAY:
+ s = s*thash2 + 0; /* was t->width */
+ break;
+ case TFUNC:
+ for(t1=t->down; t1; t1=t1->down)
+ s = s*thash3 + signat(t1, tt);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ if((i = sigind(t, tt)) >= 0){
+ s = s*thash2 + i;
+ return s;
+ }
+ for(t1=t->link; t1; t1=t1->down)
+ s = s*thash3 + signat(t1, tt);
+ return s;
+ case TIND:
+ break;
+ }
+ }
+ return s;
+}
+
+ulong
+signature(Type *t)
+{
+ ulong s;
+ Typetab tt;
+
+ tt.n = 0;
+ tt.a = nil;
+ s = signat(t, &tt);
+ free(tt.a);
+ return s;
+}
+
+ulong
+sign(Sym *s)
+{
+ ulong v;
+ Type *t;
+
+ if(s->sig == SIGINTERN)
+ return SIGNINTERN;
+ if((t = s->type) == T)
+ return 0;
+ v = signature(t);
+ if(v == 0)
+ v = SIGNINTERN;
+ return v;
+}
+
+void
+snap(Type *t)
+{
+ if(typesu[t->etype])
+ if(t->link == T && t->tag && t->tag->suetag) {
+ t->link = t->tag->suetag->link;
+ t->width = t->tag->suetag->width;
+ }
+}
+
+Type*
+dotag(Sym *s, int et, int bn)
+{
+ Decl *d;
+
+ if(bn != 0 && bn != s->sueblock) {
+ d = push();
+ d->sym = s;
+ d->val = DSUE;
+ d->type = s->suetag;
+ d->block = s->sueblock;
+ s->suetag = T;
+ }
+ if(s->suetag == T) {
+ s->suetag = typ(et, T);
+ s->sueblock = autobn;
+ }
+ if(s->suetag->etype != et)
+ diag(Z, "tag used for more than one type: %s",
+ s->name);
+ if(s->suetag->tag == S)
+ s->suetag->tag = s;
+ return s->suetag;
+}
+
+Node*
+dcllabel(Sym *s, int f)
+{
+ Decl *d, d1;
+ Node *n;
+
+ n = s->label;
+ if(n != Z) {
+ if(f) {
+ if(n->complex)
+ diag(Z, "label reused: %s", s->name);
+ n->complex = 1; // declared
+ } else
+ n->addable = 1; // used
+ return n;
+ }
+
+ d = push();
+ d->sym = s;
+ d->val = DLABEL;
+ dclstack = d->link;
+
+ d1 = *firstdcl;
+ *firstdcl = *d;
+ *d = d1;
+
+ firstdcl->link = d;
+ firstdcl = d;
+
+ n = new(OXXX, Z, Z);
+ n->sym = s;
+ n->complex = f;
+ n->addable = !f;
+ s->label = n;
+
+ if(debug['d'])
+ dbgdecl(s);
+ return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+
+ switch(t->etype) {
+ case TUNION:
+ case TSTRUCT:
+ if(t->width <= 0)
+ diag(Z, "incomplete structure: %s", t->tag->name);
+ break;
+
+ case TARRAY:
+ t = typ(TIND, t->link);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFUNC:
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ break;
+
+ case TFLOAT:
+ if(!f)
+ t = types[TDOUBLE];
+ break;
+
+ case TCHAR:
+ case TSHORT:
+ if(!f)
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ if(!f)
+ t = types[TUINT];
+ break;
+ }
+ return t;
+}
+
+void
+adecl(int c, Type *t, Sym *s)
+{
+
+ if(c == CSTATIC)
+ c = CLOCAL;
+ if(t->etype == TFUNC) {
+ if(c == CXXX)
+ c = CEXTERN;
+ if(c == CLOCAL)
+ c = CSTATIC;
+ if(c == CAUTO || c == CEXREG)
+ diag(Z, "function cannot be %s %s", cnames[c], s->name);
+ }
+ if(c == CXXX)
+ c = CAUTO;
+ if(s) {
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "just say static: %s", s->name);
+ c = CSTATIC;
+ }
+ if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
+ if(s->block == autobn)
+ diag(Z, "auto redeclaration of: %s", s->name);
+ if(c != CPARAM)
+ push1(s);
+ s->block = autobn;
+ s->offset = 0;
+ s->type = t;
+ s->class = c;
+ s->aused = 0;
+ }
+ switch(c) {
+ case CAUTO:
+ autoffset = align(autoffset, t, Aaut3);
+ stkoff = maxround(stkoff, autoffset);
+ s->offset = -autoffset;
+ break;
+
+ case CPARAM:
+ if(autoffset == 0) {
+ firstarg = s;
+ firstargtype = t;
+ }
+ autoffset = align(autoffset, t, Aarg1);
+ if(s)
+ s->offset = autoffset;
+ autoffset = align(autoffset, t, Aarg2);
+ break;
+ }
+}
+
+void
+pdecl(int c, Type *t, Sym *s)
+{
+ if(s && s->offset != -1) {
+ diag(Z, "not a parameter: %s", s->name);
+ return;
+ }
+ t = paramconv(t, c==CPARAM);
+ if(c == CXXX)
+ c = CPARAM;
+ if(c != CPARAM) {
+ diag(Z, "parameter cannot have class: %s", s->name);
+ c = CPARAM;
+ }
+ adecl(c, t, s);
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+ long o;
+
+ o = 0;
+ switch(c) {
+ case CEXREG:
+ o = exreg(t);
+ if(o == 0)
+ c = CEXTERN;
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ break;
+
+ case CEXTERN:
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ break;
+
+ case CXXX:
+ c = CGLOBL;
+ if(s->class == CEXTERN)
+ s->class = CGLOBL;
+ break;
+
+ case CAUTO:
+ diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CEXTERN;
+ break;
+
+ case CTYPESTR:
+ if(!typesuv[t->etype]) {
+ diag(Z, "typestr must be struct/union: %s", s->name);
+ break;
+ }
+ dclfunct(t, s);
+ break;
+ }
+
+ if(s->class == CSTATIC)
+ if(c == CEXTERN || c == CGLOBL) {
+ warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CSTATIC;
+ }
+ if(s->type != T)
+ if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
+ diag(Z, "external redeclaration of: %s", s->name);
+ Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln);
+ Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno);
+ }
+ tmerge(t, s);
+ s->type = t;
+ s->class = c;
+ s->block = 0;
+ s->offset = o;
+}
+
+void
+tmerge(Type *t1, Sym *s)
+{
+ Type *ta, *tb, *t2;
+
+ t2 = s->type;
+/*print("merge %T; %T\n", t1, t2);/**/
+ for(;;) {
+ if(t1 == T || t2 == T || t1 == t2)
+ break;
+ if(t1->etype != t2->etype)
+ break;
+ switch(t1->etype) {
+ case TFUNC:
+ ta = t1->down;
+ tb = t2->down;
+ if(ta == T) {
+ t1->down = tb;
+ break;
+ }
+ if(tb == T)
+ break;
+ while(ta != T && tb != T) {
+ if(ta == tb)
+ break;
+ /* ignore old-style flag */
+ if(ta->etype == TOLD) {
+ ta = ta->down;
+ continue;
+ }
+ if(tb->etype == TOLD) {
+ tb = tb->down;
+ continue;
+ }
+ /* checking terminated by ... */
+ if(ta->etype == TDOT && tb->etype == TDOT) {
+ ta = T;
+ tb = T;
+ break;
+ }
+ if(!sametype(ta, tb))
+ break;
+ ta = ta->down;
+ tb = tb->down;
+ }
+ if(ta != tb)
+ diag(Z, "function inconsistently declared: %s", s->name);
+
+ /* take new-style over old-style */
+ ta = t1->down;
+ tb = t2->down;
+ if(ta != T && ta->etype == TOLD)
+ if(tb != T && tb->etype != TOLD)
+ t1->down = tb;
+ break;
+
+ case TARRAY:
+ /* should we check array size change? */
+ if(t2->width > t1->width)
+ t1->width = t2->width;
+ break;
+
+ case TUNION:
+ case TSTRUCT:
+ return;
+ }
+ t1 = t1->link;
+ t2 = t2->link;
+ }
+}
+
+void
+edecl(int c, Type *t, Sym *s)
+{
+ Type *t1;
+
+ if(s == S) {
+ if(!typesu[t->etype])
+ diag(Z, "unnamed structure element must be struct/union");
+ if(c != CXXX)
+ diag(Z, "unnamed structure element cannot have class");
+ } else
+ if(c != CXXX)
+ diag(Z, "structure element cannot have class: %s", s->name);
+ t1 = t;
+ t = copytyp(t1);
+ t->sym = s;
+ t->down = T;
+ if(lastfield) {
+ t->shift = lastbit - lastfield;
+ t->nbits = lastfield;
+ if(firstbit)
+ t->shift = -t->shift;
+ if(typeu[t->etype])
+ t->etype = tufield->etype;
+ else
+ t->etype = tfield->etype;
+ }
+ if(strf == T)
+ strf = t;
+ else
+ strl->down = t;
+ strl = t;
+}
+
+/*
+ * this routine is very suspect.
+ * ansi requires the enum type to
+ * be represented as an 'int'
+ * this means that 0x81234567
+ * would be illegal. this routine
+ * makes signed and unsigned go
+ * to unsigned.
+ */
+Type*
+maxtype(Type *t1, Type *t2)
+{
+
+ if(t1 == T)
+ return t2;
+ if(t2 == T)
+ return t1;
+ if(t1->etype > t2->etype)
+ return t1;
+ return t2;
+}
+
+void
+doenum(Sym *s, Node *n)
+{
+
+ if(n) {
+ complex(n);
+ if(n->op != OCONST) {
+ diag(n, "enum not a constant: %s", s->name);
+ return;
+ }
+ en.cenum = n->type;
+ en.tenum = maxtype(en.cenum, en.tenum);
+
+ if(!typefd[en.cenum->etype])
+ en.lastenum = n->vconst;
+ else
+ en.floatenum = n->fconst;
+ }
+ if(dclstack)
+ push1(s);
+ xdecl(CXXX, types[TENUM], s);
+
+ if(en.cenum == T) {
+ en.tenum = types[TINT];
+ en.cenum = types[TINT];
+ en.lastenum = 0;
+ }
+ s->tenum = en.cenum;
+
+ if(!typefd[s->tenum->etype]) {
+ s->vconst = convvtox(en.lastenum, s->tenum->etype);
+ en.lastenum++;
+ } else {
+ s->fconst = en.floatenum;
+ en.floatenum++;
+ }
+
+ if(debug['d'])
+ dbgdecl(s);
+ acidvar(s);
+}
+
+void
+symadjust(Sym *s, Node *n, long del)
+{
+
+ switch(n->op) {
+ default:
+ if(n->left)
+ symadjust(s, n->left, del);
+ if(n->right)
+ symadjust(s, n->right, del);
+ return;
+
+ case ONAME:
+ if(n->sym == s)
+ n->xoffset -= del;
+ return;
+
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+ }
+}
+
+Node*
+contig(Sym *s, Node *n, long v)
+{
+ Node *p, *r, *q, *m;
+ long w;
+ Type *zt;
+
+ if(debug['i']) {
+ print("contig v = %ld; s = %s\n", v, s->name);
+ prtree(n, "doinit value");
+ }
+
+ if(n == Z)
+ goto no;
+ w = s->type->width;
+
+ /*
+ * nightmare: an automatic array whose size
+ * increases when it is initialized
+ */
+ if(v != w) {
+ if(v != 0)
+ diag(n, "automatic adjustable array: %s", s->name);
+ v = s->offset;
+ autoffset = align(autoffset, s->type, Aaut3);
+ s->offset = -autoffset;
+ stkoff = maxround(stkoff, autoffset);
+ symadjust(s, n, v - s->offset);
+ }
+ if(w <= ewidth[TIND])
+ goto no;
+ if(n->op == OAS)
+ diag(Z, "oops in contig");
+/*ZZZ this appears incorrect
+need to check if the list completely covers the data.
+if not, bail
+ */
+ if(n->op == OLIST)
+ goto no;
+ if(n->op == OASI)
+ if(n->left->type)
+ if(n->left->type->width == w)
+ goto no;
+ while(w & (ewidth[TIND]-1))
+ w++;
+/*
+ * insert the following code, where long becomes vlong if pointers are fat
+ *
+ *(long**)&X = (long*)((char*)X + sizeof(X));
+ do {
+ *(long**)&X -= 1;
+ **(long**)&X = 0;
+ } while(*(long**)&X);
+ */
+
+ for(q=n; q->op != ONAME; q=q->left)
+ ;
+
+ zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
+
+ p = new(ONAME, Z, Z);
+ *p = *q;
+ p->type = typ(TIND, zt);
+ p->xoffset = s->offset;
+
+ r = new(ONAME, Z, Z);
+ *r = *p;
+ r = new(OPOSTDEC, r, Z);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ q = new(OIND, q, Z);
+
+ m = new(OCONST, Z, Z);
+ m->vconst = 0;
+ m->type = zt;
+
+ q = new(OAS, q, m);
+
+ r = new(OLIST, r, q);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ r = new(ODWHILE, q, r);
+
+ q = new(ONAME, Z, Z);
+ *q = *p;
+ q->type = q->type->link;
+ q->xoffset += w;
+ q = new(OADDR, q, 0);
+
+ q = new(OASI, p, q);
+ r = new(OLIST, q, r);
+
+ n = new(OLIST, r, n);
+
+no:
+ return n;
+}
diff --git a/utils/cc/dpchk.c b/utils/cc/dpchk.c
new file mode 100644
index 00000000..a061b12c
--- /dev/null
+++ b/utils/cc/dpchk.c
@@ -0,0 +1,463 @@
+#include "cc.h"
+#include "y.tab.h"
+
+enum
+{
+ Fnone = 0,
+ Fl,
+ Fvl,
+ Fignor,
+ Fstar,
+ Fadj,
+
+ Fverb = 10,
+};
+
+typedef struct Tprot Tprot;
+struct Tprot
+{
+ Type* type;
+ Bits flag;
+ Tprot* link;
+};
+
+typedef struct Tname Tname;
+struct Tname
+{
+ char* name;
+ int param;
+ Tname* link;
+};
+
+static Type* indchar;
+static uchar flagbits[512];
+static char fmtbuf[100];
+static int lastadj;
+static int lastverb;
+static int nstar;
+static Tprot* tprot;
+static Tname* tname;
+
+void
+argflag(int c, int v)
+{
+
+ switch(v) {
+ case Fignor:
+ case Fstar:
+ case Fl:
+ case Fvl:
+ flagbits[c] = v;
+ break;
+ case Fverb:
+ flagbits[c] = lastverb;
+/*print("flag-v %c %d\n", c, lastadj);*/
+ lastverb++;
+ break;
+ case Fadj:
+ flagbits[c] = lastadj;
+/*print("flag-l %c %d\n", c, lastadj);*/
+ lastadj++;
+ break;
+ }
+}
+
+Bits
+getflag(char *s)
+{
+ Bits flag;
+ int f;
+ char *fmt;
+ Rune c;
+
+ fmt = fmtbuf;
+ flag = zbits;
+ nstar = 0;
+ for(;;) {
+ s += chartorune(&c, s);
+ if(c == 0 || c >= nelem(flagbits))
+ break;
+ fmt += runetochar(fmt, &c);
+ f = flagbits[c];
+ switch(f) {
+ case Fnone:
+ argflag(c, Fverb);
+ f = flagbits[c];
+ break;
+ case Fstar:
+ nstar++;
+ case Fignor:
+ continue;
+ case Fl:
+ if(bset(flag, Fl))
+ flag = bor(flag, blsh(Fvl));
+ }
+ flag = bor(flag, blsh(f));
+ if(f >= Fverb)
+ break;
+ }
+ *fmt = 0;
+ return flag;
+}
+
+void
+newprot(Sym *m, Type *t, char *s)
+{
+ Bits flag;
+ Tprot *l;
+
+ if(t == T) {
+ warn(Z, "%s: newprot: type not defined", m->name);
+ return;
+ }
+ flag = getflag(s);
+ for(l=tprot; l; l=l->link)
+ if(beq(flag, l->flag) && sametype(t, l->type))
+ return;
+ l = alloc(sizeof(*l));
+ l->type = t;
+ l->flag = flag;
+ l->link = tprot;
+ tprot = l;
+}
+
+void
+newname(char *s, int p)
+{
+ Tname *l;
+
+ for(l=tname; l; l=l->link)
+ if(strcmp(l->name, s) == 0) {
+ if(l->param != p)
+ yyerror("vargck %s already defined\n", s);
+ return;
+ }
+ l = alloc(sizeof(*l));
+ l->name = s;
+ l->param = p;
+ l->link = tname;
+ tname = l;
+}
+
+void
+arginit(void)
+{
+ int i;
+
+/* debug['F'] = 1;*/
+/* debug['w'] = 1;*/
+
+ lastadj = Fadj;
+ lastverb = Fverb;
+ indchar = typ(TIND, types[TCHAR]);
+
+ memset(flagbits, Fnone, sizeof(flagbits));
+
+ for(i='0'; i<='9'; i++)
+ argflag(i, Fignor);
+ argflag('.', Fignor);
+ argflag('#', Fignor);
+ argflag('u', Fignor);
+ argflag('+', Fignor);
+ argflag('-', Fignor);
+
+ argflag('*', Fstar);
+ argflag('l', Fl);
+
+ argflag('o', Fverb);
+ flagbits['x'] = flagbits['o'];
+ flagbits['X'] = flagbits['o'];
+}
+
+void
+pragvararg(void)
+{
+ Sym *s;
+ int n, c;
+ char *t;
+ Rune r;
+ Type *ty;
+
+ if(!debug['F'])
+ goto out;
+ s = getsym();
+ if(s && strcmp(s->name, "argpos") == 0)
+ goto ckpos;
+ if(s && strcmp(s->name, "type") == 0)
+ goto cktype;
+ if(s && strcmp(s->name, "flag") == 0)
+ goto ckflag;
+ yyerror("syntax in #pragma varargck");
+ goto out;
+
+ckpos:
+/*#pragma varargck argpos warn 2*/
+ s = getsym();
+ if(s == S)
+ goto bad;
+ n = getnsn();
+ if(n < 0)
+ goto bad;
+ newname(s->name, n);
+ goto out;
+
+ckflag:
+/*#pragma varargck flag 'c'*/
+ c = getnsc();
+ if(c != '\'')
+ goto bad;
+ c = getr();
+ if(c == '\\')
+ c = getr();
+ else if(c == '\'')
+ goto bad;
+ if(c == '\n')
+ goto bad;
+ if(getc() != '\'')
+ goto bad;
+ argflag(c, Fignor);
+ goto out;
+
+cktype:
+/*#pragma varargck type O int*/
+ c = getnsc();
+ if(c != '"')
+ goto bad;
+ t = fmtbuf;
+ for(;;) {
+ r = getr();
+ if(r == ' ' || r == '\n')
+ goto bad;
+ if(r == '"')
+ break;
+ t += runetochar(t, &r);
+ }
+ *t = 0;
+ t = strdup(fmtbuf);
+ s = getsym();
+ if(s == S)
+ goto bad;
+ ty = s->type;
+ while((c = getnsc()) == '*')
+ ty = typ(TIND, ty);
+ unget(c);
+ newprot(s, ty, t);
+ goto out;
+
+bad:
+ yyerror("syntax in #pragma varargck");
+
+out:
+ while(getnsc() != '\n')
+ ;
+}
+
+Node*
+nextarg(Node *n, Node **a)
+{
+ if(n == Z) {
+ *a = Z;
+ return Z;
+ }
+ if(n->op == OLIST) {
+ *a = n->left;
+ return n->right;
+ }
+ *a = n;
+ return Z;
+}
+
+void
+checkargs(Node *nn, char *s, int pos)
+{
+ Node *a, *n;
+ Bits flag;
+ Tprot *l;
+
+ if(!debug['F'])
+ return;
+ n = nn;
+ for(;;) {
+ s = strchr(s, '%');
+ if(s == 0) {
+ nextarg(n, &a);
+ if(a != Z)
+ warn(nn, "more arguments than format %T",
+ a->type);
+ return;
+ }
+ s++;
+ flag = getflag(s);
+ while(nstar > 0) {
+ n = nextarg(n, &a);
+ pos++;
+ nstar--;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ fmtbuf);
+ return;
+ }
+ if(a->type == T)
+ continue;
+ if(!sametype(types[TINT], a->type) &&
+ !sametype(types[TUINT], a->type))
+ warn(nn, "format mismatch '*' in %s %T, arg %d",
+ fmtbuf, a->type, pos);
+ }
+ for(l=tprot; l; l=l->link)
+ if(sametype(types[TVOID], l->type)) {
+ if(beq(flag, l->flag)) {
+ s++;
+ goto loop;
+ }
+ }
+
+ n = nextarg(n, &a);
+ pos++;
+ if(a == Z) {
+ warn(nn, "more format than arguments %s",
+ fmtbuf);
+ return;
+ }
+ if(a->type == 0)
+ continue;
+ for(l=tprot; l; l=l->link)
+ if(sametype(a->type, l->type)) {
+/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
+ if(beq(flag, l->flag))
+ goto loop;
+ }
+ warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
+ loop:;
+ }
+}
+
+void
+dpcheck(Node *n)
+{
+ char *s;
+ Node *a, *b;
+ Tname *l;
+ int i;
+
+ if(n == Z)
+ return;
+ b = n->left;
+ if(b == Z || b->op != ONAME)
+ return;
+ s = b->sym->name;
+ for(l=tname; l; l=l->link)
+ if(strcmp(s, l->name) == 0)
+ break;
+ if(l == 0)
+ return;
+
+ i = l->param;
+ b = n->right;
+ while(i > 0) {
+ b = nextarg(b, &a);
+ i--;
+ }
+ if(a == Z) {
+ warn(n, "cant find format arg");
+ return;
+ }
+ if(!sametype(indchar, a->type)) {
+ warn(n, "format arg type %T", a->type);
+ return;
+ }
+ if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
+/* warn(n, "format arg not constant string");*/
+ return;
+ }
+ s = a->left->cstring;
+ checkargs(b, s, l->param);
+}
+
+void
+pragpack(void)
+{
+ Sym *s;
+
+ packflg = 0;
+ s = getsym();
+ if(s) {
+ packflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ packflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(packflg)
+ print("%4ld: pack %d\n", lineno, packflg);
+ else
+ print("%4ld: pack off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+ Sym *s;
+
+ fproundflg = 0;
+ s = getsym();
+ if(s) {
+ fproundflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ fproundflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(fproundflg)
+ print("%4ld: fproundflg %d\n", lineno, fproundflg);
+ else
+ print("%4ld: fproundflg off\n", lineno);
+}
+
+void
+pragprofile(void)
+{
+ Sym *s;
+
+ profileflg = 0;
+ s = getsym();
+ if(s) {
+ profileflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0)
+ profileflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ if(profileflg)
+ print("%4ld: profileflg %d\n", lineno, profileflg);
+ else
+ print("%4ld: profileflg off\n", lineno);
+}
+
+void
+pragincomplete(void)
+{
+ Sym *s;
+
+ s = getsym();
+ if(s){
+ if(strcmp(s->name, "_off_") == 0)
+ debug['T'] = 0;
+ else if(strcmp(s->name, "_on_") == 0)
+ debug['T'] = 1;
+ else if(s->type == T)
+ diag(Z, "unknown type %s in pragma incomplete", s->name);
+ else
+ s->type->garb |= GINCOMPLETE;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ print("%s incomplete\n", s->name);
+}
diff --git a/utils/cc/funct.c b/utils/cc/funct.c
new file mode 100644
index 00000000..3a236be3
--- /dev/null
+++ b/utils/cc/funct.c
@@ -0,0 +1,400 @@
+#include "cc.h"
+
+typedef struct Ftab Ftab;
+struct Ftab
+{
+ char op;
+ char* name;
+ char typ;
+};
+typedef struct Gtab Gtab;
+struct Gtab
+{
+ char etype;
+ char* name;
+};
+
+Ftab ftabinit[OEND];
+Gtab gtabinit[NTYPE];
+
+int
+isfunct(Node *n)
+{
+ Type *t, *t1;
+ Funct *f;
+ Node *l;
+ Sym *s;
+ int o;
+
+ o = n->op;
+ if(n->left == Z)
+ goto no;
+ t = n->left->type;
+ if(t == T)
+ goto no;
+ f = t->funct;
+
+ switch(o) {
+ case OAS: // put cast on rhs
+ case OASI:
+ case OASADD:
+ case OASAND:
+ case OASASHL:
+ case OASASHR:
+ case OASDIV:
+ case OASLDIV:
+ case OASLMOD:
+ case OASLMUL:
+ case OASLSHR:
+ case OASMOD:
+ case OASMUL:
+ case OASOR:
+ case OASSUB:
+ case OASXOR:
+ if(n->right == Z)
+ goto no;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto no;
+ if(t1->funct == f)
+ break;
+
+ l = new(OXXX, Z, Z);
+ *l = *n->right;
+
+ n->right->left = l;
+ n->right->right = Z;
+ n->right->type = t;
+ n->right->op = OCAST;
+
+ if(!isfunct(n->right))
+ prtree(n, "isfunc !");
+ break;
+
+ case OCAST: // t f(T) or T f(t)
+ t1 = n->type;
+ if(t1 == T)
+ goto no;
+ if(f != nil) {
+ s = f->castfr[t1->etype];
+ if(s == S)
+ goto no;
+ n->right = n->left;
+ goto build;
+ }
+ f = t1->funct;
+ if(f != nil) {
+ s = f->castto[t->etype];
+ if(s == S)
+ goto no;
+ n->right = n->left;
+ goto build;
+ }
+ goto no;
+ }
+
+ if(f == nil)
+ goto no;
+ s = f->sym[o];
+ if(s == S)
+ goto no;
+
+ /*
+ * the answer is yes,
+ * now we rewrite the node
+ * and give diagnostics
+ */
+ switch(o) {
+ default:
+ diag(n, "isfunct op missing %O\n", o);
+ goto bad;
+
+ case OADD: // T f(T, T)
+ case OAND:
+ case OASHL:
+ case OASHR:
+ case ODIV:
+ case OLDIV:
+ case OLMOD:
+ case OLMUL:
+ case OLSHR:
+ case OMOD:
+ case OMUL:
+ case OOR:
+ case OSUB:
+ case OXOR:
+
+ case OEQ: // int f(T, T)
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLE:
+ case OLO:
+ case OLS:
+ case OLT:
+ case ONE:
+ if(n->right == Z)
+ goto bad;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto bad;
+ if(t1->funct != f)
+ goto bad;
+ n->right = new(OLIST, n->left, n->right);
+ break;
+
+ case OAS: // structure copies done by the compiler
+ case OASI:
+ goto no;
+
+ case OASADD: // T f(T*, T)
+ case OASAND:
+ case OASASHL:
+ case OASASHR:
+ case OASDIV:
+ case OASLDIV:
+ case OASLMOD:
+ case OASLMUL:
+ case OASLSHR:
+ case OASMOD:
+ case OASMUL:
+ case OASOR:
+ case OASSUB:
+ case OASXOR:
+ if(n->right == Z)
+ goto bad;
+ t1 = n->right->type;
+ if(t1 == T)
+ goto bad;
+ if(t1->funct != f)
+ goto bad;
+ n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
+ break;
+
+ case OPOS: // T f(T)
+ case ONEG:
+ case ONOT:
+ case OCOM:
+ n->right = n->left;
+ break;
+
+
+ }
+
+build:
+ l = new(ONAME, Z, Z);
+ l->sym = s;
+ l->type = s->type;
+ l->etype = s->type->etype;
+ l->xoffset = s->offset;
+ l->class = s->class;
+ tcomo(l, 0);
+
+ n->op = OFUNC;
+ n->left = l;
+ n->type = l->type->link;
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(tcoma(n->left, n->right, l->type->down, 1))
+ goto bad;
+ return 1;
+
+no:
+ return 0;
+
+bad:
+ diag(n, "cant rewrite typestr for op %O\n", o);
+ prtree(n, "isfunct");
+ n->type = T;
+ return 1;
+}
+
+void
+dclfunct(Type *t, Sym *s)
+{
+ Funct *f;
+ Node *n;
+ Type *f1, *f2, *f3, *f4;
+ int o, i, c;
+ char str[100];
+
+ if(t->funct)
+ return;
+
+ // recognize generated tag of dorm _%d_
+ if(t->tag == S)
+ goto bad;
+ for(i=0; c = t->tag->name[i]; i++) {
+ if(c == '_') {
+ if(i == 0 || t->tag->name[i+1] == 0)
+ continue;
+ break;
+ }
+ if(c < '0' || c > '9')
+ break;
+ }
+ if(c == 0)
+ goto bad;
+
+ f = alloc(sizeof(*f));
+ for(o=0; o<sizeof(f->sym); o++)
+ f->sym[o] = S;
+
+ t->funct = f;
+
+ f1 = typ(TFUNC, t);
+ f1->down = copytyp(t);
+ f1->down->down = t;
+
+ f2 = typ(TFUNC, types[TINT]);
+ f2->down = copytyp(t);
+ f2->down->down = t;
+
+ f3 = typ(TFUNC, t);
+ f3->down = typ(TIND, t);
+ f3->down->down = t;
+
+ f4 = typ(TFUNC, t);
+ f4->down = t;
+
+ for(i=0;; i++) {
+ o = ftabinit[i].op;
+ if(o == OXXX)
+ break;
+ sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->sym[o] = n->sym;
+ switch(ftabinit[i].typ) {
+ default:
+ diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
+ break;
+
+ case 1: // T f(T,T) +
+ dodecl(xdecl, CEXTERN, f1, n);
+ break;
+
+ case 2: // int f(T,T) ==
+ dodecl(xdecl, CEXTERN, f2, n);
+ break;
+
+ case 3: // void f(T*,T) +=
+ dodecl(xdecl, CEXTERN, f3, n);
+ break;
+
+ case 4: // T f(T) ~
+ dodecl(xdecl, CEXTERN, f4, n);
+ break;
+ }
+ }
+ for(i=0;; i++) {
+ o = gtabinit[i].etype;
+ if(o == TXXX)
+ break;
+
+ /*
+ * OCAST types T1 _T2_T1_(T2)
+ */
+ sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->castto[o] = n->sym;
+
+ f1 = typ(TFUNC, t);
+ f1->down = types[o];
+ dodecl(xdecl, CEXTERN, f1, n);
+
+ sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
+ n = new(ONAME, Z, Z);
+ n->sym = slookup(str);
+ f->castfr[o] = n->sym;
+
+ f1 = typ(TFUNC, types[o]);
+ f1->down = t;
+ dodecl(xdecl, CEXTERN, f1, n);
+ }
+ return;
+bad:
+ diag(Z, "dclfunct bad %T %s\n", t, s->name);
+}
+
+Gtab gtabinit[NTYPE] =
+{
+ TCHAR, "c",
+ TUCHAR, "uc",
+ TSHORT, "h",
+ TUSHORT, "uh",
+ TINT, "i",
+ TUINT, "ui",
+ TLONG, "l",
+ TULONG, "ul",
+ TVLONG, "v",
+ TUVLONG, "uv",
+ TFLOAT, "f",
+ TDOUBLE, "d",
+ TXXX
+};
+
+Ftab ftabinit[OEND] =
+{
+ OADD, "add", 1,
+ OAND, "and", 1,
+ OASHL, "ashl", 1,
+ OASHR, "ashr", 1,
+ ODIV, "div", 1,
+ OLDIV, "ldiv", 1,
+ OLMOD, "lmod", 1,
+ OLMUL, "lmul", 1,
+ OLSHR, "lshr", 1,
+ OMOD, "mod", 1,
+ OMUL, "mul", 1,
+ OOR, "or", 1,
+ OSUB, "sub", 1,
+ OXOR, "xor", 1,
+
+ OEQ, "eq", 2,
+ OGE, "ge", 2,
+ OGT, "gt", 2,
+ OHI, "hi", 2,
+ OHS, "hs", 2,
+ OLE, "le", 2,
+ OLO, "lo", 2,
+ OLS, "ls", 2,
+ OLT, "lt", 2,
+ ONE, "ne", 2,
+
+ OASADD, "asadd", 3,
+ OASAND, "asand", 3,
+ OASASHL, "asashl", 3,
+ OASASHR, "asashr", 3,
+ OASDIV, "asdiv", 3,
+ OASLDIV, "asldiv", 3,
+ OASLMOD, "aslmod", 3,
+ OASLMUL, "aslmul", 3,
+ OASLSHR, "aslshr", 3,
+ OASMOD, "asmod", 3,
+ OASMUL, "asmul", 3,
+ OASOR, "asor", 3,
+ OASSUB, "assub", 3,
+ OASXOR, "asxor", 3,
+
+ OPOS, "pos", 4,
+ ONEG, "neg", 4,
+ OCOM, "com", 4,
+ ONOT, "not", 4,
+
+// OPOSTDEC,
+// OPOSTINC,
+// OPREDEC,
+// OPREINC,
+
+ OXXX,
+};
+
+// Node* nodtestv;
+
+// Node* nodvpp;
+// Node* nodppv;
+// Node* nodvmm;
+// Node* nodmmv;
diff --git a/utils/cc/lex.c b/utils/cc/lex.c
new file mode 100644
index 00000000..7a99164b
--- /dev/null
+++ b/utils/cc/lex.c
@@ -0,0 +1,1518 @@
+#include "cc.h"
+#include "y.tab.h"
+
+#ifndef CPP
+#define CPP "/bin/cpp"
+#endif
+
+/*
+ * known debug flags
+ * -o file output file
+ * -D name define
+ * -I path include
+ * -a acid declaration output
+ * -M constant multiplication
+ * -B non ANSI
+ * -A !B
+ * -d print declarations
+ * -t print type trees
+ * -L print every NAME symbol
+ * -i print initialization
+ * -F format specification check
+ * -r print registerization
+ * -v verbose printing
+ * -X abort on error
+ * -w print warnings
+ * -m print add/sub/mul trees
+ * -s print structure offsets (with -a or -aa)
+ * -n print acid to file (%.c=%.acid) (with -a or -aa)
+ * -p use standard cpp ANSI preprocessor (not on windows)
+ * -V enable void* conversion warnings
+ */
+
+void
+main(int argc, char *argv[])
+{
+ char *defs[50], *p;
+ int nproc, nout, status, i, c, ndef;
+
+ memset(debug, 0, sizeof(debug));
+ tinit();
+ cinit();
+ ginit();
+ arginit();
+
+ profileflg = 1; /* #pragma can turn it off */
+ tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+ ndef = 0;
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ defs[ndef++] = p;
+ dodefine(p);
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(argc < 1 && outfile == 0) {
+ print("usage: %cc [-options] files\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't compile multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0) {
+ print("cannot create a process\n");
+ errorexit();
+ }
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ fprint(2, "%s:\n", *argv);
+ if (compile(*argv, defs, ndef))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+
+ if(argc == 0)
+ c = compile("stdin", defs, ndef);
+ else
+ c = compile(argv[0], defs, ndef);
+
+ if(c)
+ errorexit();
+ exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+ char ofile[400], incfile[20];
+ char *p, *av[100], opt[256];
+ int i, c, fd[2];
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ *p++ = 0;
+ if(!debug['.'])
+ include[0] = strdup(ofile);
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile) {
+ if(p = utfrrune(outfile, '.'))
+ if(p[1] == 'c' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ if(debug['a'] && debug['n'])
+ strcat(p, ".acid");
+ else if(debug['Z'] && debug['n'])
+ strcat(p, "_pickle.c");
+ else {
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ }
+ } else
+ outfile = "/dev/null";
+ }
+
+ if(p = getenv("INCLUDE")) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile, "/%s/include", thestring);
+ setinclude(strdup(incfile));
+ setinclude("/sys/include");
+ }
+ }
+ if((debug['a'] || debug['Z']) && !debug['n']) {
+ outfile = 0;
+ Binit(&outbuf, 1, OWRITE);
+ Binit(&diagbuf, 2, OWRITE);
+ } else {
+ c = mycreat(outfile, 0664);
+ if(c < 0) {
+ diag(Z, "cannot open %s", outfile);
+ outfile = 0;
+ errorexit();
+ }
+ Binit(&outbuf, c, OWRITE);
+ Binit(&diagbuf, 1, OWRITE);
+ }
+ newio();
+
+ /* Use an ANSI preprocessor */
+ if(debug['p']) {
+ if(systemtype(Windows)) {
+ diag(Z, "-p option not supported on windows");
+ errorexit();
+ }
+ if(myaccess(file) < 0) {
+ diag(Z, "%s does not exist", file);
+ errorexit();
+ }
+ if(mypipe(fd) < 0) {
+ diag(Z, "pipe failed");
+ errorexit();
+ }
+ switch(myfork()) {
+ case -1:
+ diag(Z, "fork failed");
+ errorexit();
+ case 0:
+ close(fd[0]);
+ mydup(fd[1], 1);
+ close(fd[1]);
+ av[0] = CPP;
+ i = 1;
+ if(debug['+']) {
+ sprint(opt, "-+");
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ndef; c++) {
+ sprint(opt, "-D%s", defs[c]);
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ninclude; c++) {
+ sprint(opt, "-I%s", include[c]);
+ av[i++] = strdup(opt);
+ }
+ if(strcmp(file, "stdin") != 0)
+ av[i++] = file;
+ av[i] = 0;
+ if(debug['p'] > 1) {
+ for(c = 0; c < i; c++)
+ fprint(2, "%s ", av[c]);
+ fprint(2, "\n");
+ }
+ myexec(av[0], av);
+ fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+ errorexit();
+ default:
+ close(fd[1]);
+ newfile(file, fd[0]);
+ break;
+ }
+ } else {
+ if(strcmp(file, "stdin") == 0)
+ newfile(file, 0);
+ else
+ newfile(file, -1);
+ }
+ yyparse();
+ if(!debug['a'] && !debug['Z'])
+ gclean();
+ return nerrors;
+}
+
+void
+errorexit(void)
+{
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ if(debug['e'])
+ print("%L: %s\n", lineno, s);
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%cc: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ ulong h;
+ char *p;
+ int c, n;
+
+ h = 0;
+ for(p=symb; *p;) {
+ h = h * 3;
+ h += *p++;
+ }
+ n = (p - symb) + 1;
+ if((long)h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, symb) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(n);
+ memmove(s->name, symb, n);
+
+ strcpy(s->name, symb);
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+
+ return s;
+}
+
+void
+syminit(Sym *s)
+{
+ s->lexical = LNAME;
+ s->block = 0;
+ s->offset = 0;
+ s->type = T;
+ s->suetag = T;
+ s->class = CXXX;
+ s->aused = 0;
+ s->sig = SIGNONE;
+}
+
+#define EOF (-1)
+#define IGN (-2)
+#define ESC (1<<20)
+#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+ Numdec = 1<<0,
+ Numlong = 1<<1,
+ Numuns = 1<<2,
+ Numvlong = 1<<3,
+ Numflt = 1<<4,
+};
+
+long
+yylex(void)
+{
+ vlong vv;
+ long c, c1, t;
+ char *cp;
+ Rune rune;
+ Sym *s;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c >= Runeself) {
+ /*
+ * extension --
+ * all multibyte runes are alpha
+ */
+ cp = symb;
+ goto talph;
+ }
+ if(isspace(c)) {
+ if(c == '\n')
+ lineno++;
+ goto l0;
+ }
+ if(isalpha(c)) {
+ cp = symb;
+ if(c != 'L')
+ goto talph;
+ *cp++ = c;
+ c = GETC();
+ if(c == '\'') {
+ /* L'x' */
+ c = escchar('\'', 1, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 1, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ yylval.vval = convvtox(c, TUSHORT);
+ return LUCONST;
+ }
+ if(c == '"') {
+ goto caselq;
+ }
+ goto talph;
+ }
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+
+ case EOF:
+ peekc = EOF;
+ return -1;
+
+ case '_':
+ cp = symb;
+ goto talph;
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c1 = GETC();
+ if(isdigit(c1)) {
+ cp = symb;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ strcpy(symb, "\"<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+
+ /* "..." */
+ for(;;) {
+ c = escchar('"', 0, 1);
+ if(c == EOF)
+ break;
+ if(c & ESC) {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = allocn(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LSTRING;
+
+ caselq:
+ /* L"..." */
+ strcpy(symb, "\"L<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+ for(;;) {
+ c = escchar('"', 1, 0);
+ if(c == EOF)
+ break;
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = c;
+ c1 += sizeof(ushort);
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, sizeof(ushort));
+ *(ushort*)(cp + c1) = 0;
+ c1 += sizeof(ushort);
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LLSTRING;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', 0, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 0, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ vv = c;
+ yylval.vval = convvtox(vv, TUCHAR);
+ if(yylval.vval != vv)
+ yyerror("overflow in character constant: 0x%lx", c);
+ else
+ if(c & 0x80){
+ nearln = lineno;
+ warn(Z, "sign-extended character constant");
+ }
+ yylval.vval = convvtox(vv, TCHAR);
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '*') {
+ for(;;) {
+ c = getr();
+ while(c == '*') {
+ c = getr();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ goto l0;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=')
+ return LDVE;
+ break;
+
+ case '*':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMLE;
+ break;
+
+ case '%':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMDE;
+ break;
+
+ case '+':
+ c1 = GETC();
+ if(c1 == '+')
+ return LPP;
+ if(c1 == '=')
+ return LPE;
+ break;
+
+ case '-':
+ c1 = GETC();
+ if(c1 == '-')
+ return LMM;
+ if(c1 == '=')
+ return LME;
+ if(c1 == '>')
+ return LMG;
+ break;
+
+ case '>':
+ c1 = GETC();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LRSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LGE;
+ break;
+
+ case '<':
+ c1 = GETC();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LLSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LLE;
+ break;
+
+ case '=':
+ c1 = GETC();
+ if(c1 == '=')
+ return LEQ;
+ break;
+
+ case '!':
+ c1 = GETC();
+ if(c1 == '=')
+ return LNE;
+ break;
+
+ case '&':
+ c1 = GETC();
+ if(c1 == '&')
+ return LANDAND;
+ if(c1 == '=')
+ return LANDE;
+ break;
+
+ case '|':
+ c1 = GETC();
+ if(c1 == '|')
+ return LOROR;
+ if(c1 == '=')
+ return LORE;
+ break;
+
+ case '^':
+ c1 = GETC();
+ if(c1 == '=')
+ return LXORE;
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+
+talph:
+ /*
+ * cp is set to symb and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = GETC();
+ }
+ cp += c1;
+ c = GETC();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ *cp = 0;
+ if(debug['L'])
+ print("%L: %s\n", lineno, symb);
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ yylval.sym = s;
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ return LTYPE;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = symb;
+ if(c != '0') {
+ c1 |= Numdec;
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = GETC();
+ if(c == 'x' || c == 'X')
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == symb+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ if(c < '0' || c > '7')
+ goto dc;
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = GETC();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+ c = GETC();
+ c1 |= Numuns;
+ goto ncu;
+ }
+ if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+ c = GETC();
+ if(c1 & Numlong)
+ c1 |= Numvlong;
+ c1 |= Numlong;
+ goto ncu;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatov(symb, &yylval.vval))
+ yyerror("overflow in constant");
+
+ vv = yylval.vval;
+ if(c1 & Numvlong) {
+ if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
+ c = LUVLCONST;
+ t = TUVLONG;
+ goto nret;
+ }
+ c = LVLCONST;
+ t = TVLONG;
+ goto nret;
+ }
+ if(c1 & Numlong) {
+ if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
+ c = LULCONST;
+ t = TULONG;
+ goto nret;
+ }
+ c = LLCONST;
+ t = TLONG;
+ goto nret;
+ }
+ if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
+ c = LUCONST;
+ t = TUINT;
+ goto nret;
+ }
+ c = LCONST;
+ t = TINT;
+ goto nret;
+
+nret:
+ yylval.vval = convvtox(vv, t);
+ if(yylval.vval != vv){
+ nearln = lineno;
+ warn(Z, "truncated constant: %T %s", types[t], symb);
+ }
+ return c;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+caseout:
+ if(c == 'L' || c == 'l') {
+ c = GETC();
+ c1 |= Numlong;
+ } else
+ if(c == 'F' || c == 'f') {
+ c = GETC();
+ c1 |= Numflt;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatof(symb, &yylval.dval)) {
+ yyerror("overflow in float constant");
+ yylval.dval = 0;
+ }
+ if(c1 & Numflt)
+ return LFCONST;
+ return LDCONST;
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+long
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ nearln = lineno;
+ diag(Z, "illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ for(;;) {
+ if(!isspace(c))
+ return c;
+ if(c == '\n') {
+ lineno++;
+ return c;
+ }
+ c = GETC();
+ }
+ return 0;
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+long
+escchar(long e, int longflg, int escflg)
+{
+ long c, l;
+ int i;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ if(c == 'x') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 2 hex
+ */
+ i = 2;
+ if(longflg)
+ i = 4;
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ unget(c);
+ break;
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ if(c >= '0' && c <= '7') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 3 oct
+ */
+ i = 2;
+ if(longflg)
+ i = 5;
+ l = c - '0';
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ unget(c);
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return '\a';
+ case 'v': return '\v';
+ }
+ return c;
+}
+
+struct
+{
+ char *name;
+ ushort lexical;
+ ushort type;
+} itab[] =
+{
+ "auto", LAUTO, 0,
+ "break", LBREAK, 0,
+ "case", LCASE, 0,
+ "char", LCHAR, TCHAR,
+ "const", LCONSTNT, 0,
+ "continue", LCONTINUE, 0,
+ "default", LDEFAULT, 0,
+ "do", LDO, 0,
+ "double", LDOUBLE, TDOUBLE,
+ "else", LELSE, 0,
+ "enum", LENUM, 0,
+ "extern", LEXTERN, 0,
+ "float", LFLOAT, TFLOAT,
+ "for", LFOR, 0,
+ "goto", LGOTO, 0,
+ "if", LIF, 0,
+ "int", LINT, TINT,
+ "long", LLONG, TLONG,
+ "register", LREGISTER, 0,
+ "return", LRETURN, 0,
+ "SET", LSET, 0,
+ "short", LSHORT, TSHORT,
+ "signed", LSIGNED, 0,
+ "signof", LSIGNOF, 0,
+ "sizeof", LSIZEOF, 0,
+ "static", LSTATIC, 0,
+ "struct", LSTRUCT, 0,
+ "switch", LSWITCH, 0,
+ "typedef", LTYPEDEF, 0,
+ "typestr", LTYPESTR, 0,
+ "union", LUNION, 0,
+ "unsigned", LUNSIGNED, 0,
+ "USED", LUSED, 0,
+ "void", LVOID, TVOID,
+ "volatile", LVOLATILE, 0,
+ "while", LWHILE, 0,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+ Type *t;
+
+ nerrors = 0;
+ lineno = 1;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+
+ types[TXXX] = T;
+ types[TCHAR] = typ(TCHAR, T);
+ types[TUCHAR] = typ(TUCHAR, T);
+ types[TSHORT] = typ(TSHORT, T);
+ types[TUSHORT] = typ(TUSHORT, T);
+ types[TINT] = typ(TINT, T);
+ types[TUINT] = typ(TUINT, T);
+ types[TLONG] = typ(TLONG, T);
+ types[TULONG] = typ(TULONG, T);
+ types[TVLONG] = typ(TVLONG, T);
+ types[TUVLONG] = typ(TUVLONG, T);
+ types[TFLOAT] = typ(TFLOAT, T);
+ types[TDOUBLE] = typ(TDOUBLE, T);
+ types[TVOID] = typ(TVOID, T);
+ types[TENUM] = typ(TENUM, T);
+ types[TFUNC] = typ(TFUNC, types[TINT]);
+ types[TIND] = typ(TIND, types[TVOID]);
+
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->lexical = itab[i].lexical;
+ if(itab[i].type != 0)
+ s->type = types[itab[i].type];
+ }
+ blockno = 0;
+ autobn = 0;
+ autoffset = 0;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+ symstring = slookup(".string");
+ symstring->class = CSTATIC;
+ symstring->type = t;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+
+ nodproto = new(OPROTO, Z, Z);
+ dclstack = D;
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+
+ fmtinstall('O', Oconv);
+ fmtinstall('T', Tconv);
+ fmtinstall('F', FNconv);
+ fmtinstall('L', Lconv);
+ fmtinstall('Q', Qconv);
+ fmtinstall('|', VBconv);
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0] & 0xff;
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+ int a;
+
+ a = va_arg(fp->args, int);
+ if(a < OXXX || a > OEND)
+ return fmtprint(fp, "***badO %d***", a);
+
+ return fmtstrcpy(fp, onames[a]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Hist *h;
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ long idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ long ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ long l, d;
+ int i, n;
+
+ l = va_arg(fp->args, long);
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset != 0) { /* #line directive, not #pragma */
+ if(n > 0 && n < HISTSZ && h->offset >= 0) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ if(n < HISTSZ) { /* beginning of file */
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ str[0] = 0;
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
+ break;
+ strcat(str, " ");
+ }
+ if(a[i].line)
+ snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+ a[i].line->name, l-a[i].ldel+1,
+ a[i].incl->name, l-a[i].idel+1);
+ else
+ snprint(s, STRINGSZ, "%s:%ld",
+ a[i].incl->name, l-a[i].idel+1);
+ if(strlen(s)+strlen(str) >= STRINGSZ-10)
+ break;
+ strcat(str, s);
+ l = a[i].incl->line - 1; /* now print out start of this file */
+ }
+ if(n == 0)
+ strcat(str, "<eof>");
+ return fmtstrcpy(fp, str);
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], s[STRINGSZ+20];
+ Type *t, *t1;
+ int et;
+ long n;
+
+ str[0] = 0;
+ for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+ et = t->etype;
+ if(str[0])
+ strcat(str, " ");
+ if(t->garb&~GINCOMPLETE) {
+ sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ sprint(s, "%s", tnames[et]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ if(et == TFUNC && (t1 = t->down)) {
+ sprint(s, "(%T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ while(t1 = t1->down) {
+ sprint(s, ", %T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, ")");
+ }
+ if(et == TARRAY) {
+ n = t->width;
+ if(t->link && t->link->width)
+ n /= t->link->width;
+ sprint(s, "[%ld]", n);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(t->nbits) {
+ sprint(s, " %d:%d", t->shift, t->nbits);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(typesu[et]) {
+ if(t->tag) {
+ strcat(str, " ");
+ if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+ strcat(str, t->tag->name);
+ } else
+ strcat(str, " {}");
+ break;
+ }
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+FNconv(Fmt *fp)
+{
+ char *str;
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ str = "<indirect>";
+ if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+ str = n->sym->name;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Qconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], *s;
+ long b;
+ int i;
+
+ str[0] = 0;
+ for(b = va_arg(fp->args, long); b;) {
+ i = bitno(b);
+ if(str[0])
+ strcat(str, " ");
+ s = qnames[i];
+ if(strlen(str) + strlen(s) >= STRINGSZ)
+ break;
+ strcat(str, s);
+ b &= ~(1L << i);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+VBconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int i, n, t, pc;
+
+ n = va_arg(fp->args, int);
+ pc = 0; /* BUG: was printcol */
+ i = 0;
+ while(pc < n) {
+ t = (pc+4) & ~3;
+ if(t <= n) {
+ str[i++] = '\t';
+ pc = t;
+ continue;
+ }
+ str[i++] = ' ';
+ pc++;
+ }
+ str[i] = 0;
+
+ return fmtstrcpy(fp, str);
+}
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((uintptr)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+ char *e;
+
+ while(*p != 0) {
+ e = strchr(p, ' ');
+ if(e != 0)
+ *e = '\0';
+
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ break;
+
+ if(i >= ninclude)
+ include[ninclude++] = p;
+
+ if(ninclude > nelem(include)) {
+ diag(Z, "ninclude too small %d", nelem(include));
+ exits("ninclude");
+ }
+
+ if(e == 0)
+ break;
+ p = e+1;
+ }
+}
diff --git a/utils/cc/lexbody b/utils/cc/lexbody
new file mode 100644
index 00000000..d8e3f6eb
--- /dev/null
+++ b/utils/cc/lexbody
@@ -0,0 +1,688 @@
+/*
+ * common code for all the assemblers
+ */
+
+void
+pragpack(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragvararg(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragfpround(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragprofile(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
+pragincomplete(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((uintptr)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+
+ if(p == 0)
+ return;
+ for(i=1; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ return;
+
+ if(ninclude >= nelem(include)) {
+ yyerror("ninclude too small %d", nelem(include));
+ exits("ninclude");
+ }
+ include[ninclude++] = p;
+}
+
+void
+errorexit(void)
+{
+
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%ca: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ long h;
+ char *p;
+ int c, l;
+
+ h = 0;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+ return s;
+}
+
+long
+yylex(void)
+{
+ int c, c1;
+ char *cp;
+ Sym *s;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c == EOF) {
+ peekc = EOF;
+ return -1;
+ }
+ if(isspace(c)) {
+ if(c == '\n') {
+ lineno++;
+ return ';';
+ }
+ goto l0;
+ }
+ if(isalpha(c))
+ goto talph;
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+ case '\n':
+ lineno++;
+ return ';';
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c = GETC();
+ if(isalpha(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto aloop;
+ }
+ if(isdigit(c)) {
+ cp = symb;
+ *cp++ = '.';
+ goto casedot;
+ }
+ peekc = c;
+ return '.';
+
+ talph:
+ case '_':
+ case '@':
+ cp = symb;
+
+ aloop:
+ *cp++ = c;
+ c = GETC();
+ if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
+ goto aloop;
+ *cp = 0;
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ if(s->type == 0)
+ s->type = LNAME;
+ if(s->type == LNAME ||
+ s->type == LVAR ||
+ s->type == LLAB) {
+ yylval.sym = s;
+ return s->type;
+ }
+ yylval.lval = s->value;
+ return s->type;
+
+ tnum:
+ cp = symb;
+ if(c != '0')
+ goto dc;
+ *cp++ = c;
+ c = GETC();
+ c1 = 3;
+ if(c == 'x' || c == 'X') {
+ c1 = 4;
+ c = GETC();
+ } else
+ if(c < '0' || c > '7')
+ goto dc;
+ yylval.lval = 0;
+ for(;;) {
+ if(c >= '0' && c <= '9') {
+ if(c > '7' && c1 == 3)
+ break;
+ yylval.lval <<= c1;
+ yylval.lval += c - '0';
+ c = GETC();
+ continue;
+ }
+ if(c1 == 3)
+ break;
+ if(c >= 'A' && c <= 'F')
+ c += 'a' - 'A';
+ if(c >= 'a' && c <= 'f') {
+ yylval.lval <<= c1;
+ yylval.lval += c - 'a' + 10;
+ c = GETC();
+ continue;
+ }
+ break;
+ }
+ goto ncu;
+
+ dc:
+ for(;;) {
+ if(!isdigit(c))
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+ *cp = 0;
+ if(sizeof(yylval.lval) == sizeof(vlong))
+ yylval.lval = strtoll(symb, nil, 10);
+ else
+ yylval.lval = strtol(symb, nil, 10);
+
+ ncu:
+ while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
+ c = GETC();
+ peekc = c;
+ return LCONST;
+
+ casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c == 'e' || c == 'E')
+ goto casee;
+ goto caseout;
+
+ casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+ caseout:
+ *cp = 0;
+ peekc = c;
+ if(FPCHIP) {
+ yylval.dval = atof(symb);
+ return LFCONST;
+ }
+ yyerror("assembler cannot interpret fp constants");
+ yylval.lval = 1L;
+ return LCONST;
+
+ case '"':
+ memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
+ cp = yylval.sval;
+ c1 = 0;
+ for(;;) {
+ c = escchar('"');
+ if(c == EOF)
+ break;
+ if(c1 < sizeof(yylval.sval))
+ *cp++ = c;
+ c1++;
+ }
+ if(c1 > sizeof(yylval.sval))
+ yyerror("string constant too long");
+ return LSCONST;
+
+ case '\'':
+ c = escchar('\'');
+ if(c == EOF)
+ c = '\'';
+ if(escchar('\'') != EOF)
+ yyerror("missing '");
+ yylval.lval = c;
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '/') {
+ for(;;) {
+ c = GETC();
+ if(c == '\n') {
+ lineno++;
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '*') {
+ for(;;) {
+ c = GETC();
+ while(c == '*') {
+ c = GETC();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ if(c == '\n')
+ lineno++;
+ }
+ }
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = peekc;
+ if(c != IGN) {
+ peekc = IGN;
+ return c;
+ }
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ for(;;) {
+ c = getc();
+ if(!isspace(c) || c == '\n')
+ return c;
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+int
+escchar(int e)
+{
+ int c, l;
+
+loop:
+ c = getc();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ return EOF;
+ return c;
+ }
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = c - '0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ return l;
+ }
+ }
+ peekc = c;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return 0x07;
+ case 'v': return 0x0b;
+ case 'z': return 0x00;
+ }
+ return c;
+}
+
+void
+pinit(char *f)
+{
+ int i;
+ Sym *s;
+
+ lineno = 1;
+ newio();
+ newfile(f, -1);
+ pc = 0;
+ peekc = IGN;
+ sym = 1;
+ for(i=0; i<NSYM; i++) {
+ h[i].type = 0;
+ h[i].sym = S;
+ }
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ s->macro = 0;
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0];
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++;
+}
+
+void
+yyerror(char *a, ...)
+{
+ char buf[200];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(a, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ prfile(lineno);
+ va_start(arg, a);
+ vseprint(buf, buf+sizeof(buf), a, arg);
+ va_end(arg);
+ print("%s\n", buf);
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
+
+void
+prfile(long l)
+{
+ int i, n;
+ Hist a[HISTSZ], *h;
+ long d;
+
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset == 0) {
+ if(n >= 0 && n < HISTSZ)
+ a[n] = *h;
+ n++;
+ continue;
+ }
+ if(n > 0 && n < HISTSZ)
+ if(a[n-1].offset == 0) {
+ a[n] = *h;
+ n++;
+ } else
+ a[n-1] = *h;
+ continue;
+ }
+ n--;
+ if(n >= 0 && n < HISTSZ) {
+ d = h->line - a[n].line;
+ for(i=0; i<n; i++)
+ a[i].line += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ for(i=0; i<n; i++)
+ print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
diff --git a/utils/cc/mac.c b/utils/cc/mac.c
new file mode 100644
index 00000000..7ec6e393
--- /dev/null
+++ b/utils/cc/mac.c
@@ -0,0 +1,3 @@
+#include "cc.h"
+
+#include "macbody"
diff --git a/utils/cc/macbody b/utils/cc/macbody
new file mode 100644
index 00000000..91181875
--- /dev/null
+++ b/utils/cc/macbody
@@ -0,0 +1,822 @@
+
+long
+getnsn(void)
+{
+ long n;
+ int c;
+
+ c = getnsc();
+ if(c < '0' || c > '9')
+ return -1;
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + c-'0';
+ c = getc();
+ }
+ unget(c);
+ return n;
+}
+
+Sym*
+getsym(void)
+{
+ int c;
+ char *cp;
+
+ c = getnsc();
+ if(!isalpha(c) && c != '_') {
+ unget(c);
+ return S;
+ }
+ for(cp = symb;;) {
+ if(cp <= symb+NSYMB-4)
+ *cp++ = c;
+ c = getc();
+ if(isalnum(c) || c == '_')
+ continue;
+ unget(c);
+ break;
+ }
+ *cp = 0;
+ if(cp > symb+NSYMB-4)
+ yyerror("symbol too large: %s", symb);
+ return lookup();
+}
+
+int
+getcom(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c != '/')
+ break;
+ c = getc();
+ if(c == '/') {
+ while(c != '\n')
+ c = getc();
+ break;
+ }
+ if(c != '*')
+ break;
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment across newline");
+ break;
+ }
+ c = getc();
+ }
+ if(c == '\n')
+ break;
+ }
+ return c;
+}
+
+void
+dodefine(char *cp)
+{
+ Sym *s;
+ char *p;
+ long l;
+
+ strcpy(symb, cp);
+ p = strchr(symb, '=');
+ if(p) {
+ *p++ = 0;
+ s = lookup();
+ l = strlen(p) + 2; /* +1 null, +1 nargs */
+ while(l & 3)
+ l++;
+ while(nhunk < l)
+ gethunk();
+ *hunk = 0;
+ strcpy(hunk+1, p);
+ s->macro = hunk;
+ hunk += l;
+ nhunk -= l;
+ } else {
+ s = lookup();
+ s->macro = "\0001"; /* \000 is nargs */
+ }
+ if(debug['m'])
+ print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+ char *macname;
+ void (*macf)(void);
+} mactab[] =
+{
+ "ifdef", 0, /* macif(0) */
+ "ifndef", 0, /* macif(1) */
+ "else", 0, /* macif(2) */
+
+ "line", maclin,
+ "define", macdef,
+ "include", macinc,
+ "undef", macund,
+
+ "pragma", macprag,
+ "endif", macend,
+ 0
+};
+
+void
+domacro(void)
+{
+ int i;
+ Sym *s;
+
+ s = getsym();
+ if(s == S)
+ s = slookup("endif");
+ for(i=0; mactab[i].macname; i++)
+ if(strcmp(s->name, mactab[i].macname) == 0) {
+ if(mactab[i].macf)
+ (*mactab[i].macf)();
+ else
+ macif(i);
+ return;
+ }
+ yyerror("unknown #: %s", s->name);
+ macend();
+}
+
+void
+macund(void)
+{
+ Sym *s;
+
+ s = getsym();
+ macend();
+ if(s == S) {
+ yyerror("syntax in #undef");
+ return;
+ }
+ s->macro = 0;
+}
+
+#define NARG 25
+void
+macdef(void)
+{
+ Sym *s, *a;
+ char *args[NARG], *np, *base;
+ int n, i, c, len;
+ int ischr;
+
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(s->macro)
+ yyerror("macro redefined: %s", s->name);
+ c = getc();
+ n = -1;
+ if(c == '(') {
+ n++;
+ c = getnsc();
+ if(c != ')') {
+ unget(c);
+ for(;;) {
+ a = getsym();
+ if(a == S)
+ goto bad;
+ if(n >= NARG) {
+ yyerror("too many arguments in #define: %s", s->name);
+ goto bad;
+ }
+ args[n++] = a->name;
+ c = getnsc();
+ if(c == ')')
+ break;
+ if(c != ',')
+ goto bad;
+ }
+ }
+ c = getc();
+ }
+ if(isspace(c))
+ if(c != '\n')
+ c = getnsc();
+ base = hunk;
+ len = 1;
+ ischr = 0;
+ for(;;) {
+ if(isalpha(c) || c == '_') {
+ np = symb;
+ *np++ = c;
+ c = getc();
+ while(isalnum(c) || c == '_') {
+ *np++ = c;
+ c = getc();
+ }
+ *np = 0;
+ for(i=0; i<n; i++)
+ if(strcmp(symb, args[i]) == 0)
+ break;
+ if(i >= n) {
+ i = strlen(symb);
+ base = allocn(base, len, i);
+ memcpy(base+len, symb, i);
+ len += i;
+ continue;
+ }
+ base = allocn(base, len, 2);
+ base[len++] = '#';
+ base[len++] = 'a' + i;
+ continue;
+ }
+ if(ischr){
+ if(c == '\\'){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = getc();
+ }else if(c == ischr)
+ ischr = 0;
+ }else{
+ if(c == '"' || c == '\''){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ ischr = c;
+ c = getc();
+ continue;
+ }
+ if(c == '/') {
+ c = getc();
+ if(c == '/'){
+ c = getc();
+ for(;;) {
+ if(c == '\n')
+ break;
+ c = getc();
+ }
+ continue;
+ }
+ if(c == '*'){
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment and newline in define: %s", s->name);
+ break;
+ }
+ c = getc();
+ }
+ continue;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '/';
+ continue;
+ }
+ }
+ if(c == '\\') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ else if(c == '\r') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '\\';
+ continue;
+ }
+ if(c == '\n')
+ break;
+ if(c == '#')
+ if(n > 0) {
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+ if(c == '\n')
+ lineno++;
+ if(c == -1) {
+ yyerror("eof in a macro: %s", s->name);
+ break;
+ }
+ }
+ do {
+ base = allocn(base, len, 1);
+ base[len++] = 0;
+ } while(len & 3);
+
+ *base = n+1;
+ s->macro = base;
+ if(debug['m'])
+ print("#define %s %s\n", s->name, s->macro+1);
+ return;
+
+bad:
+ if(s == S)
+ yyerror("syntax in #define");
+ else
+ yyerror("syntax in #define: %s", s->name);
+ macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+ char buf[2000];
+ int n, l, c, nargs;
+ char *arg[NARG], *cp, *ob, *ecp;
+
+ ob = b;
+ nargs = *s->macro - 1;
+ if(nargs < 0) {
+ strcpy(b, s->macro+1);
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+ }
+ c = getnsc();
+ if(c != '(')
+ goto bad;
+ n = 0;
+ c = getc();
+ if(c != ')') {
+ unget(c);
+ l = 0;
+ cp = buf;
+ ecp = cp + sizeof(buf)-4;
+ arg[n++] = cp;
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ c = getc();
+ if(c == '"')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ }
+ if(c == '\'')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '\'')
+ break;
+ }
+ if(c == '/') {
+ c = getc();
+ switch(c) {
+ case '*':
+ for(;;) {
+ c = getc();
+ if(c == '*') {
+ c = getc();
+ if(c == '/')
+ break;
+ }
+ }
+ *cp++ = ' ';
+ continue;
+ case '/':
+ while((c = getc()) != '\n')
+ ;
+ break;
+ default:
+ unget(c);
+ c = '/';
+ }
+ }
+ if(l == 0) {
+ if(c == ',') {
+ *cp++ = 0;
+ arg[n++] = cp;
+ if(n > nargs)
+ break;
+ continue;
+ }
+ if(c == ')')
+ break;
+ }
+ if(c == '\n')
+ c = ' ';
+ *cp++ = c;
+ if(c == '(')
+ l++;
+ if(c == ')')
+ l--;
+ }
+ *cp = 0;
+ }
+ if(n != nargs) {
+ yyerror("argument mismatch expanding: %s", s->name);
+ *b = 0;
+ return;
+ }
+ cp = s->macro+1;
+ for(;;) {
+ c = *cp++;
+ if(c != '#') {
+ *b++ = c;
+ if(c == 0)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if(c == 0)
+ goto bad;
+ if(c == '#') {
+ *b++ = c;
+ continue;
+ }
+ c -= 'a';
+ if(c < 0 || c >= n)
+ continue;
+ strcpy(b, arg[c]);
+ b += strlen(arg[c]);
+ }
+ *b = 0;
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+
+bad:
+ yyerror("syntax in macro expansion: %s", s->name);
+ *b = 0;
+ return;
+
+toobig:
+ yyerror("too much text in macro expansion: %s", s->name);
+ *b = 0;
+}
+
+void
+macinc(void)
+{
+ int c0, c, i, f;
+ char str[STRINGSZ], *hp;
+
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = str;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ f = -1;
+ for(i=0; i<ninclude; i++) {
+ if(i == 0 && c0 == '>')
+ continue;
+ strcpy(symb, include[i]);
+ strcat(symb, "/");
+ if(strcmp(symb, "./") == 0)
+ symb[0] = 0;
+ strcat(symb, str);
+ f = open(symb, 0);
+ if(f >= 0)
+ break;
+ }
+ if(f < 0)
+ strcpy(symb, str);
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ hp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += c;
+ newio();
+ pushio();
+ newfile(hp, f);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #include");
+ macend();
+}
+
+void
+maclin(void)
+{
+ char *cp;
+ int c;
+ long n;
+
+ n = getnsn();
+ c = getc();
+ if(n < 0)
+ goto bad;
+
+ for(;;) {
+ if(c == ' ' || c == '\t') {
+ c = getc();
+ continue;
+ }
+ if(c == '"')
+ break;
+ if(c == '\n') {
+ strcpy(symb, "<noname>");
+ goto nn;
+ }
+ goto bad;
+ }
+ cp = symb;
+ for(;;) {
+ c = getc();
+ if(c == '"')
+ break;
+ *cp++ = c;
+ }
+ *cp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+nn:
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ cp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += c;
+ linehist(cp, n);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #line");
+ macend();
+}
+
+void
+macif(int f)
+{
+ int c, l, bol;
+ Sym *s;
+
+ if(f == 2)
+ goto skip;
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(getcom() != '\n')
+ goto bad;
+ if((s->macro != 0) ^ f)
+ return;
+
+skip:
+ bol = 1;
+ l = 0;
+ for(;;) {
+ c = getc();
+ if(c != '#') {
+ if(!isspace(c))
+ bol = 0;
+ if(c == '\n')
+ bol = 1;
+ continue;
+ }
+ if(!bol)
+ continue;
+ s = getsym();
+ if(s == S)
+ continue;
+ if(strcmp(s->name, "endif") == 0) {
+ if(l) {
+ l--;
+ continue;
+ }
+ macend();
+ return;
+ }
+ if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+ l++;
+ continue;
+ }
+ if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+ macend();
+ return;
+ }
+ }
+
+bad:
+ yyerror("syntax in #if(n)def");
+ macend();
+}
+
+void
+macprag(void)
+{
+ Sym *s;
+ int c0, c;
+ char *hp;
+ Hist *h;
+
+ s = getsym();
+
+ if(s && strcmp(s->name, "lib") == 0)
+ goto praglib;
+ if(s && strcmp(s->name, "pack") == 0) {
+ pragpack();
+ return;
+ }
+ if(s && strcmp(s->name, "fpround") == 0) {
+ pragfpround();
+ return;
+ }
+ if(s && strcmp(s->name, "profile") == 0) {
+ pragprofile();
+ return;
+ }
+ if(s && strcmp(s->name, "varargck") == 0) {
+ pragvararg();
+ return;
+ }
+ if(s && strcmp(s->name, "incomplete") == 0) {
+ pragincomplete();
+ return;
+ }
+ while(getnsc() != '\n')
+ ;
+ return;
+
+praglib:
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = symb;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ /*
+ * put pragma-line in as a funny history
+ */
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ hp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += c;
+
+ h = alloc(sizeof(Hist));
+ h->name = hp;
+ h->line = lineno;
+ h->offset = -1;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #pragma lib");
+ macend();
+}
+
+void
+macend(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c < 0 || c == '\n')
+ return;
+ }
+}
+
+void
+linehist(char *f, int offset)
+{
+ Hist *h;
+
+ /*
+ * overwrite the last #line directive if
+ * no alloc has happened since the last one
+ */
+ if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
+ if(f && ehist->name && strcmp(f, ehist->name) == 0) {
+ ehist->line = lineno;
+ ehist->offset = offset;
+ return;
+ }
+
+ if(debug['f'])
+ if(f) {
+ if(offset)
+ print("%4ld: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4ld: %s\n", lineno, f);
+ } else
+ print("%4ld: <pop>\n", lineno);
+ newflag = 0;
+
+ h = alloc(sizeof(Hist));
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 10L*NHUNK)
+ nh = 10L*NHUNK;
+ h = (char*)mysbrk(nh);
+ if(h == (char*)-1) {
+ yyerror("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
diff --git a/utils/cc/machcap.c b/utils/cc/machcap.c
new file mode 100644
index 00000000..06b5684a
--- /dev/null
+++ b/utils/cc/machcap.c
@@ -0,0 +1,9 @@
+#include "cc.h"
+
+/* default, like old cc */
+int
+machcap(Node *n)
+{
+ USED(n);
+ return 0;
+}
diff --git a/utils/cc/mkfile b/utils/cc/mkfile
new file mode 100644
index 00000000..c2df13a5
--- /dev/null
+++ b/utils/cc/mkfile
@@ -0,0 +1,35 @@
+<../../mkconfig
+
+LIB=libcc.a
+
+OFILES=\
+ acid.$O\
+ bits.$O\
+ com.$O\
+ com64.$O\
+ $TARGMODEL.$O\
+ dcl.$O\
+ dpchk.$O\
+ funct.$O\
+ lex.$O\
+ mac.$O\
+ mpatof.$O\
+ pickle.$O\
+ scon.$O\
+ sub.$O\
+ y.tab.$O\
+ machcap.$O\
+
+HFILES=cc.h\
+ y.tab.h\
+
+YFILES=cc.y\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+mac.$O: macbody
+
+lex.$O: lex.c
+ $CC $CFLAGS '-DCPP="/bin/cpp"' lex.c
diff --git a/utils/cc/mpatof.c b/utils/cc/mpatof.c
new file mode 100644
index 00000000..a59164b7
--- /dev/null
+++ b/utils/cc/mpatof.c
@@ -0,0 +1,271 @@
+#include "cc.h"
+
+enum
+{
+ Mpscale = 29, /* safely smaller than bits in a long */
+ Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
+ Mpbase = 1L<<Mpscale,
+};
+
+typedef
+struct
+{
+ long a[Mpprec];
+ char ovf;
+} Mp;
+
+int mpatof(char*, double*);
+int mpatov(char *s, vlong *v);
+void mpint(Mp*, int);
+void mppow(Mp*, int, int);
+void mpmul(Mp*, int);
+void mpadd(Mp*, Mp*);
+int mptof(Mp*, double*);
+
+/*
+ * convert a string, s, to floating in *d
+ * return conversion overflow.
+ * required syntax is [+-]d*[.]d*[e[+-]d*]
+ */
+int
+mpatof(char *s, double *d)
+{
+ Mp a, b;
+ int dp, c, f, ef, ex, zer;
+ double d1, d2;
+
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ zer = 1; /* zero */
+ memset(&a, 0, sizeof(a));
+ for(;;) {
+ switch(c = *s++) {
+ default:
+ goto bad;
+ case '-':
+ f = 1;
+ case ' ':
+ case '\t':
+ case '+':
+ continue;
+ case '.':
+ dp = 1;
+ continue;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ zer = 0;
+ case '0':
+ mpint(&b, c-'0');
+ mpmul(&a, 10);
+ mpadd(&a, &b);
+ if(dp)
+ dp++;
+ continue;
+ case 'E':
+ case 'e':
+ ex = 0;
+ ef = 0;
+ for(;;) {
+ c = *s++;
+ if(c == '+' || c == ' ' || c == '\t')
+ continue;
+ if(c == '-') {
+ ef = 1;
+ continue;
+ }
+ if(c >= '0' && c <= '9') {
+ ex = ex*10 + (c-'0');
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+ case 0:
+ break;
+ }
+ break;
+ }
+ if(a.ovf)
+ goto bad;
+ if(zer) {
+ *d = 0;
+ return 0;
+ }
+ if(dp)
+ dp--;
+ dp -= ex;
+ if(dp > 0) {
+ /*
+ * must divide by 10**dp
+ */
+ if(mptof(&a, &d1))
+ goto bad;
+
+ /*
+ * trial exponent of 8**dp
+ * 8 (being between 5 and 10)
+ * should pick up all underflows
+ * in the division of 5**dp.
+ */
+ d2 = frexp(d1, &ex);
+ d2 = ldexp(d2, ex-3*dp);
+ if(d2 == 0)
+ goto bad;
+
+ /*
+ * decompose each 10 into 5*2.
+ * create 5**dp in fixed point
+ * and then play with the exponent
+ * for the remaining 2**dp.
+ * note that 5**dp will overflow
+ * with as few as 134 input digits.
+ */
+ mpint(&a, 1);
+ mppow(&a, 5, dp);
+ if(mptof(&a, &d2))
+ goto bad;
+ d1 = frexp(d1/d2, &ex);
+ d1 = ldexp(d1, ex-dp);
+ if(d1 == 0)
+ goto bad;
+ } else {
+ /*
+ * must multiply by 10**|dp| --
+ * just do it in fixed point.
+ */
+ mppow(&a, 10, -dp);
+ if(mptof(&a, &d1))
+ goto bad;
+ }
+ if(f)
+ d1 = -d1;
+ *d = d1;
+ return 0;
+
+bad:
+ return 1;
+}
+
+/*
+ * convert a to floating in *d
+ * return conversion overflow
+ */
+int
+mptof(Mp *a, double *d)
+{
+ double f, g;
+ long x, *a1;
+ int i;
+
+ if(a->ovf)
+ return 1;
+ a1 = a->a;
+ f = ldexp(*a1++, 0);
+ for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
+ if(x = *a1++) {
+ g = ldexp(x, i);
+ /*
+ * NOTE: the test (g==0) is plan9
+ * specific. ansi compliant overflow
+ * is signaled by HUGE and errno==ERANGE.
+ * change this for your particular ldexp.
+ */
+ if(g == 0)
+ return 1;
+ f += g; /* this could bomb! */
+ }
+ *d = f;
+ return 0;
+}
+
+/*
+ * return a += b
+ */
+void
+mpadd(Mp *a, Mp *b)
+{
+ int i, c;
+ long x, *a1, *b1;
+
+ if(b->ovf)
+ a->ovf = 1;
+ if(a->ovf)
+ return;
+ c = 0;
+ a1 = a->a;
+ b1 = b->a;
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 + *b1++ + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ a->ovf = c;
+}
+
+/*
+ * return a = c
+ */
+void
+mpint(Mp *a, int c)
+{
+
+ memset(a, 0, sizeof(*a));
+ a->a[0] = c;
+}
+
+/*
+ * return a *= c
+ */
+void
+mpmul(Mp *a, int c)
+{
+ Mp p;
+ int b;
+
+ memmove(&p, a, sizeof(p));
+ if(!(c & 1))
+ memset(a, 0, sizeof(*a));
+ c &= ~1;
+ for(b=2; c; b<<=1) {
+ mpadd(&p, &p);
+ if(c & b) {
+ mpadd(a, &p);
+ c &= ~b;
+ }
+ }
+}
+
+/*
+ * return a *= b**e
+ */
+void
+mppow(Mp *a, int b, int e)
+{
+ int b1;
+
+ b1 = b*b;
+ b1 = b1*b1;
+ while(e >= 4) {
+ mpmul(a, b1);
+ e -= 4;
+ if(a->ovf)
+ return;
+ }
+ while(e > 0) {
+ mpmul(a, b);
+ e--;
+ }
+}
diff --git a/utils/cc/pickle.c b/utils/cc/pickle.c
new file mode 100644
index 00000000..370b9983
--- /dev/null
+++ b/utils/cc/pickle.c
@@ -0,0 +1,268 @@
+#include "cc.h"
+
+static char *kwd[] =
+{
+ "$adt", "$aggr", "$append", "$complex", "$defn",
+ "$delete", "$do", "$else", "$eval", "$head", "$if",
+ "$local", "$loop", "$return", "$tail", "$then",
+ "$union", "$whatis", "$while",
+};
+static char picklestr[] = "\tbp = pickle(bp, ep, un, ";
+
+static char*
+pmap(char *s)
+{
+ int i, bot, top, new;
+
+ bot = 0;
+ top = bot + nelem(kwd) - 1;
+ while(bot <= top){
+ new = bot + (top - bot)/2;
+ i = strcmp(kwd[new]+1, s);
+ if(i == 0)
+ return kwd[new];
+
+ if(i < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return s;
+}
+
+Sym*
+picklesue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+Sym*
+picklefun(Type *t)
+{
+ int h;
+ Sym *s;
+
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == t)
+ return s;
+ return 0;
+}
+
+char picklechar[NTYPE];
+Init picklecinit[] =
+{
+ TCHAR, 'C', 0,
+ TUCHAR, 'b', 0,
+ TSHORT, 'd', 0,
+ TUSHORT, 'u', 0,
+ TLONG, 'D', 0,
+ TULONG, 'U', 0,
+ TVLONG, 'V', 0,
+ TUVLONG, 'W', 0,
+ TFLOAT, 'f', 0,
+ TDOUBLE, 'F', 0,
+ TARRAY, 'a', 0,
+ TIND, 'X', 0,
+ -1, 0, 0,
+};
+
+static void
+pickleinit(void)
+{
+ Init *p;
+
+ for(p=picklecinit; p->code >= 0; p++)
+ picklechar[p->code] = p->value;
+
+ picklechar[TINT] = picklechar[TLONG];
+ picklechar[TUINT] = picklechar[TULONG];
+ if(types[TINT]->width != types[TLONG]->width) {
+ picklechar[TINT] = picklechar[TSHORT];
+ picklechar[TUINT] = picklechar[TUSHORT];
+ if(types[TINT]->width != types[TSHORT]->width)
+ warn(Z, "picklemember int not long or short");
+ }
+
+}
+
+void
+picklemember(Type *t, long off)
+{
+ Sym *s, *s1;
+ static int picklecharinit = 0;
+
+ if(picklecharinit == 0) {
+ pickleinit();
+ picklecharinit = 1;
+ }
+ s = t->sym;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, " T%d\n", t->etype);
+ break;
+
+ case TIND:
+ if(s == S)
+ Bprint(&outbuf,
+ "%s\"p\", (char*)addr+%ld+_i*%ld);\n",
+ picklestr, t->offset+off, t->width);
+ else
+ Bprint(&outbuf,
+ "%s\"p\", &addr->%s);\n",
+ picklestr, pmap(s->name));
+ break;
+
+ case TINT:
+ case TUINT:
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ if(s == S)
+ Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n",
+ picklestr, picklechar[t->etype], t->offset+off, t->width);
+ else
+ Bprint(&outbuf, "%s\"%c\", &addr->%s);\n",
+ picklestr, picklechar[t->etype], pmap(s->name));
+ break;
+ case TARRAY:
+ Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t",
+ t->width/t->link->width);
+ picklemember(t->link, t->offset+off);
+ Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n");
+ break;
+
+ case TSTRUCT:
+ case TUNION:
+ s1 = picklesue(t->link);
+ if(s1 == S)
+ break;
+ if(s == S) {
+ Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n",
+ pmap(s1->name), pmap(s1->name), t->offset+off, t->width);
+ } else {
+ Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n",
+ pmap(s1->name), pmap(s->name));
+ }
+ break;
+ }
+}
+
+void
+pickletype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ Io *i;
+ int n;
+ char *an;
+
+ if(!debug['P'])
+ return;
+ if(debug['P'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ s = picklesue(t->link);
+ if(s == S)
+ return;
+ switch(t->etype) {
+ default:
+ Bprint(&outbuf, "T%d\n", t->etype);
+ return;
+
+ case TUNION:
+ case TSTRUCT:
+ if(debug['s'])
+ goto asmstr;
+ an = pmap(s->name);
+
+ Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
+ for(l = t->link; l != T; l = l->down)
+ picklemember(l, 0);
+ Bprint(&outbuf, "\treturn bp;\n}\n\n");
+ break;
+ asmstr:
+ if(s == S)
+ break;
+ for(l = t->link; l != T; l = l->down)
+ if(l->sym != S)
+ Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ s->name,
+ l->sym->name,
+ l->offset);
+ break;
+ }
+}
+
+void
+picklevar(Sym *s)
+{
+ int n;
+ Io *i;
+ Type *t;
+ Sym *s1, *s2;
+
+ if(!debug['P'] || debug['s'])
+ return;
+ if(debug['P'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return;
+ }
+ t = s->type;
+ while(t && t->etype == TIND)
+ t = t->link;
+ if(t == T)
+ return;
+ if(t->etype == TENUM) {
+ Bprint(&outbuf, "%s = ", pmap(s->name));
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "%lld;\n", s->vconst);
+ else
+ Bprint(&outbuf, "%f\n;", s->fconst);
+ return;
+ }
+ if(!typesu[t->etype])
+ return;
+ s1 = picklesue(t->link);
+ if(s1 == S)
+ return;
+ switch(s->class) {
+ case CAUTO:
+ case CPARAM:
+ s2 = picklefun(thisfn);
+ if(s2)
+ Bprint(&outbuf, "complex %s %s:%s;\n",
+ pmap(s1->name), pmap(s2->name), pmap(s->name));
+ break;
+
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ case CLOCAL:
+ Bprint(&outbuf, "complex %s %s;\n",
+ pmap(s1->name), pmap(s->name));
+ break;
+ }
+}
diff --git a/utils/cc/scon.c b/utils/cc/scon.c
new file mode 100644
index 00000000..f0c2bd13
--- /dev/null
+++ b/utils/cc/scon.c
@@ -0,0 +1,606 @@
+#include "cc.h"
+
+static Node*
+acast(Type *t, Node *n)
+{
+ if(n->type->etype != t->etype || n->op == OBIT) {
+ n = new1(OCAST, n, Z);
+ if(nocast(n->left->type, t))
+ *n = *n->left;
+ n->type = t;
+ }
+ return n;
+}
+
+
+void
+evconst(Node *n)
+{
+ Node *l, *r;
+ int et, isf;
+ vlong v;
+ double d;
+
+ if(n == Z || n->type == T)
+ return;
+
+ et = n->type->etype;
+ isf = typefd[et];
+
+ l = n->left;
+ r = n->right;
+
+ d = 0;
+ v = 0;
+
+ switch(n->op) {
+ default:
+ return;
+
+ case ONEG:
+ if(isf)
+ d = -l->fconst;
+ else
+ v = -l->vconst;
+ break;
+
+ case OCOM:
+ v = ~l->vconst;
+ break;
+
+ case OCAST:
+ if(et == TVOID)
+ return;
+ et = l->type->etype;
+ if(isf) {
+ if(typefd[et])
+ d = l->fconst;
+ else
+ d = l->vconst;
+ } else {
+ if(typefd[et])
+ v = l->fconst;
+ else
+ v = convvtox(l->vconst, n->type->etype);
+ }
+ break;
+
+ case OCONST:
+ break;
+
+ case OADD:
+ if(isf)
+ d = l->fconst + r->fconst;
+ else {
+ v = l->vconst + r->vconst;
+ }
+ break;
+
+ case OSUB:
+ if(isf)
+ d = l->fconst - r->fconst;
+ else
+ v = l->vconst - r->vconst;
+ break;
+
+ case OMUL:
+ if(isf)
+ d = l->fconst * r->fconst;
+ else {
+ v = l->vconst * r->vconst;
+ }
+ break;
+
+ case OLMUL:
+ v = (uvlong)l->vconst * (uvlong)r->vconst;
+ break;
+
+
+ case ODIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ if(isf)
+ d = l->fconst / r->fconst;
+ else
+ v = l->vconst / r->vconst;
+ break;
+
+ case OLDIV:
+ if(vconst(r) == 0) {
+ warn(n, "divide by zero");
+ return;
+ }
+ v = (uvlong)l->vconst / (uvlong)r->vconst;
+ break;
+
+ case OMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = l->vconst % r->vconst;
+ break;
+
+ case OLMOD:
+ if(vconst(r) == 0) {
+ warn(n, "modulo by zero");
+ return;
+ }
+ v = (uvlong)l->vconst % (uvlong)r->vconst;
+ break;
+
+ case OAND:
+ v = l->vconst & r->vconst;
+ break;
+
+ case OOR:
+ v = l->vconst | r->vconst;
+ break;
+
+ case OXOR:
+ v = l->vconst ^ r->vconst;
+ break;
+
+ case OLSHR:
+ v = (uvlong)l->vconst >> r->vconst;
+ break;
+
+ case OASHR:
+ v = l->vconst >> r->vconst;
+ break;
+
+ case OASHL:
+ v = l->vconst << r->vconst;
+ break;
+
+ case OLO:
+ v = (uvlong)l->vconst < (uvlong)r->vconst;
+ break;
+
+ case OLT:
+ if(typefd[l->type->etype])
+ v = l->fconst < r->fconst;
+ else
+ v = l->vconst < r->vconst;
+ break;
+
+ case OHI:
+ v = (uvlong)l->vconst > (uvlong)r->vconst;
+ break;
+
+ case OGT:
+ if(typefd[l->type->etype])
+ v = l->fconst > r->fconst;
+ else
+ v = l->vconst > r->vconst;
+ break;
+
+ case OLS:
+ v = (uvlong)l->vconst <= (uvlong)r->vconst;
+ break;
+
+ case OLE:
+ if(typefd[l->type->etype])
+ v = l->fconst <= r->fconst;
+ else
+ v = l->vconst <= r->vconst;
+ break;
+
+ case OHS:
+ v = (uvlong)l->vconst >= (uvlong)r->vconst;
+ break;
+
+ case OGE:
+ if(typefd[l->type->etype])
+ v = l->fconst >= r->fconst;
+ else
+ v = l->vconst >= r->vconst;
+ break;
+
+ case OEQ:
+ if(typefd[l->type->etype])
+ v = l->fconst == r->fconst;
+ else
+ v = l->vconst == r->vconst;
+ break;
+
+ case ONE:
+ if(typefd[l->type->etype])
+ v = l->fconst != r->fconst;
+ else
+ v = l->vconst != r->vconst;
+ break;
+
+ case ONOT:
+ if(typefd[l->type->etype])
+ v = !l->fconst;
+ else
+ v = !l->vconst;
+ break;
+
+ case OANDAND:
+ if(typefd[l->type->etype])
+ v = l->fconst && r->fconst;
+ else
+ v = l->vconst && r->vconst;
+ break;
+
+ case OOROR:
+ if(typefd[l->type->etype])
+ v = l->fconst || r->fconst;
+ else
+ v = l->vconst || r->vconst;
+ break;
+ }
+ if(isf) {
+ n->fconst = d;
+ } else {
+ n->vconst = convvtox(v, n->type->etype);
+ }
+ n->oldop = n->op;
+ n->op = OCONST;
+}
+
+void
+acom(Node *n)
+{
+ Type *t;
+ Node *l, *r;
+ int i;
+
+ switch(n->op)
+ {
+
+ case ONAME:
+ case OCONST:
+ case OSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+
+ case ONEG:
+ l = n->left;
+ if(addo(n) && addo(l))
+ break;
+ acom(l);
+ return;
+
+ case OADD:
+ case OSUB:
+ case OMUL:
+ l = n->left;
+ r = n->right;
+ if(addo(n)) {
+ if(addo(r))
+ break;
+ if(addo(l))
+ break;
+ }
+ acom(l);
+ acom(r);
+ return;
+
+ default:
+ l = n->left;
+ r = n->right;
+ if(l != Z)
+ acom(l);
+ if(r != Z)
+ acom(r);
+ return;
+ }
+
+ /* bust terms out */
+ t = n->type;
+ term[0].mult = 0;
+ term[0].node = Z;
+ nterm = 1;
+ acom1(1, n);
+ if(debug['m'])
+ for(i=0; i<nterm; i++) {
+ print("%d %3lld ", i, term[i].mult);
+ prtree1(term[i].node, 1, 0);
+ }
+ if(nterm < NTERM)
+ acom2(n, t);
+ n->type = t;
+}
+
+int
+acomcmp1(const void *a1, const void *a2)
+{
+ vlong c1, c2;
+ Term *t1, *t2;
+
+ t1 = (Term*)a1;
+ t2 = (Term*)a2;
+ c1 = t1->mult;
+ if(c1 < 0)
+ c1 = -c1;
+ c2 = t2->mult;
+ if(c2 < 0)
+ c2 = -c2;
+ if(c1 > c2)
+ return 1;
+ if(c1 < c2)
+ return -1;
+ c1 = 1;
+ if(t1->mult < 0)
+ c1 = 0;
+ c2 = 1;
+ if(t2->mult < 0)
+ c2 = 0;
+ if(c2 -= c1)
+ return c2;
+ if(t2 > t1)
+ return 1;
+ return -1;
+}
+
+int
+acomcmp2(const void *a1, const void *a2)
+{
+ vlong c1, c2;
+ Term *t1, *t2;
+
+ t1 = (Term*)a1;
+ t2 = (Term*)a2;
+ c1 = t1->mult;
+ c2 = t2->mult;
+ if(c1 > c2)
+ return 1;
+ if(c1 < c2)
+ return -1;
+ if(t2 > t1)
+ return 1;
+ return -1;
+}
+
+void
+acom2(Node *n, Type *t)
+{
+ Node *l, *r;
+ Term trm[NTERM];
+ int et, nt, i, j;
+ vlong c1, c2;
+
+ /*
+ * copy into automatic
+ */
+ c2 = 0;
+ nt = nterm;
+ for(i=0; i<nt; i++)
+ trm[i] = term[i];
+ /*
+ * recur on subtrees
+ */
+ j = 0;
+ for(i=1; i<nt; i++) {
+ c1 = trm[i].mult;
+ if(c1 == 0)
+ continue;
+ l = trm[i].node;
+ if(l != Z) {
+ j = 1;
+ acom(l);
+ }
+ }
+ c1 = trm[0].mult;
+ if(j == 0) {
+ n->oldop = n->op;
+ n->op = OCONST;
+ n->vconst = c1;
+ return;
+ }
+ et = t->etype;
+
+ /*
+ * prepare constant term,
+ * combine it with an addressing term
+ */
+ if(c1 != 0) {
+ l = new1(OCONST, Z, Z);
+ l->type = t;
+ l->vconst = c1;
+ trm[0].mult = 1;
+ for(i=1; i<nt; i++) {
+ if(trm[i].mult != 1)
+ continue;
+ r = trm[i].node;
+ if(r->op != OADDR)
+ continue;
+ r->type = t;
+ l = new1(OADD, r, l);
+ l->type = t;
+ trm[i].mult = 0;
+ break;
+ }
+ trm[0].node = l;
+ }
+ /*
+ * look for factorable terms
+ * c1*i + c1*c2*j -> c1*(i + c2*j)
+ */
+ qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
+ for(i=nt-1; i>=0; i--) {
+ c1 = trm[i].mult;
+ if(c1 < 0)
+ c1 = -c1;
+ if(c1 <= 1)
+ continue;
+ for(j=i+1; j<nt; j++) {
+ c2 = trm[j].mult;
+ if(c2 < 0)
+ c2 = -c2;
+ if(c2 <= 1)
+ continue;
+ if(c2 % c1)
+ continue;
+ r = trm[j].node;
+ if(r->type->etype != et)
+ r = acast(t, r);
+ c2 = trm[j].mult/trm[i].mult;
+ if(c2 != 1 && c2 != -1) {
+ r = new1(OMUL, r, new(OCONST, Z, Z));
+ r->type = t;
+ r->right->type = t;
+ r->right->vconst = c2;
+ }
+ l = trm[i].node;
+ if(l->type->etype != et)
+ l = acast(t, l);
+ r = new1(OADD, l, r);
+ r->type = t;
+ if(c2 == -1)
+ r->op = OSUB;
+ trm[i].node = r;
+ trm[j].mult = 0;
+ }
+ }
+ if(debug['m']) {
+ print("\n");
+ for(i=0; i<nt; i++) {
+ print("%d %3lld ", i, trm[i].mult);
+ prtree1(trm[i].node, 1, 0);
+ }
+ }
+
+ /*
+ * put it all back together
+ */
+ qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
+ l = Z;
+ for(i=nt-1; i>=0; i--) {
+ c1 = trm[i].mult;
+ if(c1 == 0)
+ continue;
+ r = trm[i].node;
+ if(r->type->etype != et || r->op == OBIT)
+ r = acast(t, r);
+ if(c1 != 1 && c1 != -1) {
+ r = new1(OMUL, r, new(OCONST, Z, Z));
+ r->type = t;
+ r->right->type = t;
+ if(c1 < 0) {
+ r->right->vconst = -c1;
+ c1 = -1;
+ } else {
+ r->right->vconst = c1;
+ c1 = 1;
+ }
+ }
+ if(l == Z) {
+ l = r;
+ c2 = c1;
+ continue;
+ }
+ if(c1 < 0)
+ if(c2 < 0)
+ l = new1(OADD, l, r);
+ else
+ l = new1(OSUB, l, r);
+ else
+ if(c2 < 0) {
+ l = new1(OSUB, r, l);
+ c2 = 1;
+ } else
+ l = new1(OADD, l, r);
+ l->type = t;
+ }
+ if(c2 < 0) {
+ r = new1(OCONST, 0, 0);
+ r->vconst = 0;
+ r->type = t;
+ l = new1(OSUB, r, l);
+ l->type = t;
+ }
+ *n = *l;
+}
+
+void
+acom1(vlong v, Node *n)
+{
+ Node *l, *r;
+
+ if(v == 0 || nterm >= NTERM)
+ return;
+ if(!addo(n)) {
+ if(n->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ term[0].mult += v*n->vconst;
+ return;
+ }
+ term[nterm].mult = v;
+ term[nterm].node = n;
+ nterm++;
+ return;
+ }
+ switch(n->op) {
+
+ case OCAST:
+ acom1(v, n->left);
+ break;
+
+ case ONEG:
+ acom1(-v, n->left);
+ break;
+
+ case OADD:
+ acom1(v, n->left);
+ acom1(v, n->right);
+ break;
+
+ case OSUB:
+ acom1(v, n->left);
+ acom1(-v, n->right);
+ break;
+
+ case OMUL:
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ acom1(v*l->vconst, r);
+ break;
+ }
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ acom1(v*r->vconst, l);
+ break;
+ }
+ break;
+
+ default:
+ diag(n, "not addo");
+ }
+}
+
+int
+addo(Node *n)
+{
+
+ if(n != Z)
+ if(!typefd[n->type->etype])
+ if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
+ switch(n->op) {
+
+ case OCAST:
+ if(nilcast(n->left->type, n->type))
+ return 1;
+ break;
+
+ case ONEG:
+ case OADD:
+ case OSUB:
+ return 1;
+
+ case OMUL:
+ if(n->left->op == OCONST)
+ return 1;
+ if(n->right->op == OCONST)
+ return 1;
+ }
+ return 0;
+}
diff --git a/utils/cc/sub.c b/utils/cc/sub.c
new file mode 100644
index 00000000..f1572291
--- /dev/null
+++ b/utils/cc/sub.c
@@ -0,0 +1,2012 @@
+#include "cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+ Node *n;
+
+ n = alloc(sizeof(*n));
+ n->op = t;
+ n->left = l;
+ n->right = r;
+ n->lineno = lineno;
+ newflag = 1;
+ return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+ Node *n;
+
+ n = new(o, l, r);
+ n->lineno = nearln;
+ return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+ print(" == %s ==\n", s);
+ prtree1(n, 0, 0);
+ print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+ int i;
+
+ if(f)
+ for(i=0; i<d; i++)
+ print(" ");
+ if(n == Z) {
+ print("Z\n");
+ return;
+ }
+ if(n->op == OLIST) {
+ prtree1(n->left, d, 0);
+ prtree1(n->right, d, 1);
+ return;
+ }
+ d++;
+ print("%O", n->op);
+ i = 3;
+ switch(n->op)
+ {
+ case ONAME:
+ print(" \"%F\"", n);
+ print(" %ld", n->xoffset);
+ i = 0;
+ break;
+
+ case OINDREG:
+ print(" %ld(R%d)", n->xoffset, n->reg);
+ i = 0;
+ break;
+
+ case OREGISTER:
+ if(n->xoffset)
+ print(" %ld+R%d", n->xoffset, n->reg);
+ else
+ print(" R%d", n->reg);
+ i = 0;
+ break;
+
+ case OSTRING:
+ print(" \"%s\"", n->cstring);
+ i = 0;
+ break;
+
+ case OLSTRING:
+ print(" \"%S\"", n->rstring);
+ i = 0;
+ break;
+
+ case ODOT:
+ case OELEM:
+ print(" \"%F\"", n);
+ break;
+
+ case OCONST:
+ if(typefd[n->type->etype])
+ print(" \"%.8e\"", n->fconst);
+ else
+ print(" \"%lld\"", n->vconst);
+ i = 0;
+ break;
+ }
+ if(n->addable != 0)
+ print(" <%d>", n->addable);
+ if(n->type != T)
+ print(" %T", n->type);
+ if(n->complex != 0)
+ print(" (%d)", n->complex);
+ print("\n");
+ if(i & 2)
+ prtree1(n->left, d, 1);
+ if(i & 1)
+ prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+ Type *t;
+
+ t = alloc(sizeof(*t));
+ t->etype = et;
+ t->link = d;
+ t->down = T;
+ t->sym = S;
+ t->width = ewidth[et];
+ t->offset = 0;
+ t->shift = 0;
+ t->nbits = 0;
+ t->garb = 0;
+ return t;
+}
+
+Type*
+copytyp(Type *t)
+{
+ Type *nt;
+
+ nt = typ(TXXX, T);
+ *nt = *t;
+ return nt;
+}
+
+Type*
+garbt(Type *t, long b)
+{
+ Type *t1;
+
+ if(b & BGARB) {
+ t1 = copytyp(t);
+ t1->garb = simpleg(b);
+ return t1;
+ }
+ return t;
+}
+
+int
+simpleg(long b)
+{
+
+ b &= BGARB;
+ switch(b) {
+ case BCONSTNT:
+ return GCONSTNT;
+ case BVOLATILE:
+ return GVOLATILE;
+ case BVOLATILE|BCONSTNT:
+ return GCONSTNT|GVOLATILE;
+ }
+ return GXXX;
+}
+
+int
+simplec(long b)
+{
+
+ b &= BCLASS;
+ switch(b) {
+ case 0:
+ case BREGISTER:
+ return CXXX;
+ case BAUTO:
+ case BAUTO|BREGISTER:
+ return CAUTO;
+ case BEXTERN:
+ return CEXTERN;
+ case BEXTERN|BREGISTER:
+ return CEXREG;
+ case BSTATIC:
+ return CSTATIC;
+ case BTYPEDEF:
+ return CTYPEDEF;
+ case BTYPESTR:
+ return CTYPESTR;
+ }
+ diag(Z, "illegal combination of classes %Q", b);
+ return CXXX;
+}
+
+Type*
+simplet(long b)
+{
+
+ b &= ~BCLASS & ~BGARB;
+ switch(b) {
+ case BCHAR:
+ case BCHAR|BSIGNED:
+ return types[TCHAR];
+
+ case BCHAR|BUNSIGNED:
+ return types[TUCHAR];
+
+ case BSHORT:
+ case BSHORT|BINT:
+ case BSHORT|BSIGNED:
+ case BSHORT|BINT|BSIGNED:
+ return types[TSHORT];
+
+ case BUNSIGNED|BSHORT:
+ case BUNSIGNED|BSHORT|BINT:
+ return types[TUSHORT];
+
+ case 0:
+ case BINT:
+ case BINT|BSIGNED:
+ case BSIGNED:
+ return types[TINT];
+
+ case BUNSIGNED:
+ case BUNSIGNED|BINT:
+ return types[TUINT];
+
+ case BLONG:
+ case BLONG|BINT:
+ case BLONG|BSIGNED:
+ case BLONG|BINT|BSIGNED:
+ return types[TLONG];
+
+ case BUNSIGNED|BLONG:
+ case BUNSIGNED|BLONG|BINT:
+ return types[TULONG];
+
+ case BVLONG|BLONG:
+ case BVLONG|BLONG|BINT:
+ case BVLONG|BLONG|BSIGNED:
+ case BVLONG|BLONG|BINT|BSIGNED:
+ return types[TVLONG];
+
+ case BVLONG|BLONG|BUNSIGNED:
+ case BVLONG|BLONG|BINT|BUNSIGNED:
+ return types[TUVLONG];
+
+ case BFLOAT:
+ return types[TFLOAT];
+
+ case BDOUBLE:
+ case BDOUBLE|BLONG:
+ case BFLOAT|BLONG:
+ return types[TDOUBLE];
+
+ case BVOID:
+ return types[TVOID];
+ }
+
+ diag(Z, "illegal combination of types %Q", b);
+ return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+ int i;
+ ulong b;
+
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1L << i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ttab[i]) {
+ if(ttab == tasign)
+ if(b == BSTRUCT || b == BUNION)
+ if(!sametype(t1, t2))
+ return 1;
+ if(n->op != OCAST)
+ if(b == BIND && i == TIND)
+ if(!sametype(t1, t2))
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+
+ if(stcompat(n, t1, t2, ttab)) {
+ if(t1 == T)
+ diag(n, "incompatible type: \"%T\" for op \"%O\"",
+ t2, n->op);
+ else
+ diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+ t1, t2, n->op);
+ return 1;
+ }
+ return 0;
+}
+
+void
+makedot(Node *n, Type *t, long o)
+{
+ Node *n1, *n2;
+
+ if(t->nbits) {
+ n1 = new(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OBIT;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = n1->left->addable;
+ n = n1;
+ }
+ n->addable = n->left->addable;
+ if(n->addable == 0) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ n1->type = types[TLONG];
+ n->right = n1;
+ n->type = t;
+ return;
+ }
+ n->left->type = t;
+ if(o == 0) {
+ *n = *n->left;
+ return;
+ }
+ n->type = t;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ n1->type = t;
+
+ n2 = new1(OADDR, n->left, Z);
+ n2->type = t;
+
+ n1 = new1(OADD, n1, n2);
+ n1->type = t;
+
+ n->op = OIND;
+ n->left = n1;
+ n->right = Z;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n, long *off)
+{
+ Type *t1, *xt, *rt;
+
+ xt = T;
+
+ /*
+ * look it up by name
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == s) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+
+ /*
+ * look it up by type
+ */
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(sametype(s->type, t1)) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ if(xt != T) {
+ *off = xt->offset;
+ return xt;
+ }
+
+ /*
+ * look it up in unnamed substructures
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype]){
+ rt = dotsearch(s, t1->link, n, off);
+ if(rt != T) {
+ if(xt != T)
+ goto ambig;
+ xt = rt;
+ *off += t1->offset;
+ }
+ }
+ return xt;
+
+ambig:
+ diag(n, "ambiguous structure element: %s", s->name);
+ return xt;
+}
+
+long
+dotoffset(Type *st, Type *lt, Node *n)
+{
+ Type *t;
+ Sym *g;
+ long o, o1;
+
+ o = -1;
+ /*
+ * first try matching at the top level
+ * for matching tag names
+ */
+ g = st->tag;
+ if(g != S)
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(g == t->tag) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * second try matching at the top level
+ * for similar types
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(sametype(st, t)) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * last try matching sub-levels
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(typesu[t->etype]) {
+ o1 = dotoffset(st, t, n);
+ if(o1 >= 0) {
+ if(o >= 0)
+ goto ambig;
+ o = o1 + t->offset;
+ }
+ }
+ return o;
+
+ambig:
+ diag(n, "ambiguous unnamed structure element");
+ return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+ if(n != Z) {
+ if(n->type->etype != TDOUBLE)
+ return 1;
+ switch(n->op) {
+ case OCONST:
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ case OADD: /* no need to get more exotic than this */
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ if(!allfloat(n->right, flag))
+ break;
+ case OCAST:
+ if(!allfloat(n->left, flag))
+ break;
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+ Type *l, *r;
+
+ l = il;
+ r = ir;
+
+ if(l == T)
+ return;
+ if(l->garb & GCONSTNT) {
+ warn(n, "assignment to a constant type (%T)", il);
+ return;
+ }
+ if(r == T)
+ return;
+ for(;;) {
+ if(l->etype != TIND || r->etype != TIND)
+ break;
+ l = l->link;
+ r = r->link;
+ if(l == T || r == T)
+ break;
+ if(r->garb & GCONSTNT)
+ if(!(l->garb & GCONSTNT)) {
+ warn(n, "assignment of a constant pointer type (%T)", ir);
+ break;
+ }
+ }
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+ if(st->etype == TFLOAT && allfloat(l, 0))
+ allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+ Type *lt;
+ Node *n1, *n2;
+ long o;
+
+ lt = l->type;
+ if(lt == T)
+ return;
+ if(st->etype == TIND && vconst(l) == 0) {
+ l->type = st;
+ l->vconst = 0;
+ return;
+ }
+ typeext1(st, l);
+
+ /*
+ * extension of C
+ * if assign of struct containing unnamed sub-struct
+ * to type of sub-struct, insert the DOT.
+ * if assign of *struct containing unnamed substruct
+ * to type of *sub-struct, insert the add-offset
+ */
+ if(typesu[st->etype] && typesu[lt->etype]) {
+ o = dotoffset(st, lt, l);
+ if(o >= 0) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ l->op = ODOT;
+ l->left = n1;
+ l->right = Z;
+ makedot(l, st, o);
+ }
+ return;
+ }
+ if(st->etype == TIND && typesu[st->link->etype])
+ if(lt->etype == TIND && typesu[lt->link->etype]) {
+ o = dotoffset(st->link, lt->link, l);
+ if(o >= 0) {
+ l->type = st;
+ if(o == 0)
+ return;
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ n2 = new1(OCONST, Z, Z);
+ n2->vconst = o;
+ n2->type = st;
+ l->op = OADD;
+ l->left = n1;
+ l->right = n2;
+ }
+ return;
+ }
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+ int i, b;
+
+ if(t1->nbits)
+ return 0;
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1<<i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ncast[i])
+ return 1;
+ return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+ int et1, et2;
+
+ if(t1 == T)
+ return 0;
+ if(t1->nbits)
+ return 0;
+ if(t2 == T)
+ return 0;
+ et1 = t1->etype;
+ et2 = t2->etype;
+ if(et1 == et2)
+ return 1;
+ if(typefd[et1] && typefd[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ if(typechlp[et1] && typechlp[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+ Type *t1, *t2;
+ int i, j, k;
+ Node *n1;
+ long w;
+
+ t1 = n->left->type;
+ if(n->right == Z)
+ t2 = t1;
+ else
+ t2 = n->right->type;
+ i = TXXX;
+ if(t1 != T)
+ i = t1->etype;
+ j = TXXX;
+ if(t2 != T)
+ j = t2->etype;
+ k = tab[i][j];
+ if(k == TIND) {
+ if(i == TIND)
+ n->type = t1;
+ else
+ if(j == TIND)
+ n->type = t2;
+ } else {
+ /* convert up to at least int */
+ if(f == 1)
+ while(k < TINT)
+ k += 2;
+ n->type = types[k];
+ }
+ if(n->op == OSUB)
+ if(i == TIND && j == TIND) {
+ w = n->right->type->link->width;
+ if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
+ goto bad;
+ n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
+ if(1 && ewidth[TIND] > ewidth[TLONG]){
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = types[TLONG];
+ }
+ if(w > 1) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = ODIV;
+ n->left = n1;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = n1;
+ w = vlog(n1);
+ if(w >= 0) {
+ n->op = OASHR;
+ n1->vconst = w;
+ }
+ }
+ return;
+ }
+ if(!sametype(n->type, n->left->type)) {
+ n->left = new1(OCAST, n->left, Z);
+ n->left->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w > 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->left = new1(OMUL, n->left, n1);
+ n->left->type = n->type;
+ }
+ }
+ }
+ if(n->right != Z)
+ if(!sametype(n->type, n->right->type)) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w != 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = new1(OMUL, n->right, n1);
+ n->right->type = n->type;
+ }
+ }
+ }
+ return;
+bad:
+ diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+/*
+ * try to rewrite shift & mask
+ */
+void
+simplifyshift(Node *n)
+{
+ ulong c3;
+ int o, s1, s2, c1, c2;
+
+ if(!typechlp[n->type->etype])
+ return;
+ switch(n->op) {
+ default:
+ return;
+ case OASHL:
+ s1 = 0;
+ break;
+ case OLSHR:
+ s1 = 1;
+ break;
+ case OASHR:
+ s1 = 2;
+ break;
+ }
+ if(n->right->op != OCONST)
+ return;
+ if(n->left->op != OAND)
+ return;
+ if(n->left->right->op != OCONST)
+ return;
+ switch(n->left->left->op) {
+ default:
+ return;
+ case OASHL:
+ s2 = 0;
+ break;
+ case OLSHR:
+ s2 = 1;
+ break;
+ case OASHR:
+ s2 = 2;
+ break;
+ }
+ if(n->left->left->right->op != OCONST)
+ return;
+
+ c1 = n->right->vconst;
+ c2 = n->left->left->right->vconst;
+ c3 = n->left->right->vconst;
+
+/*
+ if(debug['h'])
+ print("%.3o %ld %ld %d #%.lux\n",
+ (s1<<3)|s2, c1, c2, topbit(c3), c3);
+*/
+
+ o = n->op;
+ switch((s1<<3)|s2) {
+ case 000: /* (((e <<u c2) & c3) <<u c1) */
+ c3 >>= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ goto rewrite1;
+
+ case 002: /* (((e >>s c2) & c3) <<u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ case 001: /* (((e >>u c2) & c3) <<u c1) */
+ if(c1 > c2) {
+ c3 <<= c2;
+ c1 -= c2;
+ o = OASHL;
+ goto rewrite1;
+ }
+ c3 <<= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ c1 = c2-c1;
+ o = OLSHR;
+ goto rewrite2;
+
+ case 022: /* (((e >>s c2) & c3) >>s c1) */
+ if(c2 <= 0)
+ break;
+ case 012: /* (((e >>s c2) & c3) >>u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ goto s11;
+ case 021: /* (((e >>u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31 && c2 <= 0)
+ break;
+ goto s11;
+ case 011: /* (((e >>u c2) & c3) >>u c1) */
+ s11:
+ c3 <<= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ o = OLSHR;
+ goto rewrite1;
+
+ case 020: /* (((e <<u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31)
+ break;
+ case 010: /* (((e <<u c2) & c3) >>u c1) */
+ c3 >>= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ if(c1 > c2) {
+ c1 -= c2;
+ goto rewrite2;
+ }
+ c1 = c2 - c1;
+ o = OASHL;
+ goto rewrite2;
+ }
+ return;
+
+rewrite0: /* get rid of both shifts */
+if(debug['<'])prtree(n, "rewrite0");
+ *n = *n->left;
+ n->left = n->left->left;
+ n->right->vconst = c3;
+ return;
+rewrite1: /* get rid of lower shift */
+if(debug['<'])prtree(n, "rewrite1");
+ n->left->left = n->left->left->left;
+ n->left->right->vconst = c3;
+ n->right->vconst = c1;
+ n->op = o;
+ return;
+rewrite2: /* get rid of upper shift */
+if(debug['<'])prtree(n, "rewrite2");
+ *n = *n->left;
+ n->right->vconst = c3;
+ n->left->right->vconst = c1;
+ n->left->op = o;
+}
+
+int
+side(Node *n)
+{
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ case OCAST:
+ case ONOT:
+ case OADDR:
+ case OIND:
+ n = n->left;
+ goto loop;
+
+ case OCOND:
+ if(side(n->left))
+ break;
+ n = n->right;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OLMOD:
+ case OANDAND:
+ case OOROR:
+ case OCOMMA:
+ case ODOT:
+ if(side(n->left))
+ break;
+ n = n->right;
+ goto loop;
+
+ case OSIGN:
+ case OSIZE:
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case ONAME:
+ return 0;
+ }
+ return 1;
+}
+
+int
+vconst(Node *n)
+{
+ int i;
+
+ if(n == Z)
+ goto no;
+ if(n->op != OCONST)
+ goto no;
+ if(n->type == T)
+ goto no;
+ switch(n->type->etype)
+ {
+ case TFLOAT:
+ case TDOUBLE:
+ i = 100;
+ if(n->fconst > i || n->fconst < -i)
+ goto no;
+ i = n->fconst;
+ if(i != n->fconst)
+ goto no;
+ return i;
+
+ case TVLONG:
+ case TUVLONG:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+ }
+no:
+ return -159; /* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+log2(uvlong v)
+{
+ int s, i;
+ uvlong m;
+
+ s = 0;
+ m = MASK(8*sizeof(uvlong));
+ for(i=32; i; i>>=1) {
+ m >>= i;
+ if(!(v & m)) {
+ v >>= i;
+ s += i;
+ }
+ }
+ if(v == 1)
+ return s;
+ return -1;
+}
+
+int
+vlog(Node *n)
+{
+ if(n->op != OCONST)
+ goto bad;
+ if(typefd[n->type->etype])
+ goto bad;
+
+ return log2(n->vconst);
+
+bad:
+ return -1;
+}
+
+int
+topbit(ulong v)
+{
+ int i;
+
+ for(i = -1; v; i++)
+ v >>= 1;
+ return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ * if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+ vlong v;
+
+ if(l->op != OCONST)
+ return;
+ if(r->op != OCAST)
+ return;
+ if(!nilcast(r->left->type, r->type))
+ return;
+ switch(r->type->etype) {
+ default:
+ return;
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ v = convvtox(l->vconst, r->type->etype);
+ if(v != l->vconst)
+ return;
+ break;
+ }
+ l->type = r->left->type;
+ *r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+ switch(o) {
+ default:
+ diag(Z, "bad in relindex: %O", o);
+ case OEQ: return 0;
+ case ONE: return 1;
+ case OLE: return 2;
+ case OLS: return 3;
+ case OLT: return 4;
+ case OLO: return 5;
+ case OGE: return 6;
+ case OHS: return 7;
+ case OGT: return 8;
+ case OHI: return 9;
+ }
+}
+
+Node*
+invert(Node *n)
+{
+ Node *i;
+
+ if(n == Z || n->op != OLIST)
+ return n;
+ i = n;
+ for(n = n->left; n != Z; n = n->left) {
+ if(n->op != OLIST)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+int
+bitno(long b)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(b & (1L<<i))
+ return i;
+ diag(Z, "bad in bitno");
+ return 0;
+}
+
+long
+typebitor(long a, long b)
+{
+ long c;
+
+ c = a | b;
+ if(a & b)
+ if((a & b) == BLONG)
+ c |= BVLONG; /* long long => vlong */
+ else
+ warn(Z, "once is enough: %Q", a & b);
+ return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ if(debug['w']) {
+ Bprint(&diagbuf, "warning: ");
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "warning");
+ }
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", lineno, buf);
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ errorexit();
+}
+
+ulong thash1 = 0x2edab8c9;
+ulong thash2 = 0x1dc74fb8;
+ulong thash3 = 0x1f241331;
+ulong thash[NALLTYPES];
+Init thashinit[] =
+{
+ TXXX, 0x17527bbd, 0,
+ TCHAR, 0x5cedd32b, 0,
+ TUCHAR, 0x552c4454, 0,
+ TSHORT, 0x63040b4b, 0,
+ TUSHORT, 0x32a45878, 0,
+ TINT, 0x4151d5bd, 0,
+ TUINT, 0x5ae707d6, 0,
+ TLONG, 0x5ef20f47, 0,
+ TULONG, 0x36d8eb8f, 0,
+ TVLONG, 0x6e5e9590, 0,
+ TUVLONG, 0x75910105, 0,
+ TFLOAT, 0x25fd7af1, 0,
+ TDOUBLE, 0x7c40a1b2, 0,
+ TIND, 0x1b832357, 0,
+ TFUNC, 0x6babc9cb, 0,
+ TARRAY, 0x7c50986d, 0,
+ TVOID, 0x44112eff, 0,
+ TSTRUCT, 0x7c2da3bf, 0,
+ TUNION, 0x3eb25e98, 0,
+ TENUM, 0x44b54f61, 0,
+ TFILE, 0x19242ac3, 0,
+ TOLD, 0x22b15988, 0,
+ TDOT, 0x0204f6b3, 0,
+ -1, 0, 0,
+};
+
+char* bnames[NALIGN];
+Init bnamesinit[] =
+{
+ Axxx, 0, "Axxx",
+ Ael1, 0, "el1",
+ Ael2, 0, "el2",
+ Asu2, 0, "su2",
+ Aarg0, 0, "arg0",
+ Aarg1, 0, "arg1",
+ Aarg2, 0, "arg2",
+ Aaut3, 0, "aut3",
+ -1, 0, 0,
+};
+
+char* tnames[NALLTYPES];
+Init tnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ TDOT, 0, "DOT",
+ -1, 0, 0,
+};
+
+char* gnames[NGTYPES];
+Init gnamesinit[] =
+{
+ GXXX, 0, "GXXX",
+ GCONSTNT, 0, "CONST",
+ GVOLATILE, 0, "VOLATILE",
+ GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
+ -1, 0, 0,
+};
+
+char* qnames[NALLTYPES];
+Init qnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+
+ TAUTO, 0, "AUTO",
+ TEXTERN, 0, "EXTERN",
+ TSTATIC, 0, "STATIC",
+ TTYPEDEF, 0, "TYPEDEF",
+ TTYPESTR, 0, "TYPESTR",
+ TREGISTER, 0, "REGISTER",
+ TCONSTNT, 0, "CONSTNT",
+ TVOLATILE, 0, "VOLATILE",
+ TUNSIGNED, 0, "UNSIGNED",
+ TSIGNED, 0, "SIGNED",
+ TDOT, 0, "DOT",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ -1, 0, 0,
+};
+char* cnames[NCTYPES];
+Init cnamesinit[] =
+{
+ CXXX, 0, "CXXX",
+ CAUTO, 0, "AUTO",
+ CEXTERN, 0, "EXTERN",
+ CGLOBL, 0, "GLOBL",
+ CSTATIC, 0, "STATIC",
+ CLOCAL, 0, "LOCAL",
+ CTYPEDEF, 0, "TYPEDEF",
+ CTYPESTR, 0, "TYPESTR",
+ CPARAM, 0, "PARAM",
+ CSELEM, 0, "SELEM",
+ CLABEL, 0, "LABEL",
+ CEXREG, 0, "EXREG",
+ -1, 0, 0,
+};
+
+char* onames[OEND+1];
+Init onamesinit[] =
+{
+ OXXX, 0, "OXXX",
+ OADD, 0, "ADD",
+ OADDR, 0, "ADDR",
+ OAND, 0, "AND",
+ OANDAND, 0, "ANDAND",
+ OARRAY, 0, "ARRAY",
+ OAS, 0, "AS",
+ OASI, 0, "ASI",
+ OASADD, 0, "ASADD",
+ OASAND, 0, "ASAND",
+ OASASHL, 0, "ASASHL",
+ OASASHR, 0, "ASASHR",
+ OASDIV, 0, "ASDIV",
+ OASHL, 0, "ASHL",
+ OASHR, 0, "ASHR",
+ OASLDIV, 0, "ASLDIV",
+ OASLMOD, 0, "ASLMOD",
+ OASLMUL, 0, "ASLMUL",
+ OASLSHR, 0, "ASLSHR",
+ OASMOD, 0, "ASMOD",
+ OASMUL, 0, "ASMUL",
+ OASOR, 0, "ASOR",
+ OASSUB, 0, "ASSUB",
+ OASXOR, 0, "ASXOR",
+ OBIT, 0, "BIT",
+ OBREAK, 0, "BREAK",
+ OCASE, 0, "CASE",
+ OCAST, 0, "CAST",
+ OCOMMA, 0, "COMMA",
+ OCOND, 0, "COND",
+ OCONST, 0, "CONST",
+ OCONTINUE, 0, "CONTINUE",
+ ODIV, 0, "DIV",
+ ODOT, 0, "DOT",
+ ODOTDOT, 0, "DOTDOT",
+ ODWHILE, 0, "DWHILE",
+ OENUM, 0, "ENUM",
+ OEQ, 0, "EQ",
+ OFOR, 0, "FOR",
+ OFUNC, 0, "FUNC",
+ OGE, 0, "GE",
+ OGOTO, 0, "GOTO",
+ OGT, 0, "GT",
+ OHI, 0, "HI",
+ OHS, 0, "HS",
+ OIF, 0, "IF",
+ OIND, 0, "IND",
+ OINDREG, 0, "INDREG",
+ OINIT, 0, "INIT",
+ OLABEL, 0, "LABEL",
+ OLDIV, 0, "LDIV",
+ OLE, 0, "LE",
+ OLIST, 0, "LIST",
+ OLMOD, 0, "LMOD",
+ OLMUL, 0, "LMUL",
+ OLO, 0, "LO",
+ OLS, 0, "LS",
+ OLSHR, 0, "LSHR",
+ OLT, 0, "LT",
+ OMOD, 0, "MOD",
+ OMUL, 0, "MUL",
+ ONAME, 0, "NAME",
+ ONE, 0, "NE",
+ ONOT, 0, "NOT",
+ OOR, 0, "OR",
+ OOROR, 0, "OROR",
+ OPOSTDEC, 0, "POSTDEC",
+ OPOSTINC, 0, "POSTINC",
+ OPREDEC, 0, "PREDEC",
+ OPREINC, 0, "PREINC",
+ OPROTO, 0, "PROTO",
+ OREGISTER, 0, "REGISTER",
+ ORETURN, 0, "RETURN",
+ OSET, 0, "SET",
+ OSIGN, 0, "SIGN",
+ OSIZE, 0, "SIZE",
+ OSTRING, 0, "STRING",
+ OLSTRING, 0, "LSTRING",
+ OSTRUCT, 0, "STRUCT",
+ OSUB, 0, "SUB",
+ OSWITCH, 0, "SWITCH",
+ OUNION, 0, "UNION",
+ OUSED, 0, "USED",
+ OWHILE, 0, "WHILE",
+ OXOR, 0, "XOR",
+ OPOS, 0, "POS",
+ ONEG, 0, "NEG",
+ OCOM, 0, "COM",
+ OELEM, 0, "ELEM",
+ OTST, 0, "TST",
+ OINDEX, 0, "INDEX",
+ OFAS, 0, "FAS",
+ OREGPAIR, 0, "REGPAIR",
+ OEND, 0, "END",
+ -1, 0, 0,
+};
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+char comrel[12] =
+{
+ ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+char invrel[12] =
+{
+ OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+char logrel[12] =
+{
+ OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+char typei[NTYPE];
+int typeiinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+char typeu[NTYPE];
+int typeuinit[] =
+{
+ TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+char typesuv[NTYPE];
+int typesuvinit[] =
+{
+ TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+char typeilp[NTYPE];
+int typeilpinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+char typechl[NTYPE];
+char typechlv[NTYPE];
+char typechlvp[NTYPE];
+int typechlinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+char typechlp[NTYPE];
+int typechlpinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+char typechlpfd[NTYPE];
+int typechlpfdinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+char typec[NTYPE];
+int typecinit[] =
+{
+ TCHAR, TUCHAR, -1
+};
+
+char typeh[NTYPE];
+int typehinit[] =
+{
+ TSHORT, TUSHORT, -1,
+};
+
+char typeil[NTYPE];
+int typeilinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, -1,
+};
+
+char typev[NTYPE];
+int typevinit[] =
+{
+ TVLONG, TUVLONG, -1,
+};
+
+char typefd[NTYPE];
+int typefdinit[] =
+{
+ TFLOAT, TDOUBLE, -1,
+};
+
+char typeaf[NTYPE];
+int typeafinit[] =
+{
+ TFUNC, TARRAY, -1,
+};
+
+char typesu[NTYPE];
+int typesuinit[] =
+{
+ TSTRUCT, TUNION, -1,
+};
+
+long tasign[NTYPE];
+Init tasigninit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ TSTRUCT, BSTRUCT, 0,
+ TUNION, BUNION, 0,
+ -1, 0, 0,
+};
+
+long tasadd[NTYPE];
+Init tasaddinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long tcast[NTYPE];
+Init tcastinit[] =
+{
+ TCHAR, BNUMBER|BIND|BVOID, 0,
+ TUCHAR, BNUMBER|BIND|BVOID, 0,
+ TSHORT, BNUMBER|BIND|BVOID, 0,
+ TUSHORT, BNUMBER|BIND|BVOID, 0,
+ TINT, BNUMBER|BIND|BVOID, 0,
+ TUINT, BNUMBER|BIND|BVOID, 0,
+ TLONG, BNUMBER|BIND|BVOID, 0,
+ TULONG, BNUMBER|BIND|BVOID, 0,
+ TVLONG, BNUMBER|BIND|BVOID, 0,
+ TUVLONG, BNUMBER|BIND|BVOID, 0,
+ TFLOAT, BNUMBER|BVOID, 0,
+ TDOUBLE, BNUMBER|BVOID, 0,
+ TIND, BINTEGER|BIND|BVOID, 0,
+ TVOID, BVOID, 0,
+ TSTRUCT, BSTRUCT|BVOID, 0,
+ TUNION, BUNION|BVOID, 0,
+ -1, 0, 0,
+};
+
+long tadd[NTYPE];
+Init taddinit[] =
+{
+ TCHAR, BNUMBER|BIND, 0,
+ TUCHAR, BNUMBER|BIND, 0,
+ TSHORT, BNUMBER|BIND, 0,
+ TUSHORT, BNUMBER|BIND, 0,
+ TINT, BNUMBER|BIND, 0,
+ TUINT, BNUMBER|BIND, 0,
+ TLONG, BNUMBER|BIND, 0,
+ TULONG, BNUMBER|BIND, 0,
+ TVLONG, BNUMBER|BIND, 0,
+ TUVLONG, BNUMBER|BIND, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long tsub[NTYPE];
+Init tsubinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER|BIND, 0,
+ -1, 0, 0,
+};
+
+long tmul[NTYPE];
+Init tmulinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ -1, 0, 0,
+};
+
+long tand[NTYPE];
+Init tandinit[] =
+{
+ TCHAR, BINTEGER, 0,
+ TUCHAR, BINTEGER, 0,
+ TSHORT, BINTEGER, 0,
+ TUSHORT, BINTEGER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BINTEGER, 0,
+ TULONG, BINTEGER, 0,
+ TVLONG, BINTEGER, 0,
+ TUVLONG, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+long trel[NTYPE];
+Init trelinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ -1, 0, 0,
+};
+
+long tfunct[1] =
+{
+ BFUNC,
+};
+
+long tindir[1] =
+{
+ BIND,
+};
+
+long tdot[1] =
+{
+ BSTRUCT|BUNION,
+};
+
+long tnot[1] =
+{
+ BNUMBER|BIND,
+};
+
+long targ[1] =
+{
+ BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+char tab[NTYPE][NTYPE] =
+{
+/*TXXX*/ { 0,
+ },
+
+/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+ TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+ TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+ TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+ },
+/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+ TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+ },
+/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+ TIND, TIND, TIND, TIND, TIND, TIND,
+ },
+};
+
+void
+urk(char *name, int max, int i)
+{
+ if(i >= max) {
+ fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+ exits("init");
+ }
+}
+
+void
+tinit(void)
+{
+ int i;
+ Init *p;
+
+ for(p=thashinit; p->code >= 0; p++) {
+ urk("thash", nelem(thash), p->code);
+ thash[p->code] = p->value;
+ }
+ for(p=bnamesinit; p->code >= 0; p++) {
+ urk("bnames", nelem(bnames), p->code);
+ bnames[p->code] = p->s;
+ }
+ for(p=tnamesinit; p->code >= 0; p++) {
+ urk("tnames", nelem(tnames), p->code);
+ tnames[p->code] = p->s;
+ }
+ for(p=gnamesinit; p->code >= 0; p++) {
+ urk("gnames", nelem(gnames), p->code);
+ gnames[p->code] = p->s;
+ }
+ for(p=qnamesinit; p->code >= 0; p++) {
+ urk("qnames", nelem(qnames), p->code);
+ qnames[p->code] = p->s;
+ }
+ for(p=cnamesinit; p->code >= 0; p++) {
+ urk("cnames", nelem(cnames), p->code);
+ cnames[p->code] = p->s;
+ }
+ for(p=onamesinit; p->code >= 0; p++) {
+ urk("onames", nelem(onames), p->code);
+ onames[p->code] = p->s;
+ }
+ for(i=0; typeiinit[i] >= 0; i++) {
+ urk("typei", nelem(typei), typeiinit[i]);
+ typei[typeiinit[i]] = 1;
+ }
+ for(i=0; typeuinit[i] >= 0; i++) {
+ urk("typeu", nelem(typeu), typeuinit[i]);
+ typeu[typeuinit[i]] = 1;
+ }
+ for(i=0; typesuvinit[i] >= 0; i++) {
+ urk("typesuv", nelem(typesuv), typesuvinit[i]);
+ typesuv[typesuvinit[i]] = 1;
+ }
+ for(i=0; typeilpinit[i] >= 0; i++) {
+ urk("typeilp", nelem(typeilp), typeilpinit[i]);
+ typeilp[typeilpinit[i]] = 1;
+ }
+ for(i=0; typechlinit[i] >= 0; i++) {
+ urk("typechl", nelem(typechl), typechlinit[i]);
+ typechl[typechlinit[i]] = 1;
+ typechlv[typechlinit[i]] = 1;
+ typechlvp[typechlinit[i]] = 1;
+ }
+ for(i=0; typechlpinit[i] >= 0; i++) {
+ urk("typechlp", nelem(typechlp), typechlpinit[i]);
+ typechlp[typechlpinit[i]] = 1;
+ typechlvp[typechlinit[i]] = 1;
+ }
+ for(i=0; typechlpfdinit[i] >= 0; i++) {
+ urk("typechlpfd", nelem(typechlpfd), typechlpfdinit[i]);
+ typechlpfd[typechlpfdinit[i]] = 1;
+ }
+ for(i=0; typecinit[i] >= 0; i++) {
+ urk("typec", nelem(typec), typecinit[i]);
+ typec[typecinit[i]] = 1;
+ }
+ for(i=0; typehinit[i] >= 0; i++) {
+ urk("typeh", nelem(typeh), typehinit[i]);
+ typeh[typehinit[i]] = 1;
+ }
+ for(i=0; typeilinit[i] >= 0; i++) {
+ urk("typeil", nelem(typeil), typeilinit[i]);
+ typeil[typeilinit[i]] = 1;
+ }
+ for(i=0; typevinit[i] >= 0; i++) {
+ urk("typev", nelem(typev), typevinit[i]);
+ typev[typevinit[i]] = 1;
+ typechlv[typevinit[i]] = 1;
+ typechlvp[typechlinit[i]] = 1;
+ }
+ for(i=0; typefdinit[i] >= 0; i++) {
+ urk("typefd", nelem(typefd), typefdinit[i]);
+ typefd[typefdinit[i]] = 1;
+ }
+ for(i=0; typeafinit[i] >= 0; i++) {
+ urk("typeaf", nelem(typeaf), typeafinit[i]);
+ typeaf[typeafinit[i]] = 1;
+ }
+ for(i=0; typesuinit[i] >= 0; i++) {
+ urk("typesu", nelem(typesu), typesuinit[i]);
+ typesu[typesuinit[i]] = 1;
+ }
+ for(p=tasigninit; p->code >= 0; p++) {
+ urk("tasign", nelem(tasign), p->code);
+ tasign[p->code] = p->value;
+ }
+ for(p=tasaddinit; p->code >= 0; p++) {
+ urk("tasadd", nelem(tasadd), p->code);
+ tasadd[p->code] = p->value;
+ }
+ for(p=tcastinit; p->code >= 0; p++) {
+ urk("tcast", nelem(tcast), p->code);
+ tcast[p->code] = p->value;
+ }
+ for(p=taddinit; p->code >= 0; p++) {
+ urk("tadd", nelem(tadd), p->code);
+ tadd[p->code] = p->value;
+ }
+ for(p=tsubinit; p->code >= 0; p++) {
+ urk("tsub", nelem(tsub), p->code);
+ tsub[p->code] = p->value;
+ }
+ for(p=tmulinit; p->code >= 0; p++) {
+ urk("tmul", nelem(tmul), p->code);
+ tmul[p->code] = p->value;
+ }
+ for(p=tandinit; p->code >= 0; p++) {
+ urk("tand", nelem(tand), p->code);
+ tand[p->code] = p->value;
+ }
+ for(p=trelinit; p->code >= 0; p++) {
+ urk("trel", nelem(trel), p->code);
+ trel[p->code] = p->value;
+ }
+}
+
+static int
+deadhead(Node *n, int caseok)
+{
+loop:
+ if(n == Z)
+ return 1;
+ switch(n->op) {
+ case OLIST:
+ if(!deadhead(n->left, caseok))
+ return 0;
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ break;
+
+ case OLABEL:
+ return 0;
+
+ case OGOTO:
+ break;
+
+ case OCASE:
+ if(!caseok)
+ return 0;
+ goto rloop;
+
+ case OSWITCH:
+ return deadhead(n->right, 1);
+
+ case OWHILE:
+ case ODWHILE:
+ goto rloop;
+
+ case OFOR:
+ goto rloop;
+
+ case OCONTINUE:
+ break;
+
+ case OBREAK:
+ break;
+
+ case OIF:
+ return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
+
+ case OSET:
+ case OUSED:
+ break;
+ }
+ return 1;
+}
+
+int
+deadheads(Node *c)
+{
+ return deadhead(c->left, 0) && deadhead(c->right, 0);
+}
+
+int
+mixedasop(Type *l, Type *r)
+{
+ return !typefd[l->etype] && typefd[r->etype];
+}
diff --git a/utils/cp/cp.c b/utils/cp/cp.c
new file mode 100644
index 00000000..7395e16c
--- /dev/null
+++ b/utils/cp/cp.c
@@ -0,0 +1,118 @@
+#include <lib9.h>
+
+#define DEFB (8*1024)
+
+void copy(char *from, char *to, int todir);
+void copy1(int fdf, int fdt, char *from, char *to);
+void fixbackslash(char *file);
+
+void
+main(int argc, char *argv[])
+{
+ Dir *dirb;
+ int todir, i;
+
+ if(argc<3){
+ fprint(2, "usage:\tcp fromfile tofile\n");
+ fprint(2, "\tcp fromfile ... todir\n");
+ exits("usage");
+ }
+
+ for(i=0; i<argc; i++)
+ fixbackslash(argv[i]);
+
+
+ todir=0;
+ if((dirb = dirstat(argv[argc-1]))!=nil && (dirb->mode&DMDIR))
+ todir=1;
+ if(argc>3 && !todir){
+ fprint(2, "cp: %s not a directory\n", argv[argc-1]);
+ exits("bad usage");
+ }
+ for(i=1; i<argc-1; i++)
+ copy(argv[i], argv[argc-1], todir);
+ exits(0);
+}
+
+void
+copy(char *from, char *to, int todir)
+{
+ Dir *dirb, *dirt;
+ char name[256];
+ int fdf, fdt;
+
+ if(todir){
+ char *s, *elem;
+ elem=s=from;
+ while(*s++)
+ if(s[-1]=='/')
+ elem=s;
+ sprint(name, "%s/%s", to, elem);
+ to=name;
+ }
+ if((dirb = dirstat(from))==nil){
+ fprint(2,"cp: can't stat %s: %r\n", from);
+ return;
+ }
+ if(dirb->mode&DMDIR){
+ fprint(2, "cp: %s is a directory\n", from);
+ return;
+ }
+ dirb->mode &= 0777;
+ if((dirt = dirstat(to))!=nil)
+ if(dirb->qid.path==dirt->qid.path && dirb->qid.vers==dirt->qid.vers)
+ if(dirb->dev==dirt->dev && dirb->type==dirt->type){
+ fprint(2, "cp: %s and %s are the same file\n", from, to);
+ return;
+ }
+ fdf=open(from, OREAD);
+ if(fdf<0){
+ fprint(2, "cp: can't open %s: %r\n", from);
+ return;
+ }
+ fdt=create(to, OWRITE, dirb->mode);
+ if(fdt<0){
+ fprint(2, "cp: can't create %s: %r\n", to);
+ close(fdf);
+ return;
+ }
+ copy1(fdf, fdt, from, to);
+ close(fdf);
+ close(fdt);
+}
+
+void
+copy1(int fdf, int fdt, char *from, char *to)
+{
+ char *buf;
+ long n, n1, rcount;
+ char err[ERRMAX];
+
+ buf = malloc(DEFB);
+ /* clear any residual error */
+ err[0] = '\0';
+ errstr(err, ERRMAX);
+ for(rcount=0;; rcount++) {
+ n = read(fdf, buf, DEFB);
+ if(n <= 0)
+ break;
+ n1 = write(fdt, buf, n);
+ if(n1 != n) {
+ fprint(2, "cp: error writing %s: %r\n", to);
+ break;
+ }
+ }
+ if(n < 0)
+ fprint(2, "cp: error reading %s: %r\n", from);
+ free(buf);
+}
+
+void
+fixbackslash(char *file)
+{
+ char *p;
+
+ for(p=file; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+}
diff --git a/utils/cp/mkfile b/utils/cp/mkfile
new file mode 100644
index 00000000..722c269e
--- /dev/null
+++ b/utils/cp/mkfile
@@ -0,0 +1,22 @@
+<../../mkconfig
+
+TARG=cp
+
+OFILES= cp.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+#
+# override install so that cp doesn't try to copy onto itself
+#
+
+$BIN/%: $O.out
+ cp $target cpx.exe
+ ./cpx $O.out $target
+ rm cpx.exe
diff --git a/utils/data2c/data2c.c b/utils/data2c/data2c.c
new file mode 100644
index 00000000..faf597c5
--- /dev/null
+++ b/utils/data2c/data2c.c
@@ -0,0 +1,33 @@
+#include <lib9.h>
+#include <bio.h>
+
+void
+main(int argc, char *argv[])
+{
+ Biobuf bin, bout;
+ long len;
+ int n;
+ uchar block[16], *c;
+
+ if(argc != 2){
+ fprint(2, "usage: data2s name\n");
+ exits("usage");
+ }
+ setbinmode();
+ Binit(&bin, 0, OREAD);
+ Binit(&bout, 1, OWRITE);
+ Bprint(&bout, "unsigned char %scode[] = {\n", argv[1]);
+ for(len=0; (n=Bread(&bin, block, sizeof(block))) > 0; len += n){
+ for(c=block; c < block+n; c++)
+ if(*c)
+ Bprint(&bout, "0x%ux,", *c);
+ else
+ Bprint(&bout, "0,");
+ Bprint(&bout, "\n");
+ }
+ if(len == 0)
+ Bprint(&bout, "0\n"); /* avoid empty initialiser */
+ Bprint(&bout, "};\n");
+ Bprint(&bout, "int %slen = %ld;\n", argv[1], len);
+ exits(0);
+}
diff --git a/utils/data2c/mkfile b/utils/data2c/mkfile
new file mode 100644
index 00000000..047ddb3e
--- /dev/null
+++ b/utils/data2c/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=data2c
+
+OFILES= data2c.$O\
+
+HFILES=../../include/bio.h
+
+LIBS=bio 9 #order matters
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/data2s/data2s.c b/utils/data2s/data2s.c
new file mode 100644
index 00000000..97244fb1
--- /dev/null
+++ b/utils/data2s/data2s.c
@@ -0,0 +1,32 @@
+#include <lib9.h>
+#include <bio.h>
+
+void
+main(int argc, char *argv[])
+{
+ Biobuf bin, bout;
+ long len;
+ int n;
+ uchar block[8], *c;
+
+ if(argc != 2){
+ fprint(2, "usage: data2s name\n");
+ exits("usage");
+ }
+ setbinmode();
+ Binit(&bin, 0, OREAD);
+ Binit(&bout, 1, OWRITE);
+ for(len=0; (n=Bread(&bin, block, sizeof(block))) > 0; len += n){
+ Bprint(&bout, "DATA %scode+%ld(SB)/%d, $\"", argv[1], len, n);
+ for(c=block; c < block+n; c++)
+ if(*c)
+ Bprint(&bout, "\\%uo", *c);
+ else
+ Bprint(&bout, "\\z");
+ Bprint(&bout, "\"\n");
+ }
+ Bprint(&bout, "GLOBL %scode+0(SB), $%ld\n", argv[1], len);
+ Bprint(&bout, "GLOBL %slen+0(SB), $4\n", argv[1]);
+ Bprint(&bout, "DATA %slen+0(SB)/4, $%ld\n", argv[1], len);
+ exits(0);
+}
diff --git a/utils/data2s/mkfile b/utils/data2s/mkfile
new file mode 100644
index 00000000..9b712aa8
--- /dev/null
+++ b/utils/data2s/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=data2s
+
+OFILES= data2s.$O\
+
+HFILES=../../include/bio.h
+
+LIBS=bio 9 #order matters
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/echo/echo.c b/utils/echo/echo.c
new file mode 100644
index 00000000..9574e129
--- /dev/null
+++ b/utils/echo/echo.c
@@ -0,0 +1,33 @@
+#include <lib9.h>
+
+void
+main(int argc, char *argv[])
+{
+ int nflag;
+ int i, len;
+ char *buf, *p;
+
+ nflag = 0;
+ if(argc > 1 && strcmp(argv[1], "-n") == 0)
+ nflag = 1;
+
+ len = 1;
+ for(i = 1+nflag; i < argc; i++)
+ len += strlen(argv[i])+1;
+
+ buf = malloc(len);
+ if(buf == 0)
+ exits("no memory");
+
+ p = buf;
+ for(i = 1+nflag; i < argc; i++)
+ p += sprint(p, i == argc-1 ? "%s":"%s ", argv[i]);
+
+ if(!nflag)
+ sprint(p, "\n");
+
+ if(write(1, buf, strlen(buf)) < 0)
+ fprint(2, "echo: write error: %r\n");
+
+ exits((char *)0);
+}
diff --git a/utils/echo/mkfile b/utils/echo/mkfile
new file mode 100644
index 00000000..fed9561b
--- /dev/null
+++ b/utils/echo/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=echo
+
+OFILES= echo.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/format/Nt.c b/utils/format/Nt.c
new file mode 100644
index 00000000..f2239f3c
--- /dev/null
+++ b/utils/format/Nt.c
@@ -0,0 +1,47 @@
+#include <lib9.h>
+
+int
+initfflag()
+{
+ return 1;
+}
+
+Tm *
+getlocaltime()
+{
+ static Tm tmstruct;
+
+ time_t t = time((time_t *)0);
+ struct tm *ts = localtime(&t);
+ Tm *tt = &tmstruct;
+
+ tt->hour = ts->tm_hour;
+ tt->min = ts->tm_min;
+ tt->sec = ts->tm_sec;
+ tt->year = ts->tm_year;
+ tt->mon = ts->tm_mon;
+ tt->mday = ts->tm_mday;
+ tt->wday = ts->tm_wday;
+ tt->yday = ts->tm_yday;
+ return tt;
+}
+
+int
+openfloppy(char *dev)
+{
+ char buf[16];
+
+ /* if dev is of the form "x:" use "\\.\x:" instead */
+ if (strlen(dev) == 2 && dev[1] == ':') {
+ if (dev[0] == 'a' || dev[0] == 'A') {
+ strcpy(buf, "\\\\.\\");
+ strcat(buf, dev);
+ return open(buf, ORDWR);
+ }
+ else {
+ print("can only open A: drive\n");
+ return -1;
+ }
+ }
+ return open(dev, ORDWR);
+}
diff --git a/utils/format/Plan9.c b/utils/format/Plan9.c
new file mode 100644
index 00000000..2cf97970
--- /dev/null
+++ b/utils/format/Plan9.c
@@ -0,0 +1,19 @@
+#include <lib9.h>
+
+int
+initfflag()
+{
+ return 0;
+}
+
+Tm *
+getlocaltime()
+{
+ return localtime(time(0));
+}
+
+int
+openfloppy(char *dev)
+{
+ return create(dev, ORDWR, 0666);
+}
diff --git a/utils/format/format.c b/utils/format/format.c
new file mode 100644
index 00000000..f9963572
--- /dev/null
+++ b/utils/format/format.c
@@ -0,0 +1,574 @@
+#include <lib9.h>
+
+/*
+ * floppy types (all MFM encoding)
+ */
+typedef struct Type Type;
+struct Type
+{
+ char *name;
+ int bytes; /* bytes/sector */
+ int sectors; /* sectors/track */
+ int heads; /* number of heads */
+ int tracks; /* tracks/disk */
+ int media; /* media descriptor byte */
+ int cluster; /* default cluster size */
+};
+Type floppytype[] =
+{
+ { "3½HD", 512, 18, 2, 80, 0xf0, 1, },
+ { "3½DD", 512, 9, 2, 80, 0xf9, 2, },
+ { "5¼HD", 512, 15, 2, 80, 0xf9, 1, },
+ { "5¼DD", 512, 9, 2, 40, 0xfd, 2, },
+};
+#define NTYPES (sizeof(floppytype)/sizeof(Type))
+
+typedef struct Dosboot Dosboot;
+struct Dosboot{
+ uchar magic[3]; /* really an xx86 JMP instruction */
+ uchar version[8];
+ uchar sectsize[2];
+ uchar clustsize;
+ uchar nresrv[2];
+ uchar nfats;
+ uchar rootsize[2];
+ uchar volsize[2];
+ uchar mediadesc;
+ uchar fatsize[2];
+ uchar trksize[2];
+ uchar nheads[2];
+ uchar nhidden[4];
+ uchar bigvolsize[4];
+ uchar driveno;
+ uchar reserved0;
+ uchar bootsig;
+ uchar volid[4];
+ uchar label[11];
+ uchar type[8];
+};
+#define PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); }
+#define PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); }
+
+typedef struct Dosdir Dosdir;
+struct Dosdir
+{
+ uchar name[8];
+ uchar ext[3];
+ uchar attr;
+ uchar reserved[10];
+ uchar time[2];
+ uchar date[2];
+ uchar start[2];
+ uchar length[4];
+};
+
+#define DRONLY 0x01
+#define DHIDDEN 0x02
+#define DSYSTEM 0x04
+#define DVLABEL 0x08
+#define DDIR 0x10
+#define DARCH 0x20
+
+/*
+ * the boot program for the boot sector.
+ */
+uchar bootprog[512];
+uchar bootprog1[16] =
+{
+ 0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+uchar bootprog2[128] =
+{
+ 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
+ 0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
+ 0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
+ 0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
+ 0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
+ 0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
+ 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
+ 0xC3, 'N', 'o', 't', ' ', 'a', ' ', 'b',
+ 'o', 'o', 't', 'a', 'b', 'l', 'e', ' ',
+ 'd', 'i', 's', 'c', ' ', 'o', 'r', ' ',
+ 'd', 'i', 's', 'c', ' ', 'e', 'r', 'r',
+ 'o', 'r', '\r', '\n', 'P', 'r', 'e', 's',
+ 's', ' ', 'a', 'l', 'm', 'o', 's', 't',
+ ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y',
+ ' ', 't', 'o', ' ', 'r', 'e', 'b', 'o',
+ 'o', 't', '.', '.', '.', 0x00, 0x00, 0x00,
+};
+uchar bootprog3[16] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA,
+};
+
+static void
+mkbootprog(void)
+{
+ int i;
+
+ for (i = 0; i < 512; i++)
+ bootprog[i] = 0;
+ for (i = 0; i < 16; i++)
+ bootprog[i+0x000] = bootprog1[i];
+ for (i = 0; i < 128; i++)
+ bootprog[i+0x03E] = bootprog2[i];
+ for (i = 0; i < 16; i++)
+ bootprog[i+0x1F0] = bootprog3[i];
+}
+
+char *dev;
+int clustersize;
+uchar *fat; /* the fat */
+int fatbits;
+int fatsecs;
+int fatlast; /* last cluster allocated */
+int clusters;
+int fatsecs;
+int volsecs;
+uchar *root; /* first block of root */
+int rootsecs;
+int rootfiles;
+int rootnext;
+Type *t;
+int fflag;
+char file[64]; /* output file name */
+char *bootfile;
+char *type;
+
+enum
+{
+ Sof = 1, /* start of file */
+ Eof = 2, /* end of file */
+};
+
+
+void dosfs(int, char*, int, char*[]);
+ulong clustalloc(int);
+void addrname(uchar*, Dir*, ulong, char *);
+
+int initfflag(void);
+Tm *getlocaltime(void);
+int openfloppy(char *);
+
+void
+usage(void)
+{
+ fprint(2, "usage: format [-b bfile] [-c csize] [-df] [-l label] [-t type] file [args ...]\n");
+ exits("usage");
+}
+
+void
+fatal(char *fmt, ...)
+{
+ char err[128];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(err, err+sizeof(err), fmt, arg);
+ va_end(arg);
+ fprint(2, "format: %s\n", err);
+ if(fflag && file[0])
+ remove(file);
+ exits(err);
+}
+
+void
+main(int argc, char **argv)
+{
+ int n, dos;
+ int cfd;
+ char buf[512];
+ char label[11];
+ char *a;
+
+ fflag = initfflag();
+ mkbootprog();
+ dos = 0;
+ type = 0;
+ clustersize = 0;
+ memmove(label, "CYLINDRICAL", sizeof(label));
+ ARGBEGIN {
+ case 'b':
+ bootfile = ARGF();
+ break;
+ case 'd':
+ dos = 1;
+ break;
+ case 'c':
+ clustersize = atoi(ARGF());
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'l':
+ a = ARGF();
+ n = strlen(a);
+ if(n > sizeof(label))
+ n = sizeof(label);
+ memmove(label, a, n);
+ while(n < sizeof(label))
+ label[n++] = ' ';
+ break;
+ case 't':
+ type = ARGF();
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if(argc < 1)
+ usage();
+
+ dev = argv[0];
+ cfd = -1;
+ if(fflag == 0){
+ n = strlen(argv[0]);
+ if(n > 4 && strcmp(argv[0]+n-4, "disk") == 0)
+ *(argv[0]+n-4) = 0;
+ else if(n > 3 && strcmp(argv[0]+n-3, "ctl") == 0)
+ *(argv[0]+n-3) = 0;
+
+ sprint(buf, "%sctl", dev);
+ cfd = open(buf, ORDWR);
+ if(cfd < 0)
+ fatal("opening %s: %r", buf);
+ print("Formatting floppy %s\n", dev);
+ if(type)
+ sprint(buf, "format %s", type);
+ else
+ strcpy(buf, "format");
+ if(write(cfd, buf, strlen(buf)) < 0)
+ fatal("formatting tracks: %r");
+ }
+
+ if(dos)
+ dosfs(cfd, label, argc-1, argv+1);
+ if(cfd >= 0)
+ close(cfd);
+ exits(0);
+}
+
+void
+dosfs(int cfd, char *label, int argc, char *argv[])
+{
+ char r[16];
+ Dosboot *b;
+ uchar *buf;
+ Dir *d;
+ int n, fd, sysfd;
+ ulong length, x;
+ uchar *p;
+
+ print("Initialising MS-DOS file system\n");
+
+ if(fflag){
+ sprint(file, "%s", dev);
+ if ((fd = openfloppy(dev)) < 0)
+ fatal("create %s: %r", file);
+ t = floppytype;
+ if(type){
+ for(t = floppytype; t < &floppytype[NTYPES]; t++)
+ if(strcmp(type, t->name) == 0)
+ break;
+ if(t == &floppytype[NTYPES])
+ fatal("unknown floppy type %s", type);
+ }
+ length = t->bytes*t->sectors*t->heads*t->tracks;
+ }
+ else{
+ sprint(file, "%sdisk", dev);
+ fd = open(file, ORDWR);
+ if(fd < 0)
+ fatal("open %s: %r", file);
+ d = dirfstat(fd);
+ if(d == nil)
+ fatal("stat %s: %r", file);
+ length = d->length;
+ free(d);
+
+ t = 0;
+ seek(cfd, 0, 0);
+ n = read(cfd, file, sizeof(file)-1);
+ if(n < 0)
+ fatal("reading floppy type");
+ else {
+ file[n] = 0;
+ for(t = floppytype; t < &floppytype[NTYPES]; t++)
+ if(strcmp(file, t->name) == 0)
+ break;
+ if(t == &floppytype[NTYPES])
+ fatal("unknown floppy type %s", file);
+ }
+ }
+ print("floppy type %s, %d tracks, %d heads, %d sectors/track, %d bytes/sec\n",
+ t->name, t->tracks, t->heads, t->sectors, t->bytes);
+
+ if(clustersize == 0)
+ clustersize = t->cluster;
+ clusters = length/(t->bytes*clustersize);
+ if(clusters < 4087)
+ fatbits = 12;
+ else
+ fatbits = 16;
+ volsecs = length/t->bytes;
+ fatsecs = (fatbits*clusters + 8*t->bytes - 1)/(8*t->bytes);
+ rootsecs = volsecs/200;
+ rootfiles = rootsecs * (t->bytes/sizeof(Dosdir));
+ buf = malloc(t->bytes);
+ if(buf == 0)
+ fatal("out of memory");
+
+ /*
+ * write bootstrap & parameter block
+ */
+ if(bootfile){
+ if((sysfd = open(bootfile, OREAD)) < 0)
+ fatal("open %s: %r", bootfile);
+ if(read(sysfd, buf, t->bytes) < 0)
+ fatal("read %s: %r", bootfile);
+ close(sysfd);
+ }
+ else
+ memmove(buf, bootprog, sizeof(bootprog));
+ b = (Dosboot*)buf;
+ b->magic[0] = 0xEB;
+ b->magic[1] = 0x3C;
+ b->magic[2] = 0x90;
+ memmove(b->version, "Plan9.00", sizeof(b->version));
+ PUTSHORT(b->sectsize, t->bytes);
+ b->clustsize = clustersize;
+ PUTSHORT(b->nresrv, 1);
+ b->nfats = 2;
+ PUTSHORT(b->rootsize, rootfiles);
+ if(volsecs < (1<<16)){
+ PUTSHORT(b->volsize, volsecs);
+ }
+ PUTLONG(b->bigvolsize, volsecs);
+ b->mediadesc = t->media;
+ PUTSHORT(b->fatsize, fatsecs);
+ PUTSHORT(b->trksize, t->sectors);
+ PUTSHORT(b->nheads, t->heads);
+ PUTLONG(b->nhidden, 0);
+ b->driveno = 0;
+ b->bootsig = 0x29;
+ x = time(0);
+ PUTLONG(b->volid, x);
+ memmove(b->label, label, sizeof(b->label));
+ sprint(r, "FAT%d ", fatbits);
+ memmove(b->type, r, sizeof(b->type));
+ buf[t->bytes-2] = 0x55;
+ buf[t->bytes-1] = 0xAA;
+ if(seek(fd, 0, 0) < 0)
+ fatal("seek to boot sector: %r\n");
+ if(write(fd, buf, t->bytes) != t->bytes)
+ fatal("writing boot sector: %r");
+ free(buf);
+
+ /*
+ * allocate an in memory fat
+ */
+ fat = malloc(fatsecs*t->bytes);
+ if(fat == 0)
+ fatal("out of memory");
+ memset(fat, 0, fatsecs*t->bytes);
+ fat[0] = t->media;
+ fat[1] = 0xff;
+ fat[2] = 0xff;
+ if(fatbits == 16)
+ fat[3] = 0xff;
+ fatlast = 1;
+ if (seek(fd, 2*fatsecs*t->bytes, 1) < 0)
+ fatal("seek to 2 fats: %r"); /* 2 fats */
+
+ /*
+ * allocate an in memory root
+ */
+ root = malloc(rootsecs*t->bytes);
+ if(root == 0)
+ fatal("out of memory");
+ memset(root, 0, rootsecs*t->bytes);
+ if (seek(fd, rootsecs*t->bytes, 1) < 0)
+ fatal("seek to root: %r"); /* rootsecs */
+
+ /*
+ * Now positioned at the Files Area.
+ * If we have any arguments, process
+ * them and write out.
+ */
+ for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){
+ if(p >= (root+(rootsecs*t->bytes)))
+ fatal("too many files in root");
+ /*
+ * Open the file and get its length.
+ */
+ if((sysfd = open(*argv, OREAD)) < 0)
+ fatal("open %s: %r", *argv);
+ d = dirfstat(sysfd);
+ if(d == nil)
+ fatal("stat %s: %r", *argv);
+ print("Adding file %s, length %lld\n", *argv, d->length);
+
+ length = d->length;
+ if(length){
+ /*
+ * Allocate a buffer to read the entire file into.
+ * This must be rounded up to a cluster boundary.
+ *
+ * Read the file and write it out to the Files Area.
+ */
+ length += t->bytes*clustersize - 1;
+ length /= t->bytes*clustersize;
+ length *= t->bytes*clustersize;
+ if((buf = malloc(length)) == 0)
+ fatal("out of memory");
+
+ if(read(sysfd, buf, d->length) < 0)
+ fatal("read %s: %r", *argv);
+ memset(buf+d->length, 0, length-d->length);
+ /* if(write(fd, buf, length) < 0) */
+ if (write(fd, buf, length) != length)
+ fatal("write %s: %r", *argv);
+ free(buf);
+
+ close(sysfd);
+
+ /*
+ * Allocate the FAT clusters.
+ * We're assuming here that where we
+ * wrote the file is in sync with
+ * the cluster allocation.
+ * Save the starting cluster.
+ */
+ length /= t->bytes*clustersize;
+ x = clustalloc(Sof);
+ for(n = 0; n < length-1; n++)
+ clustalloc(0);
+ clustalloc(Eof);
+ }
+ else
+ x = 0;
+
+ /*
+ * Add the filename to the root.
+ */
+ addrname(p, d, x, *argv);
+ free(d);
+ }
+
+ /*
+ * write the fats and root
+ */
+ if (seek(fd, t->bytes, 0) < 0)
+ fatal("seek to fat1: %r");
+ /* if(write(fd, fat, fatsecs*t->bytes) < 0) */
+ if (write(fd, fat, fatsecs*t->bytes) != fatsecs*t->bytes)
+ fatal("writing fat #1: %r");
+ /* if(write(fd, fat, fatsecs*t->bytes) < 0) */
+ if (write(fd, fat, fatsecs*t->bytes) != fatsecs*t->bytes)
+ fatal("writing fat #2: %r");
+ /* if(write(fd, root, rootsecs*t->bytes) < 0) */
+ if (write(fd, root, rootsecs*t->bytes) != rootsecs*t->bytes)
+ fatal("writing root: %r");
+
+ if(fflag){
+ if (seek(fd, t->bytes*t->sectors*t->heads*t->tracks-1, 0) < 0)
+ /* fatal("seek to 9: %r") */ {}
+ if (write(fd, "9", 1) != 1)
+ /* fatal("writing 9: %r") */ {}
+ }
+}
+
+/*
+ * allocate a cluster
+ */
+ulong
+clustalloc(int flag)
+{
+ ulong o, x;
+
+ if(flag != Sof){
+ x = (flag == Eof) ? 0xffff : (fatlast+1);
+ if(fatbits == 12){
+ x &= 0xfff;
+ o = (3*fatlast)/2;
+ if(fatlast & 1){
+ fat[o] = (fat[o]&0x0f) | (x<<4);
+ fat[o+1] = (x>>4);
+ } else {
+ fat[o] = x;
+ fat[o+1] = (fat[o+1]&0xf0) | ((x>>8) & 0x0F);
+ }
+ } else {
+ o = 2*fatlast;
+ fat[o] = x;
+ fat[o+1] = x>>8;
+ }
+ }
+
+ if(flag == Eof)
+ return 0;
+ else
+ return ++fatlast;
+}
+
+void
+putname(char *p, Dosdir *d)
+{
+ int i;
+ char *q;
+
+ q = strrchr(p, '/');
+ if (q)
+ p = q+1;
+ q = strrchr(p, '\\');
+ if (q)
+ p = q+1;
+ memset(d->name, ' ', sizeof d->name+sizeof d->ext);
+ for(i = 0; i< sizeof(d->name); i++){
+ if(*p == 0 || *p == '.')
+ break;
+ d->name[i] = toupper(*p++);
+ }
+ p = strrchr(p, '.');
+ if(p){
+ for(i = 0; i < sizeof d->ext; i++){
+ if(*++p == 0)
+ break;
+ d->ext[i] = toupper(*p);
+ }
+ }
+}
+
+void
+puttime(Dosdir *d)
+{
+ Tm *t = getlocaltime();
+ ushort x;
+
+ x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
+ d->time[0] = x;
+ d->time[1] = x>>8;
+ x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
+ d->date[0] = x;
+ d->date[1] = x>>8;
+}
+
+void
+addrname(uchar *entry, Dir *dir, ulong start, char *nm)
+{
+ Dosdir *d;
+
+ d = (Dosdir*)entry;
+ /* putname(dir->name, d); */
+ putname(nm, d);
+ d->attr = DRONLY;
+ puttime(d);
+ d->start[0] = start;
+ d->start[1] = start>>8;
+ d->length[0] = dir->length;
+ d->length[1] = dir->length>>8;
+ d->length[2] = dir->length>>16;
+ d->length[3] = dir->length>>24;
+}
diff --git a/utils/format/mkfile b/utils/format/mkfile
new file mode 100644
index 00000000..02b153d3
--- /dev/null
+++ b/utils/format/mkfile
@@ -0,0 +1,14 @@
+<../../mkconfig
+
+TARG=format
+
+OFILES= format.$O\
+ $TARGMODEL.$O\
+
+HFILES=
+
+LIBS=9 # libbio.a uses lib9.a so order matters.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/ftl/ftl.c b/utils/ftl/ftl.c
new file mode 100644
index 00000000..231f1ae5
--- /dev/null
+++ b/utils/ftl/ftl.c
@@ -0,0 +1,867 @@
+/*
+ * basic Flash Translation Layer driver
+ * see for instance the Intel technical paper
+ * ``Understanding the Flash Translation Layer (FTL) Specification''
+ * Order number 297816-001 (online at www.intel.com)
+ *
+ * a public driver by David Hinds, dhinds@allegro.stanford.edu
+ * further helps with some details.
+ *
+ * this driver uses the common simplification of never storing
+ * the VBM on the medium (a waste of precious flash!) but
+ * rather building it on the fly as the block maps are read.
+ *
+ * Plan 9 driver (c) 1997 by C H Forsyth (forsyth@caldo.demon.co.uk)
+ * This driver may be used or adapted by anyone for any non-commercial purpose.
+ *
+ * adapted for Inferno 1998 by C H Forsyth, Vita Nuova Limited, York, England (charles@vitanuova.com)
+ *
+ * C H Forsyth and Vita Nuova Limited expressly allow Lucent Technologies
+ * to use this driver freely for any Inferno-related purposes whatever,
+ * including commercial applications.
+ *
+ * TO DO:
+ * check error handling details for get/put flash
+ * bad block handling
+ * reserved space in formatted size
+ * possibly block size as parameter
+ * fetch parameters from header on init
+ *
+ * Adapted to a ftl formatter for Inferno 2000 by J R Firth, Vita Nuova Limited
+ * usage : ftl flashsize secsize inputfile outputfile
+ * outputfile will then be a ftl image of inputfile
+ * nb assumes the base address is zero
+ *
+ */
+
+#include <lib9.h>
+
+ulong flashsize, secsize;
+char *flashm;
+int trace = 0;
+
+#ifndef offsetof
+#define offsetof(T,X) ((ulong)&(((T*)0)->X))
+#endif
+
+typedef struct Ftl Ftl;
+typedef struct Merase Merase;
+typedef struct Terase Terase;
+
+enum {
+ Eshift = 18, /* 2^18=256k; log2(eraseunit) */
+ Flashseg = 1<<Eshift,
+ Bshift = 9, /* 2^9=512 */
+ Bsize = 1<<Bshift,
+ BAMoffset = 0x100,
+ Nolimit = ~0,
+ USABLEPCT = 95, /* release only this % to client */
+
+ FTLDEBUG = 0
+};
+
+/* erase unit header (defined by FTL specification) */
+struct Merase {
+ uchar linktuple[5];
+ uchar orgtuple[10];
+ uchar nxfer;
+ uchar nerase[4];
+ uchar id[2];
+ uchar bshift;
+ uchar eshift;
+ uchar pstart[2];
+ uchar nunits[2];
+ uchar psize[4];
+ uchar vbmbase[4];
+ uchar nvbm[2];
+ uchar flags;
+ uchar code;
+ uchar serial[4];
+ uchar altoffset[4];
+ uchar bamoffset[4];
+ uchar rsv2[12];
+};
+#define ERASEHDRLEN 64
+
+enum {
+ /* special unit IDs */
+ XferID = 0xffff,
+ XferBusy = 0x7fff,
+
+ /* special BAM addresses */
+ Bfree = 0xffffffff,
+ Bwriting = 0xfffffffe,
+ Bdeleted = 0,
+
+ /* block types */
+ TypeShift = 7,
+ BlockType = (1<<TypeShift)-1,
+ ControlBlock = 0x30,
+ DataBlock = 0x40,
+ ReplacePage = 0x60,
+ BadBlock = 0x70,
+};
+
+#define BTYPE(b) ((b) & BlockType)
+#define BADDR(b) ((b) & ~BlockType)
+#define BNO(va) (((ulong)(va))>>Bshift)
+#define MKBAM(b,t) (((b)<<Bshift)|(t))
+
+struct Terase {
+ int x;
+ int id;
+ ulong offset;
+ ulong bamoffset;
+ ulong nbam;
+ ulong* bam;
+ ulong bamx;
+ ulong nfree;
+ ulong nused;
+ ulong ndead;
+ ulong nbad;
+ ulong nerase;
+};
+
+struct Ftl {
+ ulong base; /* base of flash region */
+ ulong size; /* size of flash region */
+ ulong segsize; /* size of flash segment (erase unit) */
+ int eshift; /* log2(erase-unit-size) */
+ int bshift; /* log2(bsize) */
+ int bsize;
+ int nunit; /* number of segments (erase units) */
+ Terase** unit;
+ int lastx; /* index in unit of last allocation */
+ int xfer; /* index in unit of current transfer unit (-1 if none) */
+ ulong nfree; /* total free space in blocks */
+ ulong nblock; /* total space in blocks */
+ ulong rwlimit; /* user-visible block limit (`formatted size') */
+ ulong* vbm; /* virtual block map */
+ ulong fstart; /* address of first block of data in a segment */
+ int trace; /* (debugging) trace of read/write actions */
+ int detach; /* free Ftl on last close */
+
+ /* scavenging variables */
+ int needspace;
+ int hasproc;
+};
+
+enum {
+ /* Ftl.detach */
+ Detached = 1, /* detach on close */
+ Deferred /* scavenger must free it */
+};
+
+/* little endian */
+#define GET2(p) (((p)[1]<<8)|(p)[0])
+#define GET4(p) (((((((p)[3]<<8)|(p)[2])<<8)|(p)[1])<<8)|(p)[0])
+#define PUT2(p,v) (((p)[1]=(v)>>8),((p)[0]=(v)))
+#define PUT4(p,v) (((p)[3]=(v)>>24),((p)[2]=(v)>>16),((p)[1]=(v)>>8),((p)[0]=(v)))
+
+static Ftl *ftls;
+
+static ulong allocblk(Ftl*);
+static void eraseflash(Ftl*, ulong);
+static void erasefree(Terase*);
+static void eraseinit(Ftl*, ulong, int, int);
+static Terase* eraseload(Ftl*, int, ulong);
+static void ftlfree(Ftl*);
+static void getflash(Ftl*, void*, ulong, long);
+static int mapblk(Ftl*, ulong, Terase**, ulong*);
+static Ftl* mkftl(char*, ulong, ulong, int, char*);
+static void putbam(Ftl*, Terase*, int, ulong);
+static void putflash(Ftl*, ulong, void*, long);
+static int scavenge(Ftl*);
+
+static void
+ftlstat(int sz)
+{
+ print("0x%lux:0x%ux:0x%lux\n", ftls->rwlimit*Bsize, sz, flashsize);
+ print("%lud:%d:%lud in 512b blocks\n", ftls->rwlimit, sz>>Bshift, flashsize>>Bshift);
+}
+
+static long
+ftlread(void *buf, long n, ulong offset)
+{
+ Ftl *ftl;
+ Terase *e;
+ int nb;
+ uchar *a;
+ ulong pb;
+
+ if(n <= 0 || n%Bsize || offset%Bsize) {
+ fprint(2, "bad read\n");
+ exits("1");
+ }
+ ftl = ftls;
+ nb = n/Bsize;
+ offset /= Bsize;
+ if(offset >= ftl->rwlimit)
+ return 0;
+ if(offset+nb > ftl->rwlimit)
+ nb = ftl->rwlimit - offset;
+ a = buf;
+ for(n = 0; n < nb; n++){
+ if(mapblk(ftl, offset+n, &e, &pb))
+ getflash(ftl, a, e->offset + pb*Bsize, Bsize);
+ else
+ memset(a, 0, Bsize);
+ a += Bsize;
+ }
+ return a-(uchar*)buf;
+ return 0; /* not reached */
+}
+
+static long
+ftlwrite(void *buf, long n, ulong offset)
+{
+ int ns, nb;
+ uchar *a;
+ Terase *e, *oe;
+ ulong ob, v;
+ Ftl *ftl;
+
+ if(n <= 0)
+ return 0;
+ ftl = ftls;
+ if(n <= 0 || n%Bsize || offset%Bsize) {
+ fprint(2, "bad write\n");
+ exits("1");
+ }
+ nb = n/Bsize;
+ offset /= Bsize;
+ if(offset >= ftl->rwlimit)
+ return 0;
+ if(offset+nb > ftl->rwlimit)
+ nb = ftl->rwlimit - offset;
+ a = buf;
+ for(n = 0; n < nb; n++){
+ ns = 0;
+ while((v = allocblk(ftl)) == 0)
+ if(!scavenge(ftl) || ++ns > 3){
+ print("ftl: flash memory full\n");
+ }
+ if(!mapblk(ftl, offset+n, &oe, &ob))
+ oe = nil;
+ e = ftl->unit[v>>16];
+ v &= 0xffff;
+ putflash(ftl, e->offset + v*Bsize, a, Bsize);
+ putbam(ftl, e, v, MKBAM(offset+n, DataBlock));
+ /* both old and new block references exist in this window (can't be closed?) */
+ ftl->vbm[offset+n] = (e->x<<16) | v;
+ if(oe != nil){
+ putbam(ftl, oe, ob, Bdeleted);
+ oe->ndead++;
+ }
+ a += Bsize;
+ }
+ return a-(uchar*)buf;
+ return 0; /* not reached */
+}
+
+static Ftl *
+mkftl(char *fname, ulong base, ulong size, int eshift, char *op)
+{
+ int i, j, nov, segblocks;
+ ulong limit;
+ Terase *e;
+ Ftl *ftl;
+
+ ftl = malloc(sizeof(*ftl));
+ if(ftl == nil) {
+ fprint(2, "out of memory\n");
+ exits("1");
+ }
+ ftl->lastx = 0;
+ ftl->detach = 0;
+ ftl->needspace = 0;
+ ftl->hasproc = 0;
+ ftl->trace = 0;
+ limit = flashsize;
+ if(size == Nolimit)
+ size = limit-base;
+ if(base >= limit || size > limit || base+size > limit || eshift < 8 || (1<<eshift) > size) {
+ fprint(2, "bad flash space parameters");
+ exits("1");
+ }
+ if(FTLDEBUG || ftl->trace || trace)
+ print("%s flash %s #%lux:#%lux limit #%lux\n", op, fname, base, size, limit);
+ ftl->base = base;
+ ftl->size = size;
+ ftl->bshift = Bshift;
+ ftl->bsize = Bsize;
+ ftl->eshift = eshift;
+ ftl->segsize = 1<<eshift;
+ ftl->nunit = size>>eshift;
+ nov = ((ftl->segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize; /* number of overhead blocks per segment (header, and BAM itself) */
+ ftl->fstart = nov;
+ segblocks = ftl->segsize/Bsize - nov;
+ ftl->nblock = ftl->nunit*segblocks;
+ if(ftl->nblock >= 0x10000)
+ ftl->nblock = 0x10000;
+ ftl->vbm = malloc(ftl->nblock*sizeof(*ftl->vbm));
+ ftl->unit = malloc(ftl->nunit*sizeof(*ftl->unit));
+ if(ftl->vbm == nil || ftl->unit == nil) {
+ fprint(2, "out of mem");
+ exits("1");
+ }
+ for(i=0; i<ftl->nblock; i++)
+ ftl->vbm[i] = 0;
+ if(strcmp(op, "format") == 0){
+ for(i=0; i<ftl->nunit-1; i++)
+ eraseinit(ftl, i*ftl->segsize, i, 1);
+ eraseinit(ftl, i*ftl->segsize, XferID, 1);
+ }
+ ftl->xfer = -1;
+ for(i=0; i<ftl->nunit; i++){
+ e = eraseload(ftl, i, i*ftl->segsize);
+ if(e == nil){
+ print("ftl: logical segment %d: bad format\n", i);
+ continue;
+ }
+ if(e->id == XferBusy){
+ e->nerase++;
+ eraseinit(ftl, e->offset, XferID, e->nerase);
+ e->id = XferID;
+ }
+ for(j=0; j<ftl->nunit; j++)
+ if(ftl->unit[j] != nil && ftl->unit[j]->id == e->id){
+ print("ftl: duplicate erase unit #%x\n", e->id);
+ erasefree(e);
+ e = nil;
+ break;
+ }
+ if(e){
+ ftl->unit[e->x] = e;
+ if(e->id == XferID)
+ ftl->xfer = e->x;
+ if (FTLDEBUG || ftl->trace || trace)
+ print("ftl: unit %d:#%x used %lud free %lud dead %lud bad %lud nerase %lud\n",
+ e->x, e->id, e->nused, e->nfree, e->ndead, e->nbad, e->nerase);
+ }
+ }
+ if(ftl->xfer < 0 && ftl->nunit <= 0 || ftl->xfer >= 0 && ftl->nunit <= 1) {
+ fprint(2, "no valid flash data units");
+ exits("1");
+ }
+ if(ftl->xfer < 0)
+ print("ftl: no transfer unit: device is WORM\n");
+ else
+ ftl->nblock -= segblocks; /* discount transfer segment */
+ if(ftl->nblock >= 1000)
+ ftl->rwlimit = ftl->nblock-100; /* TO DO: variable reserve */
+ else
+ ftl->rwlimit = ftl->nblock*USABLEPCT/100;
+ return ftl;
+}
+
+static void
+ftlfree(Ftl *ftl)
+{
+ if(ftl != nil){
+ free(ftl->unit);
+ free(ftl->vbm);
+ free(ftl);
+ }
+}
+
+/*
+ * this simple greedy algorithm weighted by nerase does seem to lead
+ * to even wear of erase units (cf. the eNVy file system)
+ */
+static Terase *
+bestcopy(Ftl *ftl)
+{
+ Terase *e, *be;
+ int i;
+
+ be = nil;
+ for(i=0; i<ftl->nunit; i++)
+ if((e = ftl->unit[i]) != nil && e->id != XferID && e->id != XferBusy && e->ndead+e->nbad &&
+ (be == nil || e->nerase <= be->nerase && e->ndead >= be->ndead))
+ be = e;
+ return be;
+}
+
+static int
+copyunit(Ftl *ftl, Terase *from, Terase *to)
+{
+ int i, nb;
+ uchar id[2];
+ ulong *bam;
+ uchar *buf;
+ ulong v, bno;
+
+ if(FTLDEBUG || ftl->trace || trace)
+ print("ftl: copying %d (#%lux) to #%lux\n", from->id, from->offset, to->offset);
+ to->nbam = 0;
+ free(to->bam);
+ to->bam = nil;
+ buf = malloc(Bsize);
+ if(buf == nil)
+ return 0;
+ PUT2(id, XferBusy);
+ putflash(ftl, to->offset+offsetof(Merase,id[0]), id, 2);
+ /* make new BAM */
+ nb = from->nbam*sizeof(*to->bam);
+ bam = malloc(nb);
+ if(bam == nil) {
+ fprint(2, "nomem\n");
+ exits("1");
+ }
+ memmove(bam, from->bam, nb);
+ to->nused = 0;
+ to->nbad = 0;
+ to->nfree = 0;
+ to->ndead = 0;
+ for(i = 0; i < from->nbam; i++)
+ switch(bam[i]){
+ case Bwriting:
+ case Bdeleted:
+ case Bfree:
+ bam[i] = Bfree;
+ to->nfree++;
+ break;
+ default:
+ switch(bam[i]&BlockType){
+ default:
+ case BadBlock: /* it isn't necessarily bad in this unit */
+ to->nfree++;
+ bam[i] = Bfree;
+ break;
+ case DataBlock:
+ case ReplacePage:
+ v = bam[i];
+ bno = BNO(v & ~BlockType);
+ if(i < ftl->fstart || bno >= ftl->nblock){
+ print("ftl: unit %d:#%x bad bam[%d]=#%lux\n", from->x, from->id, i, v);
+ to->nfree++;
+ bam[i] = Bfree;
+ break;
+ }
+ getflash(ftl, buf, from->offset+i*Bsize, Bsize);
+ putflash(ftl, to->offset+i*Bsize, buf, Bsize);
+ to->nused++;
+ break;
+ case ControlBlock:
+ to->nused++;
+ break;
+ }
+ }
+ for(i=0; i<from->nbam; i++){
+ uchar *p = (uchar*)&bam[i];
+ v = bam[i];
+ if(v != Bfree && ftl->trace > 1)
+ print("to[%d]=#%lux\n", i, v);
+ PUT4(p, v);
+ }
+ putflash(ftl, to->bamoffset, bam, nb); /* BUG: PUT4 */
+ for(i=0; i<from->nbam; i++){
+ uchar *p = (uchar*)&bam[i];
+ v = bam[i];
+ PUT4(p, v);
+ }
+ to->id = from->id;
+ PUT2(id, to->id);
+ putflash(ftl, to->offset+offsetof(Merase,id[0]), id, 2);
+ to->nbam = from->nbam;
+ to->bam = bam;
+ ftl->nfree += to->nfree - from->nfree;
+ free(buf);
+ return 1;
+}
+
+static int
+mustscavenge(void *a)
+{
+ return ((Ftl*)a)->needspace || ((Ftl*)a)->detach == Deferred;
+}
+
+static int
+donescavenge(void *a)
+{
+ return ((Ftl*)a)->needspace == 0;
+}
+
+static void
+scavengeproc(void *arg)
+{
+ Ftl *ftl;
+ int i;
+ Terase *e, *ne;
+
+ ftl = arg;
+ if(mustscavenge(ftl)){
+ if(ftl->detach == Deferred){
+ ftlfree(ftl);
+ fprint(2, "scavenge out of memory\n");
+ exits("1");
+ }
+ if(FTLDEBUG || ftl->trace || trace)
+ print("ftl: scavenge %ld\n", ftl->nfree);
+ e = bestcopy(ftl);
+ if(e == nil || ftl->xfer < 0 || (ne = ftl->unit[ftl->xfer]) == nil || ne->id != XferID || e == ne)
+ goto Fail;
+ if(copyunit(ftl, e, ne)){
+ i = ne->x; ne->x = e->x; e->x = i;
+ ftl->unit[ne->x] = ne;
+ ftl->unit[e->x] = e;
+ ftl->xfer = e->x;
+ e->id = XferID;
+ e->nbam = 0;
+ free(e->bam);
+ e->bam = nil;
+ e->bamx = 0;
+ e->nerase++;
+ eraseinit(ftl, e->offset, XferID, e->nerase);
+ }
+ Fail:
+ if(FTLDEBUG || ftl->trace || trace)
+ print("ftl: end scavenge %ld\n", ftl->nfree);
+ ftl->needspace = 0;
+ }
+}
+
+static int
+scavenge(Ftl *ftl)
+{
+ if(ftl->xfer < 0 || bestcopy(ftl) == nil)
+ return 0; /* you worm! */
+
+ if(!ftl->hasproc){
+ ftl->hasproc = 1;
+ }
+ ftl->needspace = 1;
+
+ scavengeproc(ftls);
+
+ return ftl->nfree;
+}
+
+static void
+putbam(Ftl *ftl, Terase *e, int n, ulong entry)
+{
+ uchar b[4];
+
+ e->bam[n] = entry;
+ PUT4(b, entry);
+ putflash(ftl, e->bamoffset + n*4, b, 4);
+}
+
+static ulong
+allocblk(Ftl *ftl)
+{
+ Terase *e;
+ int i, j;
+
+ i = ftl->lastx;
+ do{
+ e = ftl->unit[i];
+ if(e != nil && e->id != XferID && e->nfree){
+ ftl->lastx = i;
+ for(j=e->bamx; j<e->nbam; j++)
+ if(e->bam[j] == Bfree){
+ putbam(ftl, e, j, Bwriting);
+ ftl->nfree--;
+ e->nfree--;
+ e->bamx = j+1;
+ return (e->x<<16) | j;
+ }
+ e->nfree = 0;
+ print("ftl: unit %d:#%x nfree %ld but not free in BAM\n", e->x, e->id, e->nfree);
+ }
+ if(++i >= ftl->nunit)
+ i = 0;
+ }while(i != ftl->lastx);
+ return 0;
+}
+
+static int
+mapblk(Ftl *ftl, ulong bno, Terase **ep, ulong *bp)
+{
+ ulong v;
+ int x;
+
+ if(bno < ftl->nblock){
+ v = ftl->vbm[bno];
+ if(v == 0 || v == ~0)
+ return 0;
+ x = v>>16;
+ if(x >= ftl->nunit || x == ftl->xfer || ftl->unit[x] == nil){
+ print("ftl: corrupt format: bad block mapping %lud -> unit #%x\n", bno, x);
+ return 0;
+ }
+ *ep = ftl->unit[x];
+ *bp = v & 0xFFFF;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+eraseinit(Ftl *ftl, ulong offset, int id, int nerase)
+{
+ union {
+ Merase m;
+ uchar block[ERASEHDRLEN];
+ } *m;
+ uchar *bam, *p;
+ int i, nov;
+
+ nov = ((ftl->segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize; /* number of overhead blocks (header, and BAM itself) */
+ if(nov*Bsize >= ftl->segsize) {
+ fprint(2, "ftl -- too small for files");
+ exits("1");
+ }
+ eraseflash(ftl, offset);
+ m = malloc(sizeof(*m));
+ if(m == nil) {
+ fprint(2, "nomem\n");
+ exits("1");
+ }
+ memset(m, 0xFF, sizeof(*m));
+ m->m.linktuple[0] = 0x13;
+ m->m.linktuple[1] = 0x3;
+ memmove(m->m.linktuple+2, "CIS", 3);
+ m->m.orgtuple[0] = 0x46;
+ m->m.orgtuple[1] = 0x57;
+ m->m.orgtuple[2] = 0x00;
+ memmove(m->m.orgtuple+3, "FTL100", 7);
+ m->m.nxfer = 1;
+ PUT4(m->m.nerase, nerase);
+ PUT2(m->m.id, id);
+ m->m.bshift = ftl->bshift;
+ m->m.eshift = ftl->eshift;
+ PUT2(m->m.pstart, 0);
+ PUT2(m->m.nunits, ftl->nunit);
+ PUT4(m->m.psize, ftl->size - nov*Bsize);
+ PUT4(m->m.vbmbase, 0xffffffff); /* we always calculate the VBM */
+ PUT2(m->m.nvbm, 0);
+ m->m.flags = 0;
+ m->m.code = 0xFF;
+ memmove(m->m.serial, "Inf1", 4);
+ PUT4(m->m.altoffset, 0);
+ PUT4(m->m.bamoffset, BAMoffset);
+ putflash(ftl, offset, m, ERASEHDRLEN);
+ free(m);
+ if(id == XferID)
+ return;
+ nov *= 4; /* now bytes of BAM */
+ bam = malloc(nov);
+ if(bam == nil) {
+ fprint(2, "nomem");
+ exits("1");
+ }
+ for(i=0; i<nov; i += 4){
+ p = bam+i;
+ PUT4(p, ControlBlock); /* reserve them */
+ }
+ putflash(ftl, offset+BAMoffset, bam, nov);
+ free(bam);
+}
+
+static Terase *
+eraseload(Ftl *ftl, int x, ulong offset)
+{
+ union {
+ Merase m;
+ uchar block[ERASEHDRLEN];
+ } *m;
+ Terase *e;
+ uchar *p;
+ int i, nbam;
+ ulong bno, v;
+
+ m = malloc(sizeof(*m));
+ if(m == nil) {
+ fprint(2, "nomem");
+ exits("1");
+ }
+ getflash(ftl, m, offset, ERASEHDRLEN);
+ if(memcmp(m->m.orgtuple+3, "FTL100", 7) != 0 ||
+ memcmp(m->m.serial, "Inf1", 4) != 0){
+ free(m);
+ return nil;
+ }
+ e = malloc(sizeof(*e));
+ if(e == nil){
+ free(m);
+ fprint(2, "nomem");
+ exits("1");
+ }
+ e->x = x;
+ e->id = GET2(m->m.id);
+ e->offset = offset;
+ e->bamoffset = GET4(m->m.bamoffset);
+ e->nerase = GET4(m->m.nerase);
+ e->bamx = 0;
+ e->nfree = 0;
+ e->nused = 0;
+ e->ndead = 0;
+ e->nbad = 0;
+ free(m);
+ if(e->bamoffset != BAMoffset){
+ free(e);
+ return nil;
+ }
+ e->bamoffset += offset;
+ if(e->id == XferID || e->id == XferBusy){
+ e->bam = nil;
+ e->nbam = 0;
+ return e;
+ }
+ nbam = ftl->segsize/Bsize;
+ e->bam = malloc(nbam*sizeof(*e->bam));
+ e->nbam = nbam;
+ getflash(ftl, e->bam, e->bamoffset, nbam*4);
+ /* scan BAM to build VBM */
+ e->bamx = 0;
+ for(i=0; i<nbam; i++){
+ p = (uchar*)&e->bam[i];
+ e->bam[i] = v = GET4(p);
+ if(v == Bwriting || v == Bdeleted)
+ e->ndead++;
+ else if(v == Bfree){
+ if(e->bamx == 0)
+ e->bamx = i;
+ e->nfree++;
+ ftl->nfree++;
+ }else{
+ switch(v & BlockType){
+ case ControlBlock:
+ break;
+ case DataBlock:
+ /* add to VBM */
+ if(v & (1<<31))
+ break; /* negative => VBM page, ignored */
+ bno = BNO(v & ~BlockType);
+ if(i < ftl->fstart || bno >= ftl->nblock){
+ print("ftl: unit %d:#%x bad bam[%d]=#%lux\n", e->x, e->id, i, v);
+ e->nbad++;
+ break;
+ }
+ ftl->vbm[bno] = (e->x<<16) | i;
+ e->nused++;
+ break;
+ case ReplacePage:
+ /* replacement VBM page; ignored */
+ break;
+ default:
+ print("ftl: unit %d:#%x bad bam[%d]=%lux\n", e->x, e->id, i, v);
+ case BadBlock:
+ e->nbad++;
+ break;
+ }
+ }
+ }
+ return e;
+}
+
+static void
+erasefree(Terase *e)
+{
+ free(e->bam);
+ free(e);
+}
+
+static void
+eraseflash(Ftl *ftl, ulong offset)
+{
+ offset += ftl->base;
+ if(FTLDEBUG || ftl->trace || trace)
+ print("ftl: erase seg @#%lux\n", offset);
+ memset(flashm+offset, 0xff, secsize);
+}
+
+static void
+putflash(Ftl *ftl, ulong offset, void *buf, long n)
+{
+ offset += ftl->base;
+ if(ftl->trace || trace)
+ print("ftl: write(#%lux, %ld)\n", offset, n);
+ memcpy(flashm+offset, buf, n);
+}
+
+static void
+getflash(Ftl *ftl, void *buf, ulong offset, long n)
+{
+ offset += ftl->base;
+ if(ftl->trace || trace)
+ print("ftl: read(#%lux, %ld)\n", offset, n);
+ memcpy(buf, flashm+offset, n);
+}
+
+#define BUFSIZE 8192
+
+void
+main(int argc, char **argv)
+{
+ int k, r, sz, offset = 0;
+ char *buf, *buf1;
+ int fd1, fd2;
+
+ if (argc != 5) {
+ fprint(2, "usage: %s flashsize secsize kfsfile flashfile\n", argv[0]);
+ exits("1");
+ }
+ flashsize = strtol(argv[1], nil, 0);
+ secsize = strtol(argv[2], nil , 0);
+ fd1 = open(argv[3], OREAD);
+ fd2 = create(argv[4], OWRITE, 0644);
+ if (fd1 < 0 || fd2 < 0) {
+ fprint(2, "bad io files\n");
+ exits("1");
+ }
+ if(secsize == 0 || secsize > flashsize || secsize&(secsize-1) || 0&(secsize-1) || flashsize == 0 || flashsize != Nolimit && flashsize&(secsize-1)) {
+ fprint(2, "bad sizes\n");
+ exits("1");
+ }
+ for(k=0; k<32 && (1<<k) != secsize; k++)
+ ;
+ flashm = malloc(flashsize);
+ buf = malloc(BUFSIZE);
+ if (flashm == nil) {
+ fprint(2, "no mem for flash\n");
+ exits("1");
+ }
+ ftls = mkftl("FLASH", 0, Nolimit, k, "format");
+ for (;;) {
+ r = read(fd1, buf, BUFSIZE);
+ if (r <= 0)
+ break;
+ if (ftlwrite(buf, r, offset) != r) {
+ fprint(2, "ftlwrite failed - input file too big\n");
+ exits("1");
+ }
+ offset += r;
+ }
+ write(fd2, flashm, flashsize);
+ close(fd1);
+ close(fd2);
+ ftlstat(offset);
+ /* ftls = mkftl("FLASH", 0, Nolimit, k, "init"); */
+ sz = offset;
+ offset = 0;
+ buf1 = malloc(BUFSIZE);
+ fd1 = open(argv[3], OREAD);
+ for (;;) {
+ r = read(fd1, buf1, BUFSIZE);
+ if (r <= 0)
+ break;
+ if (ftlread(buf, r, offset) != r) {
+ fprint(2, "ftlread failed\n");
+ exits("1");
+ }
+ if (memcmp(buf, buf1, r) != 0) {
+ fprint(2, "bad read\n");
+ exits("1");
+ }
+ offset += r;
+ }
+ close(fd1);
+ if (offset != sz) {
+ fprint(2, "bad final offset\n");
+ exits("1");
+ }
+ exits("0");
+}
diff --git a/utils/ftl/mkfile b/utils/ftl/mkfile
new file mode 100644
index 00000000..cd9c4f2f
--- /dev/null
+++ b/utils/ftl/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=ftl
+
+OFILES= ftl.$O\
+
+HFILES=
+
+LIBS=9 # libbio.a uses lib9.a so order matters.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/iar/Nt.c b/utils/iar/Nt.c
new file mode 100644
index 00000000..dbb038ba
--- /dev/null
+++ b/utils/iar/Nt.c
@@ -0,0 +1,10 @@
+#include <lib9.h>
+
+char *
+myctime(long x)
+{
+ time_t t;
+
+ t = x;
+ return ctime(&t);
+}
diff --git a/utils/iar/Plan9.c b/utils/iar/Plan9.c
new file mode 100644
index 00000000..49f03f06
--- /dev/null
+++ b/utils/iar/Plan9.c
@@ -0,0 +1,7 @@
+#include <lib9.h>
+
+char *
+myctime(long x)
+{
+ return ctime(x);
+}
diff --git a/utils/iar/Posix.c b/utils/iar/Posix.c
new file mode 100644
index 00000000..dbb038ba
--- /dev/null
+++ b/utils/iar/Posix.c
@@ -0,0 +1,10 @@
+#include <lib9.h>
+
+char *
+myctime(long x)
+{
+ time_t t;
+
+ t = x;
+ return ctime(&t);
+}
diff --git a/utils/iar/ar.c b/utils/iar/ar.c
new file mode 100644
index 00000000..aff05d3a
--- /dev/null
+++ b/utils/iar/ar.c
@@ -0,0 +1,1197 @@
+/*
+ * ar - portable (ascii) format version
+ */
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+#include <ar.h>
+
+/*
+ * The algorithm uses up to 3 temp files. The "pivot member" is the
+ * archive member specified by and a, b, or i option. The temp files are
+ * astart - contains existing members up to and including the pivot member.
+ * amiddle - contains new files moved or inserted behind the pivot.
+ * aend - contains the existing members that follow the pivot member.
+ * When all members have been processed, function 'install' streams the
+ * temp files, in order, back into the archive.
+ */
+
+typedef struct Arsymref
+{
+ char *name;
+ int type;
+ int len;
+ long offset;
+ struct Arsymref *next;
+} Arsymref;
+
+typedef struct Armember /* Temp file entry - one per archive member */
+{
+ struct Armember *next;
+ struct ar_hdr hdr;
+ long size;
+ long date;
+ void *member;
+} Armember;
+
+typedef struct Arfile /* Temp file control block - one per tempfile */
+{
+ int paged; /* set when some data paged to disk */
+ char *fname; /* paging file name */
+ int fd; /* paging file descriptor */
+ long size;
+ Armember *head; /* head of member chain */
+ Armember *tail; /* tail of member chain */
+ Arsymref *sym; /* head of defined symbol chain */
+} Arfile;
+
+typedef struct Hashchain
+{
+ char *name;
+ struct Hashchain *next;
+} Hashchain;
+
+#define NHASH 1024
+
+/*
+ * macro to portably read/write archive header.
+ * 'cmd' is read/write/Bread/Bwrite, etc.
+ */
+#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
+ || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
+ || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
+ || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
+ || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
+ || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
+ || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
+
+ /* constants and flags */
+char *man = "mrxtdpq";
+char *opt = "uvnbailo";
+char artemp[] = "/tmp/vXXXXX";
+char movtemp[] = "/tmp/v1XXXXX";
+char tailtemp[] = "/tmp/v2XXXXX";
+char symdef[] = "__.SYMDEF";
+
+int aflag; /* command line flags */
+int bflag;
+int cflag;
+int oflag;
+int uflag;
+int vflag;
+
+Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */
+int allobj = 1; /* set when all members are object files of the same type */
+int symdefsize; /* size of symdef file */
+int dupfound; /* flag for duplicate symbol */
+Hashchain *hash[NHASH]; /* hash table of text symbols */
+
+#define ARNAMESIZE sizeof(astart->tail->hdr.name)
+
+char poname[ARNAMESIZE+1]; /* name of pivot member */
+char *file; /* current file or member being worked on */
+Biobuf bout;
+Biobuf bar;
+
+void arcopy(Biobuf*, Arfile*, Armember*);
+int arcreate(char*);
+void arfree(Arfile*);
+void arinsert(Arfile*, Armember*);
+char *armalloc(int);
+void armove(Biobuf*, Arfile*, Armember*);
+void arread(Biobuf*, Armember*, int);
+void arstream(int, Arfile*);
+int arwrite(int, Armember*);
+int bamatch(char*, char*);
+int duplicate(char*);
+Armember *getdir(Biobuf*);
+int getspace(void);
+void install(char*, Arfile*, Arfile*, Arfile*, int);
+void longt(Armember*);
+int match(int, char**);
+void mesg(int, char*);
+char *myctime(long); /* $TARGMODEL.c */
+Arfile *newtempfile(char*);
+Armember *newmember(void);
+void objsym(Sym*, void*);
+int openar(char*, int, int);
+int page(Arfile*);
+void pmode(long);
+void rl(int);
+void scanobj(Biobuf*, Arfile*, int);
+void ar_select(int*, long);
+void setcom(void(*)(char*, int, char**));
+void skip(Biobuf*, long);
+int symcomp(void*, void*);
+void trim(char*, char*, int);
+void usage(void);
+void wrerr(void);
+void wrsym(Biobuf*, int, Arsymref*);
+
+void arcmd(char*, int, char**); /* command processing */
+void dcmd(char*, int, char**);
+void xcmd(char*, int, char**);
+void tcmd(char*, int, char**);
+void pcmd(char*, int, char**);
+void mcmd(char*, int, char**);
+void qcmd(char*, int, char**);
+void (*comfun)(char*, int, char**);
+
+void
+main(int argc, char *argv[])
+{
+ char *cp;
+
+ Binit(&bout, 1, OWRITE);
+ if(argc < 3)
+ usage();
+ for (cp = argv[1]; *cp; cp++) {
+ switch(*cp) {
+ case 'a': aflag = 1; break;
+ case 'b': bflag = 1; break;
+ case 'c': cflag = 1; break;
+ case 'd': setcom(dcmd); break;
+ case 'i': bflag = 1; break;
+ case 'l':
+ strcpy(artemp, "vXXXXX");
+ strcpy(movtemp, "v1XXXXX");
+ strcpy(tailtemp, "v2XXXXX");
+ break;
+ case 'm': setcom(mcmd); break;
+ case 'o': oflag = 1; break;
+ case 'p': setcom(pcmd); break;
+ case 'q': setcom(qcmd); break;
+ case 'r': setcom(arcmd); break;
+ case 't': setcom(tcmd); break;
+ case 'u': uflag = 1; break;
+ case 'v': vflag = 1; break;
+ case 'x': setcom(xcmd); break;
+ default:
+ fprint(2, "ar: bad option `%c'\n", *cp);
+ exits("error");
+ }
+ }
+ if (aflag && bflag) {
+ fprint(2, "ar: only one of 'a' and 'b' can be specified\n");
+ usage();
+ }
+ if(aflag || bflag) {
+ trim(argv[2], poname, sizeof(poname));
+ argv++;
+ argc--;
+ if(argc < 3)
+ usage();
+ }
+ if(comfun == 0) {
+ if(uflag == 0) {
+ fprint(2, "ar: one of [%s] must be specified\n", man);
+ usage();
+ }
+ setcom(arcmd);
+ }
+ cp = argv[2];
+ argc -= 3;
+ argv += 3;
+ (*comfun)(cp, argc, argv); /* do the command */
+ cp = 0;
+ while (argc--) {
+ if (*argv) {
+ fprint(2, "ar: %s not found\n", *argv);
+ cp = "error";
+ }
+ argv++;
+ }
+ if(allobj && dupfound)
+ exits("dup found");
+ exits(cp);
+}
+/*
+ * select a command
+ */
+void
+setcom(void (*fun)(char *, int, char**))
+{
+
+ if(comfun != 0) {
+ fprint(2, "ar: only one of [%s] allowed\n", man);
+ usage();
+ }
+ comfun = fun;
+}
+/*
+ * perform the 'r' and 'u' commands
+ */
+void
+arcmd(char *arname, int count, char **files)
+{
+ int fd;
+ int i;
+ Arfile *ap;
+ Armember *bp;
+ Dir *d;
+ Biobuf *bfile;
+
+ fd = openar(arname, ORDWR, 1);
+ if (fd >= 0) {
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ }
+ astart = newtempfile(artemp);
+ ap = astart;
+ aend = 0;
+ for(i = 0; fd >= 0; i++) {
+ bp = getdir(&bar);
+ if (!bp)
+ break;
+ if (bamatch(file, poname)) { /* check for pivot */
+ aend = newtempfile(tailtemp);
+ ap = aend;
+ }
+ /* pitch symdef file */
+ if (i == 0 && strcmp(file, symdef) == 0) {
+ skip(&bar, bp->size);
+ continue;
+ }
+ if (count && !match(count, files)) {
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ continue;
+ }
+ bfile = Bopen(file, OREAD);
+ if (!bfile) {
+ if (count != 0)
+ fprint(2, "ar: cannot open %s\n", file);
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ continue;
+ }
+ d = dirfstat(Bfildes(bfile));
+ if (d == nil)
+ fprint(2, "ar: cannot stat %s: %r\n", file);
+ if (uflag && (d == nil || d->mtime <= bp->date)) {
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ Bterm(bfile);
+ free(d);
+ continue;
+ }
+ mesg('r', file);
+ skip(&bar, bp->size);
+ scanobj(bfile, ap, d->length);
+ free(d);
+ armove(bfile, ap, bp);
+ Bterm(bfile);
+ }
+ if(fd >= 0)
+ close(fd);
+ /* copy in remaining files named on command line */
+ for (i = 0; i < count; i++) {
+ file = files[i];
+ if(file == 0)
+ continue;
+ files[i] = 0;
+ bfile = Bopen(file, OREAD);
+ if (!bfile)
+ fprint(2, "ar: %s cannot open\n", file);
+ else {
+ mesg('a', file);
+ d = dirfstat(Bfildes(bfile));
+ if (d == nil)
+ fprint(2, "ar: can't stat %s: %r\n", file);
+ else {
+ scanobj(bfile, astart, d->length);
+ armove(bfile, astart, newmember());
+ free(d);
+ }
+ Bterm(bfile);
+ }
+ }
+ if(fd < 0 && !cflag)
+ install(arname, astart, 0, aend, 1); /* issue 'creating' msg */
+ else
+ install(arname, astart, 0, aend, 0);
+}
+
+void
+dcmd(char *arname, int count, char **files)
+{
+ Armember *bp;
+ int fd, i;
+
+
+ if (!count)
+ return;
+ fd = openar(arname, ORDWR, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ astart = newtempfile(artemp);
+ for (i = 0; bp = getdir(&bar); i++) {
+ if(match(count, files)) {
+ mesg('d', file);
+ skip(&bar, bp->size);
+ if (strcmp(file, symdef) == 0)
+ allobj = 0;
+ } else if (i == 0 && strcmp(file, symdef) == 0)
+ skip(&bar, bp->size);
+ else {
+ scanobj(&bar, astart, bp->size);
+ arcopy(&bar, astart, bp);
+ }
+ }
+ close(fd);
+ install(arname, astart, 0, 0, 0);
+}
+
+void
+xcmd(char *arname, int count, char **files)
+{
+ int fd, f, mode, i;
+ Armember *bp;
+ Dir dx;
+
+ fd = openar(arname, OREAD, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ i = 0;
+ while (bp = getdir(&bar)) {
+ if(count == 0 || match(count, files)) {
+ mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
+ f = create(file, OWRITE, mode);
+ if(f < 0) {
+ fprint(2, "ar: %s cannot create\n", file);
+ skip(&bar, bp->size);
+ } else {
+ mesg('x', file);
+ arcopy(&bar, 0, bp);
+ if (write(f, bp->member, bp->size) < 0)
+ wrerr();
+ if(oflag) {
+ nulldir(&dx);
+ dx.atime = bp->date;
+ dx.mtime = bp->date;
+ if(dirwstat(file, &dx) < 0)
+ perror(file);
+ }
+ free(bp->member);
+ close(f);
+ }
+ free(bp);
+ if (count && ++i >= count)
+ break;
+ } else {
+ skip(&bar, bp->size);
+ free(bp);
+ }
+ }
+ close(fd);
+}
+void
+pcmd(char *arname, int count, char **files)
+{
+ int fd;
+ Armember *bp;
+
+ fd = openar(arname, OREAD, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ while(bp = getdir(&bar)) {
+ if(count == 0 || match(count, files)) {
+ if(vflag)
+ print("\n<%s>\n\n", file);
+ arcopy(&bar, 0, bp);
+ if (write(1, bp->member, bp->size) < 0)
+ wrerr();
+ } else
+ skip(&bar, bp->size);
+ free(bp);
+ }
+ close(fd);
+}
+void
+mcmd(char *arname, int count, char **files)
+{
+ int fd, i;
+ Arfile *ap;
+ Armember *bp;
+
+ if (count == 0)
+ return;
+ fd = openar(arname, ORDWR, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ astart = newtempfile(artemp);
+ amiddle = newtempfile(movtemp);
+ aend = 0;
+ ap = astart;
+ for (i = 0; bp = getdir(&bar); i++) {
+ if (bamatch(file, poname)) {
+ aend = newtempfile(tailtemp);
+ ap = aend;
+ }
+ if(match(count, files)) {
+ mesg('m', file);
+ scanobj(&bar, amiddle, bp->size);
+ arcopy(&bar, amiddle, bp);
+ } else
+ /*
+ * pitch the symdef file if it is at the beginning
+ * of the archive and we aren't inserting in front
+ * of it (ap == astart).
+ */
+ if (ap == astart && i == 0 && strcmp(file, symdef) == 0)
+ skip(&bar, bp->size);
+ else {
+ scanobj(&bar, ap, bp->size);
+ arcopy(&bar, ap, bp);
+ }
+ }
+ close(fd);
+ if (poname[0] && aend == 0)
+ fprint(2, "ar: %s not found - files moved to end.\n", poname);
+ install(arname, astart, amiddle, aend, 0);
+}
+void
+tcmd(char *arname, int count, char **files)
+{
+ int fd;
+ Armember *bp;
+ char name[ARNAMESIZE+1];
+
+ fd = openar(arname, OREAD, 0);
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ while(bp = getdir(&bar)) {
+ if(count == 0 || match(count, files)) {
+ if(vflag)
+ longt(bp);
+ trim(file, name, ARNAMESIZE);
+ Bprint(&bout, "%s\n", name);
+ }
+ skip(&bar, bp->size);
+ free(bp);
+ }
+ close(fd);
+}
+void
+qcmd(char *arname, int count, char **files)
+{
+ int fd, i;
+ Armember *bp;
+ Biobuf *bfile;
+
+ if(aflag || bflag) {
+ fprint(2, "ar: abi not allowed with q\n");
+ exits("error");
+ }
+ fd = openar(arname, ORDWR, 1);
+ if (fd < 0) {
+ if(!cflag)
+ fprint(2, "ar: creating %s\n", arname);
+ fd = arcreate(arname);
+ }
+ Binit(&bar, fd, OREAD);
+ Bseek(&bar,seek(fd,0,1), 1);
+ Bseek(&bar, 0, 2);
+ bp = newmember();
+ for(i=0; i<count && files[i]; i++) {
+ file = files[i];
+ files[i] = 0;
+ bfile = Bopen(file, OREAD);
+ if(!bfile)
+ fprint(2, "ar: %s cannot open\n", file);
+ else {
+ mesg('q', file);
+ armove(bfile, 0, bp);
+ if (!arwrite(fd, bp))
+ wrerr();
+ free(bp->member);
+ bp->member = 0;
+ Bterm(bfile);
+ }
+ }
+ free(bp);
+ close(fd);
+}
+
+/*
+ * extract the symbol references from an object file
+ */
+void
+scanobj(Biobuf *b, Arfile *ap, int size)
+{
+ int obj;
+ long offset;
+ Dir *d;
+ static int lastobj = -1;
+
+ if (!allobj) /* non-object file encountered */
+ return;
+ offset = Boffset(b);
+ obj = objtype(b, 0);
+ if (obj < 0) { /* not an object file */
+ allobj = 0;
+ d = dirfstat(Bfildes(b));
+ if (d != nil && d->length == 0)
+ fprint(2, "ar: zero length file %s\n", file);
+ free(d);
+ Bseek(b, offset, 0);
+ return;
+ }
+ if (lastobj >= 0 && obj != lastobj) {
+ fprint(2, "ar: inconsistent object file %s\n", file);
+ allobj = 0;
+ Bseek(b, offset, 0);
+ return;
+ }
+ lastobj = obj;
+ if (!readar(b, obj, offset+size, 0)) {
+ fprint(2, "ar: invalid symbol reference in file %s\n", file);
+ allobj = 0;
+ Bseek(b, offset, 0);
+ return;
+ }
+ Bseek(b, offset, 0);
+ objtraverse(objsym, ap);
+}
+
+/*
+ * add text and data symbols to the symbol list
+ */
+void
+objsym(Sym *s, void *p)
+{
+ int n;
+ Arsymref *as;
+ Arfile *ap;
+
+ if (s->type != 'T' && s->type != 'D')
+ return;
+ ap = (Arfile*)p;
+ as = (Arsymref*)armalloc(sizeof(Arsymref));
+ as->offset = ap->size;
+ n = strlen(s->name);
+ as->name = armalloc(n+1);
+ strcpy(as->name, s->name);
+ if(s->type == 'T' && duplicate(as->name)) {
+ dupfound = 1;
+ fprint(2, "duplicate text symbol: %s\n", as->name);
+ free(as->name);
+ free(as);
+ return;
+ }
+ as->type = s->type;
+ symdefsize += 4+(n+1)+1;
+ as->len = n;
+ as->next = ap->sym;
+ ap->sym = as;
+}
+
+/*
+ * Check the symbol table for duplicate text symbols
+ */
+int
+duplicate(char *name)
+{
+ Hashchain *p;
+ char *cp;
+ int h;
+
+ h = 0;
+ for(cp = name; *cp; h += *cp++)
+ h *= 1119;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+
+ for(p = hash[h]; p; p = p->next)
+ if(strcmp(p->name, name) == 0)
+ return 1;
+ p = (Hashchain*) armalloc(sizeof(Hashchain));
+ p->next = hash[h];
+ p->name = name;
+ hash[h] = p;
+ return 0;
+}
+
+/*
+ * open an archive and validate its header
+ */
+int
+openar(char *arname, int mode, int errok)
+{
+ int fd;
+ char mbuf[SARMAG];
+
+ fd = open(arname, mode);
+ if(fd >= 0){
+ if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
+ fprint(2, "ar: %s not in archive format\n", arname);
+ exits("error");
+ }
+ }else if(!errok){
+ fprint(2, "ar: cannot open %s: %r\n", arname);
+ exits("error");
+ }
+ return fd;
+}
+/*
+ * create an archive and set its header
+ */
+int
+arcreate(char *arname)
+{
+ int fd;
+
+ fd = create(arname, OWRITE, 0664);
+ if(fd < 0){
+ fprint(2, "ar: cannot create %s: %r\n", arname);
+ exits("error");
+ }
+ if(write(fd, ARMAG, SARMAG) != SARMAG)
+ wrerr();
+ return fd;
+}
+/*
+ * error handling
+ */
+void
+wrerr(void)
+{
+ perror("ar: write error");
+ exits("error");
+}
+
+void
+rderr(void)
+{
+ perror("ar: read error");
+ exits("error");
+}
+
+void
+phaseerr(int offset)
+{
+ fprint(2, "ar: phase error at offset %d\n", offset);
+ exits("error");
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man);
+ exits("error");
+}
+/*
+ * read the header for the next archive member
+ */
+Armember *
+getdir(Biobuf *b)
+{
+ Armember *bp;
+ char *cp;
+ static char name[ARNAMESIZE+1];
+
+ bp = newmember();
+ if(HEADER_IO(Bread, b, bp->hdr)) {
+ free(bp);
+ return 0;
+ }
+ if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
+ phaseerr(Boffset(b));
+ strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
+ cp = name+sizeof(name)-1;
+ while(*--cp==' ')
+ ;
+ cp[1] = '\0';
+ file = name;
+ bp->date = atol(bp->hdr.date);
+ bp->size = atol(bp->hdr.size);
+ return bp;
+}
+/*
+ * Copy the file referenced by fd to the temp file
+ */
+void
+armove(Biobuf *b, Arfile *ap, Armember *bp)
+{
+ char *cp;
+ Dir *d;
+
+ if ((d = dirfstat(Bfildes(b))) == nil) {
+ fprint(2, "ar: cannot stat %s: %r\n", file);
+ return;
+ }
+ trim(file, bp->hdr.name, sizeof(bp->hdr.name));
+ for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
+ cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
+ *cp = ' ';
+ sprint(bp->hdr.date, "%-12ld", d->mtime);
+ sprint(bp->hdr.uid, "%-6d", 0);
+ sprint(bp->hdr.gid, "%-6d", 0);
+ sprint(bp->hdr.mode, "%-8lo", d->mode);
+ sprint(bp->hdr.size, "%-10lld", (vlong)d->length);
+ strncpy(bp->hdr.fmag, ARFMAG, 2);
+ bp->size = d->length;
+ bp->date = d->mtime;
+ arread(b, bp, bp->size);
+ if (d->length&0x01)
+ d->length++;
+ if (ap) {
+ arinsert(ap, bp);
+ ap->size += d->length+SAR_HDR;
+ }
+ free(d);
+}
+/*
+ * Copy the archive member at the current offset into the temp file.
+ */
+void
+arcopy(Biobuf *b, Arfile *ap, Armember *bp)
+{
+ int n;
+
+ n = bp->size;
+ if (n & 01)
+ n++;
+ arread(b, bp, n);
+ if (ap) {
+ arinsert(ap, bp);
+ ap->size += n+SAR_HDR;
+ }
+}
+/*
+ * Skip an archive member
+ */
+void
+skip(Biobuf *bp, long len)
+{
+ if (len & 01)
+ len++;
+ Bseek(bp, len, 1);
+}
+/*
+ * Stream the three temp files to an archive
+ */
+void
+install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
+{
+ int fd;
+
+ if(allobj && dupfound) {
+ fprint(2, "%s not changed\n", arname);
+ return;
+ }
+
+ if(createflag)
+ fprint(2, "ar: creating %s\n", arname);
+ fd = arcreate(arname);
+
+ if(allobj)
+ rl(fd);
+
+ if (astart) {
+ arstream(fd, astart);
+ arfree(astart);
+ }
+ if (amiddle) {
+ arstream(fd, amiddle);
+ arfree(amiddle);
+ }
+ if (aend) {
+ arstream(fd, aend);
+ arfree(aend);
+ }
+ close(fd);
+}
+
+void
+rl(int fd)
+{
+
+ Biobuf b;
+ char *cp;
+ struct ar_hdr a;
+ long len;
+
+ Binit(&b, fd, OWRITE);
+ Bseek(&b,seek(fd,0,1), 0);
+
+ len = symdefsize;
+ if(len&01)
+ len++;
+ sprint(a.date, "%-12ld", time(0));
+ sprint(a.uid, "%-6d", 0);
+ sprint(a.gid, "%-6d", 0);
+ sprint(a.mode, "%-8o", 0644);
+ sprint(a.size, "%-10ld", len);
+ strncpy(a.fmag, ARFMAG, 2);
+ strcpy(a.name, symdef);
+ for (cp = strchr(a.name, 0); /* blank pad on right */
+ cp < a.name+sizeof(a.name); cp++)
+ *cp = ' ';
+ if(HEADER_IO(Bwrite, &b, a))
+ wrerr();
+
+ len += Boffset(&b);
+ if (astart) {
+ wrsym(&b, len, astart->sym);
+ len += astart->size;
+ }
+ if(amiddle) {
+ wrsym(&b, len, amiddle->sym);
+ len += amiddle->size;
+ }
+ if(aend)
+ wrsym(&b, len, aend->sym);
+
+ if(symdefsize&0x01)
+ Bputc(&b, 0);
+ Bterm(&b);
+}
+/*
+ * Write the defined symbols to the symdef file
+ */
+void
+wrsym(Biobuf *bp, int offset, Arsymref *as)
+{
+ int off;
+
+ while(as) {
+ Bputc(bp, as->type);
+ off = as->offset+offset;
+ Bputc(bp, off);
+ Bputc(bp, off>>8);
+ Bputc(bp, off>>16);
+ Bputc(bp, off>>24);
+ if (Bwrite(bp, as->name, as->len+1) != as->len+1)
+ wrerr();
+ as = as->next;
+ }
+}
+/*
+ * Check if the archive member matches an entry on the command line.
+ */
+int
+match(int count, char **files)
+{
+ int i;
+ char name[ARNAMESIZE+1];
+
+ for(i=0; i<count; i++) {
+ if(files[i] == 0)
+ continue;
+ trim(files[i], name, ARNAMESIZE);
+ if(strncmp(name, file, ARNAMESIZE) == 0) {
+ file = files[i];
+ files[i] = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+/*
+ * compare the current member to the name of the pivot member
+ */
+int
+bamatch(char *file, char *pivot)
+{
+ static int state = 0;
+
+ switch(state)
+ {
+ case 0: /* looking for position file */
+ if (aflag) {
+ if (strncmp(file, pivot, ARNAMESIZE) == 0)
+ state = 1;
+ } else if (bflag) {
+ if (strncmp(file, pivot, ARNAMESIZE) == 0) {
+ state = 2; /* found */
+ return 1;
+ }
+ }
+ break;
+ case 1: /* found - after previous file */
+ state = 2;
+ return 1;
+ case 2: /* already found position file */
+ break;
+ }
+ return 0;
+}
+/*
+ * output a message, if 'v' option was specified
+ */
+void
+mesg(int c, char *file)
+{
+
+ if(vflag)
+ Bprint(&bout, "%c - %s\n", c, file);
+}
+/*
+ * isolate file name by stripping leading directories and trailing slashes
+ */
+void
+trim(char *s, char *buf, int n)
+{
+ char *p;
+
+ for(;;) {
+ p = strrchr(s, '/');
+ if (!p) { /* no slash in name */
+ strncpy(buf, s, n);
+ return;
+ }
+ if (p[1] != 0) { /* p+1 is first char of file name */
+ strncpy(buf, p+1, n);
+ return;
+ }
+ *p = 0; /* strip trailing slash */
+ }
+}
+/*
+ * utilities for printing long form of 't' command
+ */
+#define SUID 04000
+#define SGID 02000
+#define ROWN 0400
+#define WOWN 0200
+#define XOWN 0100
+#define RGRP 040
+#define WGRP 020
+#define XGRP 010
+#define ROTH 04
+#define WOTH 02
+#define XOTH 01
+#define STXT 01000
+
+void
+longt(Armember *bp)
+{
+ char *cp;
+
+ pmode(strtoul(bp->hdr.mode, 0, 8));
+ Bprint(&bout, "%3ld/%1ld", atol(bp->hdr.uid), atol(bp->hdr.gid));
+ Bprint(&bout, "%7ld", bp->size);
+ cp = myctime(bp->date);
+ Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
+}
+
+int m1[] = { 1, ROWN, 'r', '-' };
+int m2[] = { 1, WOWN, 'w', '-' };
+int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
+int m4[] = { 1, RGRP, 'r', '-' };
+int m5[] = { 1, WGRP, 'w', '-' };
+int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
+int m7[] = { 1, ROTH, 'r', '-' };
+int m8[] = { 1, WOTH, 'w', '-' };
+int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
+
+int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
+
+void
+pmode(long mode)
+{
+ int **mp;
+
+ for(mp = &m[0]; mp < &m[9];)
+ ar_select(*mp++, mode);
+}
+
+void
+ar_select(int *ap, long mode)
+{
+ int n;
+
+ n = *ap++;
+ while(--n>=0 && (mode&*ap++)==0)
+ ap++;
+ Bputc(&bout, *ap);
+}
+/*
+ * Temp file I/O subsystem. We attempt to cache all three temp files in
+ * core. When we run out of memory we spill to disk.
+ * The I/O model assumes that temp files:
+ * 1) are only written on the end
+ * 2) are only read from the beginning
+ * 3) are only read after all writing is complete.
+ * The architecture uses one control block per temp file. Each control
+ * block anchors a chain of buffers, each containing an archive member.
+ */
+Arfile *
+newtempfile(char *name) /* allocate a file control block */
+{
+ Arfile *ap;
+
+ ap = (Arfile *) armalloc(sizeof(Arfile));
+ ap->fname = name;
+ return ap;
+}
+
+Armember *
+newmember(void) /* allocate a member buffer */
+{
+ return (Armember *)armalloc(sizeof(Armember));
+}
+
+void
+arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */
+{
+ int i;
+
+ bp->member = armalloc(n);
+ i = Bread(b, bp->member, n);
+ if (i < 0) {
+ free(bp->member);
+ bp->member = 0;
+ rderr();
+ }
+}
+/*
+ * insert a member buffer into the member chain
+ */
+void
+arinsert(Arfile *ap, Armember *bp)
+{
+ bp->next = 0;
+ if (!ap->tail)
+ ap->head = bp;
+ else
+ ap->tail->next = bp;
+ ap->tail = bp;
+}
+/*
+ * stream the members in a temp file to the file referenced by 'fd'.
+ */
+void
+arstream(int fd, Arfile *ap)
+{
+ Armember *bp;
+ int i;
+ char buf[8192];
+
+ if (ap->paged) { /* copy from disk */
+ seek(ap->fd, 0, 0);
+ for (;;) {
+ i = read(ap->fd, buf, sizeof(buf));
+ if (i < 0)
+ rderr();
+ if (i == 0)
+ break;
+ if (write(fd, buf, i) != i)
+ wrerr();
+ }
+ close(ap->fd);
+ ap->paged = 0;
+ }
+ /* dump the in-core buffers */
+ for (bp = ap->head; bp; bp = bp->next) {
+ if (!arwrite(fd, bp))
+ wrerr();
+ }
+}
+/*
+ * write a member to 'fd'.
+ */
+int
+arwrite(int fd, Armember *bp)
+{
+ int len;
+
+ if(HEADER_IO(write, fd, bp->hdr))
+ return 0;
+ len = bp->size;
+ if (len & 01)
+ len++;
+ if (write(fd, bp->member, len) != len)
+ return 0;
+ return 1;
+}
+/*
+ * Spill a member to a disk copy of a temp file
+ */
+int
+page(Arfile *ap)
+{
+ Armember *bp;
+
+ bp = ap->head;
+ if (!ap->paged) { /* not yet paged - create file */
+ ap->fname = mktemp(ap->fname);
+ ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
+ if (ap->fd < 0) {
+ fprint(2,"ar: can't create temp file\n");
+ return 0;
+ }
+ ap->paged = 1;
+ }
+ if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
+ return 0;
+ ap->head = bp->next;
+ if (ap->tail == bp)
+ ap->tail = bp->next;
+ free(bp->member);
+ free(bp);
+ return 1;
+}
+/*
+ * try to reclaim space by paging. we try to spill the start, middle,
+ * and end files, in that order. there is no particular reason for the
+ * ordering.
+ */
+int
+getspace(void)
+{
+ if (astart && astart->head && page(astart))
+ return 1;
+ if (amiddle && amiddle->head && page(amiddle))
+ return 1;
+ if (aend && aend->head && page(aend))
+ return 1;
+ return 0;
+}
+
+void
+arfree(Arfile *ap) /* free a member buffer */
+{
+ Armember *bp, *next;
+
+ for (bp = ap->head; bp; bp = next) {
+ next = bp->next;
+ if (bp->member)
+ free(bp->member);
+ free(bp);
+ }
+ free(ap);
+}
+/*
+ * allocate space for a control block or member buffer. if the malloc
+ * fails we try to reclaim space by spilling previously allocated
+ * member buffers.
+ */
+char *
+armalloc(int n)
+{
+ char *cp;
+
+ do {
+ cp = malloc(n);
+ if (cp) {
+ memset(cp, 0, n);
+ return cp;
+ }
+ } while (getspace());
+ fprint(2, "ar: out of memory\n");
+ exits("malloc");
+ return 0;
+}
+/*
+ * Nt stub for GetNameFromID() in lib9\dirstat-Nt.c.
+ * Other architectures never call it.
+ */
+char *
+GetNameFromID(int id)
+{
+ USED(id);
+ return "unknown";
+}
diff --git a/utils/iar/mkfile b/utils/iar/mkfile
new file mode 100644
index 00000000..35f60249
--- /dev/null
+++ b/utils/iar/mkfile
@@ -0,0 +1,18 @@
+<../../mkconfig
+
+TARG=iar # inferno archiver
+
+OFILES= ar.$O\
+ $TARGMODEL.$O\
+
+HFILES= ../include/a.out.h\
+ ../../include/bio.h\
+ ../include/mach.h\
+
+LIBS=mach bio 9 # libbio.a uses lib9.a so order matters.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/idea/NOTICE b/utils/idea/NOTICE
new file mode 100644
index 00000000..48e4162a
--- /dev/null
+++ b/utils/idea/NOTICE
@@ -0,0 +1,27 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 2002 Vita Nuova Holdings Limited (www.vitanuova.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/utils/idea/idea.c b/utils/idea/idea.c
new file mode 100644
index 00000000..0db0591c
--- /dev/null
+++ b/utils/idea/idea.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright © 2002 Vita Nuova Holdings Limited. All rights reserved.
+ */
+#include <lib9.h>
+#include <bio.h>
+
+/* CBC, ECB, integrate, SSL */
+
+#define KEYLEN 52
+
+#define MODA 0x10000
+#define MODM 0x10001
+#define MASKA (MODA-1)
+
+#define OP1(x, y) ((x) ^ (y))
+#define OP2(x, y) (((x) + (y)) & MASKA)
+#define OP3(x, y) mod(x, y)
+
+#define OP2INV(x) (-(x))
+#define OP3INV(x) inv(x)
+
+#define BIGEND(k, i) ((k[i]<<8)|k[i+1])
+#define MSB(x) ((x)>>8)
+#define LSB(x) ((x)&0xff)
+
+static ushort
+mod(ushort x, ushort y)
+{
+ ushort q, r;
+ uint z;
+
+ if (x == 0)
+ return 1-y;
+ if (y == 0)
+ return 1-x;
+ z = (uint)x*(uint)y;
+ q = z >> 16;
+ r = z & MASKA;
+ return r-q+(r<q);
+}
+
+static ushort
+inv(ushort x)
+{
+ int q, r0, r1, r2, v0, v1, v2;
+
+ if (x <= 1)
+ return x;
+ r0 = MODM;
+ r1 = x;
+ v0 = 0;
+ v1 = 1;
+ while (r1 != 0) {
+ q = r0/r1;
+ r2 = r0-q*r1;
+ v2 = v0-q*v1;
+ r0 = r1;
+ r1 = r2;
+ v0 = v1;
+ v1 = v2;
+ }
+ if (v0 < 0)
+ v0 += MODM;
+ return v0 & MASKA;
+}
+
+static void
+idea_key_setup_decrypt(ushort ek[KEYLEN], ushort dk[KEYLEN])
+{
+ int i;
+
+ for (i = 0; i < 54; i += 6) {
+ dk[i] = OP3INV(ek[48-i]);
+ dk[i+1] = OP2INV(ek[50-i]);
+ dk[i+2] = OP2INV(ek[49-i]);
+ dk[i+3] = OP3INV(ek[51-i]);
+ if (i < 48) {
+ dk[i+4] = ek[46-i];
+ dk[i+5] = ek[47-i];
+ }
+ }
+}
+
+void
+idea_key_setup(uchar key[16], ushort ek[2*KEYLEN])
+{
+ int i, j;
+ ushort tmp, *e = ek;
+
+ for (i = 0; i < 8; i++)
+ ek[i] = BIGEND(key, 2*i);
+ for (i = 8, j = 1; i < KEYLEN; i++, j++) {
+ ek[i] = (e[j&7]<<9)|(e[(j+1)&7]>>7);
+ if (((i+1) & 7) == 0)
+ e += 8;
+ }
+ tmp = ek[49];
+ ek[49] = ek[50];
+ ek[50] = tmp;
+ idea_key_setup_decrypt(ek, &ek[KEYLEN]);
+}
+
+void
+idea_cipher(ushort key[2*KEYLEN], uchar text[8], int decrypting)
+{
+ int i;
+ ushort *k;
+ ushort x[4];
+ ushort tmp, yout, zout;
+
+ k = decrypting ? &key[KEYLEN] : key;
+ for (i = 0; i < 4; i++)
+ x[i] = BIGEND(text, 2*i);
+ for (i = 0; i < 17; i++) {
+ if (!(i&1)) { /* odd round */
+ x[0] = OP3(x[0], k[3*i]);
+ tmp = OP2(x[2], k[3*i+2]);
+ x[2] = OP2(x[1], k[3*i+1]);
+ x[3] = OP3(x[3], k[3*i+3]);
+ x[1] = tmp;
+ }
+ else {
+ tmp = OP3(k[3*i+1], OP1(x[0], x[1]));
+ yout = OP3(OP2(tmp, OP1(x[2], x[3])), k[3*i+2]);
+ zout = OP2(tmp, yout);
+ x[0] = OP1(x[0], yout);
+ x[1] = OP1(x[1], yout);
+ x[2] = OP1(x[2], zout);
+ x[3] = OP1(x[3], zout);
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ text[2*i] = MSB(x[i]);
+ text[2*i+1] = LSB(x[i]);
+ }
+}
+
+static void
+decerr(char *s)
+{
+ fprint(2, "decrypt error: %s (wrong password ?)\n", s);
+ exits("decrypt");
+}
+
+void
+main(int argc, char **argv)
+{
+/*
+ uchar key[] = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
+ 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 };
+ uchar plain[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 };
+ uchar cipher[] = { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 };
+ uchar tmp[8];
+*/
+ ushort edkey[2*KEYLEN];
+ uchar obuf[8], buf[8], key[16];
+ long i, m, n, om;
+ int dec, stdin = 0, stdout = 1;
+ Biobuf *bin, *bout;
+
+/*
+ memcpy(tmp, plain, 8);
+ idea_key_setup(key, edkey);
+ idea_cipher(edkey, tmp, 0);
+ if (memcmp(tmp, cipher, 8)) {
+ print("encrypt wrong\n");
+ exits("");
+ }
+ idea_cipher(edkey, tmp, 1);
+ if (memcmp(tmp, plain, 8)) {
+ print("decrypt wrong\n");
+ exits("");
+ }
+*/
+
+ if((argc != 3 && argc != 4) || (strcmp(argv[1], "-e") != 0 && strcmp(argv[1], "-d") != 0) || strlen(argv[2]) != 16){
+ fprint(2, "usage: idea -[e | d] <16 char key> [inputfile]\n");
+ exits("usage");
+ }
+ dec = strcmp(argv[1], "-d") == 0;
+ if(argc == 4){
+ char s[128];
+
+ stdin = open(argv[3], OREAD);
+ if(stdin < 0){
+ fprint(2, "cannot open %s\n", argv[3]);
+ exits("");
+ }
+ strcpy(s, argv[3]);
+ if(dec){
+ if(strcmp(s+strlen(s)-3, ".id") != 0){
+ fprint(2, "input file not a .id file\n");
+ exits("");
+ }
+ s[strlen(s)-3] = '\0';
+ }
+ else
+ strcat(s, ".id");
+ stdout = create(s, OWRITE, 0666);
+ if(stdout < 0){
+ fprint(2, "cannot create %s\n", s);
+ exits("");
+ }
+ }
+ for(i = 0; i < 16; i++)
+ key[i] = argv[2][i];
+ idea_key_setup(key, edkey);
+ m = om = 0;
+ bin = (Biobuf*)malloc(sizeof(Biobuf));
+ bout = (Biobuf*)malloc(sizeof(Biobuf));
+ Binit(bin, stdin, OREAD);
+ Binit(bout, stdout, OWRITE);
+ for(;;){
+ n = Bread(bin, &buf[m], 8-m);
+ if(n <= 0)
+ break;
+ m += n;
+ if(m == 8){
+ idea_cipher(edkey, buf, dec);
+ if(dec){ /* leave last block around */
+ if(om > 0)
+ Bwrite(bout, obuf, 8);
+ memcpy(obuf, buf, 8);
+ om = 8;
+ }
+ else
+ Bwrite(bout, buf, 8);
+ m = 0;
+ }
+ }
+ if(dec){
+ if(om != 8)
+ decerr("no last block");
+ if(m != 0)
+ decerr("last block not 8 bytes long");
+ m = obuf[7];
+ if(m < 0 || m > 7)
+ decerr("bad modulus");
+ for(i = m; i < 8-1; i++)
+ if(obuf[i] != 0)
+ decerr("byte not 0");
+ Bwrite(bout, obuf, m);
+ }
+ else{
+ for(i = m; i < 8; i++)
+ buf[i] = 0;
+ buf[7] = m;
+ idea_cipher(edkey, buf, dec);
+ Bwrite(bout, buf, 8);
+ }
+ Bflush(bout);
+ Bterm(bin);
+ Bterm(bout);
+}
diff --git a/utils/idea/mkfile b/utils/idea/mkfile
new file mode 100644
index 00000000..2721022f
--- /dev/null
+++ b/utils/idea/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=idea
+
+OFILES= idea.$O\
+
+HFILES=
+
+LIBS=bio 9 # libbio.a uses lib9.a so order matters.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/include/a.out.h b/utils/include/a.out.h
new file mode 100644
index 00000000..8c0b7137
--- /dev/null
+++ b/utils/include/a.out.h
@@ -0,0 +1,45 @@
+typedef struct Exec Exec;
+struct Exec
+{
+ long magic; /* magic number */
+ long text; /* size of text segment */
+ long data; /* size of initialized data */
+ long bss; /* size of uninitialized data */
+ long syms; /* size of symbol table */
+ long entry; /* entry point */
+ long spsz; /* size of pc/sp offset table */
+ long pcsz; /* size of pc/line number table */
+};
+
+
+#define HDR_MAGIC 0x00008000 /* header expansion */
+
+#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
+#define A_MAGIC _MAGIC(0, 8) /* 68020 */
+#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
+#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
+#define K_MAGIC _MAGIC(0, 13) /* sparc */
+#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
+#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
+#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
+#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
+#define E_MAGIC _MAGIC(0, 20) /* arm */
+#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
+#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
+#define L_MAGIC _MAGIC(0, 23) /* dec alpha */
+#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
+#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
+#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
+
+#define MIN_MAGIC 8
+#define MAX_MAGIC 26 /* <= 90 */
+
+#define DYN_MAGIC 0x80000000 /* or'd in for dynamically loaded modules */
+
+typedef struct Sym Sym;
+struct Sym
+{
+ long value;
+ char type;
+ char *name;
+};
diff --git a/utils/include/ar.h b/utils/include/ar.h
new file mode 100644
index 00000000..cd538fab
--- /dev/null
+++ b/utils/include/ar.h
@@ -0,0 +1,17 @@
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+
+#define ARFMAG "`\n"
+#define SARNAME 16
+
+struct ar_hdr
+{
+ char name[SARNAME];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char fmag[2];
+};
+#define SAR_HDR (SARNAME+44)
diff --git a/utils/include/mach.h b/utils/include/mach.h
new file mode 100644
index 00000000..f809aa2d
--- /dev/null
+++ b/utils/include/mach.h
@@ -0,0 +1,295 @@
+/*
+ * Architecture-dependent application data
+ */
+#include "a.out.h"
+/*
+ * Supported architectures:
+ * mips,
+ * 68020,
+ * i386,
+ * sparc,
+ * i960 (limited)
+ * 3210DSP (limited)
+ * mips2 (R4000)
+ * arm (limited)
+ */
+enum
+{
+ MMIPS, /* machine types */
+ MSPARC,
+ M68020,
+ MI386,
+ MI960,
+ M3210,
+ MMIPS2,
+ NMIPS2,
+ M29000,
+ MARM,
+ MPOWER,
+ /* types of exectables */
+ FNONE = 0, /* unidentified */
+ FMIPS, /* v.out */
+ FMIPSB, /* mips bootable */
+ FSPARC, /* k.out */
+ FSPARCB, /* Sparc bootable */
+ F68020, /* 2.out */
+ F68020B, /* 68020 bootable */
+ FNEXTB, /* Next bootable */
+ FI386, /* 8.out */
+ FI386B, /* I386 bootable */
+ FI960, /* 6.out */
+ FI960B, /* I960 bootable */
+ F3210, /* x.out */
+ FMIPS2BE, /* 4.out */
+ F29000, /* 9.out */
+ FARM, /* 5.out */
+ FARMB, /* ARM bootable */
+ FPOWER, /* q.out */
+ FPOWERB, /* power pc bootable */
+ FMIPS2LE, /* 4k little endian */
+
+ ANONE = 0, /* dissembler types */
+ AMIPS,
+ AMIPSCO, /* native mips */
+ ASPARC,
+ ASUNSPARC, /* native sun */
+ A68020,
+ AI386,
+ AI8086, /* oh god */
+ AI960,
+ A29000,
+ AARM,
+ APOWER,
+ /* object file types */
+ Obj68020 = 0, /* .2 */
+ ObjSparc, /* .k */
+ ObjMips, /* .v */
+ Obj386, /* .8 */
+ Obj960, /* .6 */
+ Obj3210, /* .x */
+ ObjMips2, /* .4 */
+ Obj29000, /* .9 */
+ ObjArm, /* .5 */
+ ObjPower, /* .q */
+ ObjMips2le, /* .0 */
+ Maxobjtype,
+
+ CNONE = 0, /* symbol table classes */
+ CAUTO,
+ CPARAM,
+ CSTAB,
+ CTEXT,
+ CDATA,
+ CANY /* to look for any class */
+};
+
+typedef struct Map Map;
+typedef struct Symbol Symbol;
+typedef struct Reglist Reglist;
+typedef struct Mach Mach;
+typedef struct Machdata Machdata;
+typedef struct segment segment;
+
+typedef int (*Rsegio)(segment*, ulong, long, char*, int);
+
+/*
+ * Structure to map a segment to a position in a file
+ */
+struct Map {
+ int nsegs; /* number of segments */
+ struct segment { /* per-segment map */
+ char *name; /* the segment name */
+ int fd; /* file descriptor */
+ int inuse; /* in use - not in use */
+ ulong b; /* base */
+ ulong e; /* end */
+ ulong f; /* offset within file */
+ Rsegio mget; /* special get if not 0 */
+ Rsegio mput; /* special put if not 0 */
+ } seg[1]; /* actually n of these */
+};
+
+
+
+/*
+ * Internal structure describing a symbol table entry
+ */
+struct Symbol {
+ void *handle; /* used internally - owning func */
+ /*struct {*/
+ char *name;
+ long value; /* address or stack offset */
+ char type; /* as in a.out.h */
+ char class; /* as above */
+ /*};*/
+};
+
+/*
+ * machine register description
+ */
+struct Reglist {
+ char *rname; /* register name */
+ short roffs; /* offset in u-block */
+ char rflags; /* INTEGER/FLOAT, WRITABLE */
+ char rformat; /* print format: 'x', 'X', 'f', '8' */
+};
+
+enum { /* bits in rflags field */
+ RINT = (0<<0),
+ RFLT = (1<<0),
+ RRDONLY = (1<<1)
+};
+/*
+ * Machine-dependent data is stored in two structures:
+ * Mach - miscellaneous general parameters
+ * Machdata - jump vector of service functions used by debuggers
+ *
+ * Mach is defined in 2.c, 4.c, v.c, k.c, 8.c, 6.c and set in executable.c
+ *
+ * Machdata is defined in 2db.c, 4db.c, vdb.c, kdb.c, 8db.c, and 6db.c
+ * and set in the debugger startup.
+ */
+
+
+struct Mach{
+ char *name;
+ int mtype; /* machine type code */
+ Reglist *reglist; /* register set */
+ ulong regsize; /* sizeof registers in bytes*/
+ ulong fpregsize; /* sizeof fp registers in bytes*/
+ char *pc; /* pc name */
+ char *sp; /* sp name */
+ char *link; /* link register name */
+ char *sbreg; /* static base register name */
+ ulong sb; /* static base register value */
+ int pgsize; /* page size */
+ ulong kbase; /* kernel base address */
+ ulong ktmask; /* ktzero = kbase & ~ktmask */
+ int pcquant; /* quantization of pc */
+ int szaddr; /* sizeof(void*) */
+ int szreg; /* sizeof(register) */
+ int szfloat; /* sizeof(float) */
+ int szdouble; /* sizeof(double) */
+};
+
+extern Mach *mach; /* Current machine */
+
+typedef vlong (*Rgetter)(Map*, char*);
+typedef void (*Tracer)(Map*, ulong, ulong, Symbol*);
+
+struct Machdata { /* Machine-dependent debugger support */
+ uchar bpinst[4]; /* break point instr. */
+ short bpsize; /* size of break point instr. */
+
+ ushort (*swab)(ushort); /* short to local byte order */
+ long (*swal)(long); /* long to local byte order */
+ vlong (*swav)(vlong); /* vlong to local byte order */
+ int (*ctrace)(Map*, ulong, ulong, ulong, Tracer); /* C traceback */
+ ulong (*findframe)(Map*, ulong, ulong, ulong, ulong);/* frame finder */
+ char* (*excep)(Map*, Rgetter); /* last exception */
+ ulong (*bpfix)(ulong); /* breakpoint fixup */
+ int (*sftos)(char*, int, void*); /* single precision float */
+ int (*dftos)(char*, int, void*); /* double precision float */
+ int (*foll)(Map*, ulong, Rgetter, ulong*); /* follow set */
+ int (*das)(Map*, ulong, char, char*, int); /* symbolic disassembly */
+ int (*hexinst)(Map*, ulong, char*, int); /* hex disassembly */
+ int (*instsize)(Map*, ulong); /* instruction size */
+};
+
+/*
+ * Common a.out header describing all architectures
+ */
+typedef struct Fhdr
+{
+ char *name; /* identifier of executable */
+ short type; /* file type - see codes above*/
+ short hdrsz; /* size of this header */
+ long magic; /* magic number */
+ long txtaddr; /* text address */
+ long entry; /* entry point */
+ long txtsz; /* text size */
+ long txtoff; /* start of text in file */
+ long dataddr; /* start of data segment */
+ long datsz; /* size of data seg */
+ long datoff; /* offset to data seg in file */
+ long bsssz; /* size of bss */
+ long symsz; /* size of symbol table */
+ long symoff; /* offset of symbol table in file */
+ long sppcsz; /* size of sp-pc table */
+ long sppcoff; /* offset of sp-pc table in file */
+ long lnpcsz; /* size of line number-pc table */
+ long lnpcoff; /* size of line number-pc table */
+} Fhdr;
+
+extern int asstype; /* dissembler type - machdata.c */
+extern Machdata *machdata; /* jump vector - machdata.c */
+
+Map* attachproc(int, int, int, Fhdr*);
+Map* attachremt(int, Fhdr*);
+int beieee80ftos(char*, int, void*);
+int beieeesftos(char*, int, void*);
+int beieeedftos(char*, int, void*);
+ushort beswab(ushort);
+long beswal(long);
+vlong beswav(vlong);
+int cisctrace(Map*, ulong, ulong, ulong, Tracer);
+ulong ciscframe(Map*, ulong, ulong, ulong, ulong);
+int crackhdr(int fd, Fhdr*);
+long file2pc(char*, ulong);
+int fileelem(Sym**, uchar *, char*, int);
+int fileline(char*, int, ulong);
+int filesym(int, char*, int);
+int findlocal(Symbol*, char*, Symbol*);
+int findseg(Map*, char*);
+int findsym(long, int, Symbol *);
+int fnbound(long, ulong*);
+int fpformat(Map*, Reglist*, char*, int, int);
+int get1(Map*, ulong, uchar*, int);
+int get2(Map*, ulong, ushort*);
+int get4(Map*, ulong, long*);
+int get8(Map*, ulong, vlong*);
+int getauto(Symbol*, int, int, Symbol*);
+Sym* getsym(int);
+int globalsym(Symbol *, int);
+int gsymoff(char*, int, long, int);
+char* _hexify(char*, ulong, int);
+int ieeesftos(char*, int, ulong);
+int ieeedftos(char*, int, ulong, ulong);
+int isar(Biobuf*);
+int leieee80ftos(char*, int, void*);
+int leieeesftos(char*, int, void*);
+int leieeedftos(char*, int, void*);
+ushort leswab(ushort);
+long leswal(long);
+vlong leswav(vlong);
+long line2addr(ulong, ulong, ulong);
+Map* loadmap(Map*, int, Fhdr*);
+int localaddr(Map*, char*, char*, long*, Rgetter);
+int localsym(Symbol*, int);
+int lookup(char*, char*, Symbol*);
+void machbytype(int);
+int machbyname(char*);
+int nextar(Biobuf*, int, char*);
+Map* newmap(Map*, int);
+void objtraverse(void(*)(Sym*, void*), void*);
+int objtype(Biobuf*, char**);
+long pc2sp(ulong);
+long pc2line(ulong);
+int put1(Map*, ulong, uchar*, int);
+int put2(Map*, ulong, ushort);
+int put4(Map*, ulong, long);
+int put8(Map*, ulong, vlong);
+int readar(Biobuf*, int, int, int);
+int readobj(Biobuf*, int);
+struct segment* reloc(Map*, ulong, long*);
+ulong riscframe(Map*, ulong, ulong, ulong, ulong);
+int risctrace(Map*, ulong, ulong, ulong, Tracer);
+int setmap(Map*, int, ulong, ulong, ulong, char*);
+void setmapio(Map*, int, Rsegio, Rsegio);
+Sym* symbase(long*);
+int syminit(int, Fhdr*);
+int symoff(char*, int, long, int);
+void textseg(ulong, Fhdr*);
+int textsym(Symbol*, int);
+void unusemap(Map*, int);
+
diff --git a/utils/include/regexp.h b/utils/include/regexp.h
new file mode 100644
index 00000000..bcd06f3e
--- /dev/null
+++ b/utils/include/regexp.h
@@ -0,0 +1,66 @@
+#pragma src "/usr/inferno/libregexp"
+#pragma lib "libregexp.a"
+
+typedef struct Resub Resub;
+typedef struct Reclass Reclass;
+typedef struct Reinst Reinst;
+typedef struct Reprog Reprog;
+
+/*
+ * Sub expression matches
+ */
+struct Resub{
+ union
+ {
+ char *sp;
+ Rune *rsp;
+ }s;
+ union
+ {
+ char *ep;
+ Rune *rep;
+ }e;
+};
+
+/*
+ * character class, each pair of rune's defines a range
+ */
+struct Reclass{
+ Rune *end;
+ Rune spans[64];
+};
+
+/*
+ * Machine instructions
+ */
+struct Reinst{
+ int type;
+ union {
+ Reclass *cp; /* class pointer */
+ Rune r; /* character */
+ int subid; /* sub-expression id for RBRA and LBRA */
+ Reinst *right; /* right child of OR */
+ }u1;
+ union { /* regexp relies on these two being in the same union */
+ Reinst *left; /* left child of OR */
+ Reinst *next; /* next instruction for CAT & LBRA */
+ }u2;
+};
+
+/*
+ * Reprogram definition
+ */
+struct Reprog{
+ Reinst *startinst; /* start pc */
+ Reclass class[16]; /* .data */
+ Reinst firstinst[5]; /* .text */
+};
+
+extern Reprog *regcomp(char*);
+extern Reprog *regcomplit(char*);
+extern Reprog *regcompnl(char*);
+extern void regerror(char*);
+extern int regexec(Reprog*, char*, Resub*, int);
+extern void regsub(char*, char*, Resub*, int);
+extern int rregexec(Reprog*, Rune*, Resub*, int);
+extern void rregsub(Rune*, Rune*, Resub*, int);
diff --git a/utils/ka/a.h b/utils/ka/a.h
new file mode 100644
index 00000000..05016089
--- /dev/null
+++ b/utils/ka/a.h
@@ -0,0 +1,181 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../kc/k.out.h"
+
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym *sym;
+ long offset;
+ short type;
+ short reg;
+ short xreg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN int nosched;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(long);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+void outcode(int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void outhist(void);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/ka/a.y b/utils/ka/a.y
new file mode 100644
index 00000000..4d927203
--- /dev/null
+++ b/utils/ka/a.y
@@ -0,0 +1,734 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LMOVW LMOVD LMOVB LSWAP LADDW LCMP
+%token <lval> LBRA LFMOV LFCONV LFADD LCPOP LTRAP LJMPL LXORW
+%token <lval> LNOP LEND LRETT LUNIMP LTEXT LDATA LRETRN
+%token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH
+%token <lval> LREG LFREG LR LC LF
+%token <lval> LFSR LFPQ LPSR LSCHED
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset sreg
+%type <gen> addr rreg name psr creg freg
+%type <gen> imm ximm fimm rel fsr fpq
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LSCHED ';'
+ {
+ nosched = $1;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * B.1 load integer instructions
+ */
+ LMOVW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.2 load floating instructions
+ * includes CSR
+ */
+| LMOVD addr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV addr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV fimm ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW addr ',' fsr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.3 load coprocessor instructions
+ * excludes CSR
+ */
+| LMOVW addr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD addr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.4 store integer instructions
+ */
+| LMOVW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW imm ',' addr
+ {
+ if($2.offset != 0)
+ yyerror("constant must be zero");
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB imm ',' addr
+ {
+ if($2.offset != 0)
+ yyerror("constant must be zero");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.5 store floating instructions
+ * includes CSR and CQ
+ */
+| LMOVW freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW fsr ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD fpq ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.6 store coprocessor instructions
+ * excludes CSR and CQ
+ */
+| LMOVW creg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD creg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.7 atomic load unsigned byte (TAS)
+ * B.8 swap
+ */
+| LSWAP addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.9 add instructions
+ * B.10 tagged add instructions
+ * B.11 subtract instructions
+ * B.12 tagged subtract instructions
+ * B.13 multiply step instruction
+ * B.14 logical instructions
+ * B.15 shift instructions
+ * B.17 save/restore
+ */
+| LADDW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LADDW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXORW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LXORW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LXORW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXORW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.16 set hi
+ * other pseudo moves
+ */
+| LMOVW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW ximm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVD ximm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.18 branch on integer condition
+ * B.19 floating point branch on condition
+ * B.20 coprocessor branch on condition
+ */
+| LBRA comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * B.21 call instruction
+ * B.22 jump and link instruction
+ */
+| LJMPL comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LJMPL comma addr
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LJMPL comma sreg ',' rel
+ {
+ outcode($1, &nullgen, $3, &$5);
+ }
+| LJMPL comma sreg ',' addr
+ {
+ outcode($1, &nullgen, $3, &$5);
+ }
+/*
+ * B.23 return from trap
+ */
+| LRETT rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.28 instruction cache flush
+ */
+| LFLUSH rel comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LFLUSH addr comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * B.24 trap on condition
+ */
+| LTRAP rreg ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP imm ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LTRAP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * B.25 read state register instructions
+ */
+| LMOVW psr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * B.26 write state register instructions BOTCH XOR
+ */
+| LMOVW rreg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW imm ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXORW rreg ',' sreg ',' psr
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LXORW imm ',' sreg ',' psr
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * B.27 unimplemented trap
+ */
+| LUNIMP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LUNIMP imm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * B.29 floating point operate
+ */
+| LFCONV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg ',' freg
+ {
+ outcode($1, &$2, $4.reg, &$6);
+ }
+/*
+ * B.30 coprocessor operate
+ */
+| LCPOP creg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCPOP creg ',' creg ',' creg
+ {
+ outcode($1, &$2, $4.reg, &$6);
+ }
+/*
+ * CMP
+ */
+| LCMP rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * NOP
+ */
+| LNOP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LNOP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP freg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP ',' rreg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LNOP ',' freg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * END
+ */
+| LEND comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTEXT name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTEXT name ',' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LDATA name '/' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' fimm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * RETURN
+ */
+| LRETRN comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+rreg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+fsr:
+ LFSR
+ {
+ $$ = nullgen;
+ $$.type = D_PREG;
+ $$.reg = $1;
+ }
+
+fpq:
+ LFPQ
+ {
+ $$ = nullgen;
+ $$.type = D_PREG;
+ $$.reg = $1;
+ }
+
+psr:
+ LPSR
+ {
+ $$ = nullgen;
+ $$.type = D_PREG;
+ $$.reg = $1;
+ }
+
+creg:
+ LCREG
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $1;
+ }
+| LC '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+ximm:
+ '$' addr
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+
+fimm:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+sreg:
+ LREG
+| LR '(' con ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+addr:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| '(' sreg ',' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_ASI;
+ $$.reg = $2;
+ $$.offset = $4;
+ }
+| '(' sreg '+' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.xreg = $4;
+ $$.offset = 0;
+ }
+| name
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+comma:
+| ','
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/ka/l.s b/utils/ka/l.s
new file mode 100644
index 00000000..b982e553
--- /dev/null
+++ b/utils/ka/l.s
@@ -0,0 +1,696 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
+
+#define MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ 20 /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+
+/*
+ * PSR bits
+ */
+#define PSREC 0x00002000
+#define PSREF 0x00001000
+#define PSRSUPER 0x00000080
+#define PSRPSUPER 0x00000040
+#define PSRET 0x00000020
+#define SPL(n) (n<<8)
+
+/*
+ * Magic registers
+ */
+
+#define MACH 6 /* R6 is m-> */
+#define USER 5 /* R5 is u-> */
+
+/*
+ * Fundamental addresses
+ */
+
+#define USERADDR 0xE0000000
+#define UREGADDR (USERADDR+BY2PG-((32+6)*BY2WD))
+#define BOOTSTACK (KTZERO-0*BY2PG)
+#define TRAPS (KTZERO-2*BY2PG)
+
+/*
+ * MMU
+ */
+
+#define VAMASK 0x3FFFFFFF
+#define NPMEG (1<<12)
+#define BY2SEGM (1<<18)
+#define PG2SEGM (1<<6)
+#define NTLBPID (1+NCONTEXT) /* TLBPID 0 is unallocated */
+#define NCONTEXT 8
+#define CONTEXT 0x30000000 /* in ASI 2 */
+
+/*
+ * MMU regions
+ */
+#define INVALIDSEGM 0xFFFC0000 /* highest seg of VA reserved as invalid */
+#define INVALIDPMEG 0x7F
+#define SCREENSEGM 0xFFF80000
+#define SCREENPMEG 0x7E
+#define ROMSEGM 0xFFE80000
+#define ROMEND 0xFFEA0000
+#define PG2ROM ((ROMEND-ROMSEGM)/BY2PG)
+#define IOSEGM0 ROMSEGM /* see mmuinit() */
+#define NIOSEGM ((SCREENSEGM-ROMSEGM)/BY2SEGM)
+#define IOPMEG0 (SCREENPMEG-NIOSEGM)
+#define IOSEGM ROMEND
+#define IOEND SCREENSEGM
+#define TOPPMEG IOPMEG0
+
+/*
+ * MMU entries
+ */
+#define PTEVALID (1<<31)
+#define PTERONLY (0<<30)
+#define PTEWRITE (1<<30)
+#define PTEKERNEL (1<<29)
+#define PTENOCACHE (1<<28)
+#define PTEMAINMEM (0<<26)
+#define PTEIO (1<<26)
+#define PTEACCESS (1<<25)
+#define PTEMODIFY (1<<24)
+#define PTEUNCACHED 0
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 16
+
+#define INVALIDPTE 0
+#define PPN(pa) ((pa>>12)&0xFFFF)
+
+/*
+ * Weird addresses in various ASI's
+ */
+#define CACHETAGS 0x80000000 /* ASI 2 */
+#define CACHEDATA 0x90000000 /* ASI 2 */
+#define SER 0x60000000 /* ASI 2 */
+#define SEVAR 0x60000004 /* ASI 2 */
+#define ASER 0x60000008 /* ASI 2 */
+#define ASEVAR 0x6000000C /* ASI 2 */
+#define ENAB 0x40000000 /* ASI 2 */
+#define ENABCACHE 0x10
+#define ENABRESET 0x04
+
+/*
+ * Virtual addresses
+ */
+#define VTAG(va) ((va>>22)&0x03F)
+#define VPN(va) ((va>>13)&0x1FF)
+
+#define PARAM ((char*)0x40500000)
+#define TLBFLUSH_ 0x01
+
+/*
+ * Address spaces
+ */
+
+#define UZERO 0x00000000 /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define TSTKTOP 0x10000000 /* end of new stack in sysexec */
+#define TSTKSIZ 32
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define KZERO 0xE0000000 /* base of kernel address space */
+#define KTZERO (KZERO+4*BY2PG) /* first address in kernel text */
+#define USTKSIZE (4*1024*1024) /* size of user stack */
+
+#define MACHSIZE 4096
+
+#define isphys(x) (((ulong)(x)&0xF0000000) == KZERO)
+
+#define SYSPSR (SPL(0x0)|PSREF|PSRSUPER|0)
+#define NOOP OR R0, R0; OR R0, R0; OR R0, R0
+
+TEXT start(SB), $-4
+
+ /* get virtual, fast */
+ /* we are executing in segment 0, mapped to pmeg 0. stack is there too */
+ /* get virtual by mapping segment(KZERO) to pmeg 0., and next to 1 */
+ MOVW $KZERO, R7
+ MOVB R0, (R7, 3)
+ MOVW $(KZERO+BY2SEGM), R7
+ MOVW $1, R8
+ MOVB R8, (R7, 3)
+ /* now mapped correctly. jmpl to where we want to be */
+ MOVW $setSB(SB), R2
+ MOVW $startvirt(SB), R7
+ JMPL (R7)
+ MOVW $_mul(SB), R0 /* touch _mul etc.; doesn't need to execute */
+ RETURN /* can't get here */
+
+TEXT startvirt(SB), $-4
+
+ MOVW $BOOTSTACK, R1
+
+ MOVW $(SPL(0xF)|PSREF|PSRSUPER), R7
+ MOVW R7, PSR
+
+ MOVW $(0x35<<22), R7 /* NVM OFM DZM AU */
+ MOVW R7, fsr+0(SB)
+ MOVW fsr+0(SB), FSR
+ FMOVD $0.5, F26 /* 0.5 -> F26 */
+ FSUBD F26, F26, F24 /* 0.0 -> F24 */
+ FADDD F26, F26, F28 /* 1.0 -> F28 */
+ FADDD F28, F28, F30 /* 2.0 -> F30 */
+
+ FMOVD F24, F0
+ FMOVD F24, F2
+ FMOVD F24, F4
+ FMOVD F24, F6
+ FMOVD F24, F8
+ FMOVD F24, F10
+ FMOVD F24, F12
+ FMOVD F24, F14
+ FMOVD F24, F16
+ FMOVD F24, F18
+ FMOVD F24, F20
+ FMOVD F24, F22
+
+ MOVW $mach0(SB), R(MACH)
+/* MOVW $0x8, R7 /**/
+ MOVW R0, WIM
+ JMPL main(SB)
+ MOVW (R0), R0
+ RETURN
+
+TEXT swap1(SB), $0
+
+ TAS (R7), R7 /* LDSTUB, thank you ken */
+ RETURN
+
+TEXT swap1_should_work(SB), $0
+
+ MOVW R7, R8
+ MOVW $1, R7
+ SWAP (R8), R7
+ RETURN
+
+TEXT swap1x(SB), $0
+
+ MOVW PSR, R9
+ MOVW R9, R10
+ AND $~PSRET, R10 /* BUG: book says this is buggy */
+ MOVW R10, PSR
+ NOOP
+ MOVW (R7), R7
+ CMP R7, R0
+ BNE was1
+ MOVW $1, R10
+ MOVW R10, (R8)
+was1:
+ MOVW R9, PSR
+ RETURN
+
+TEXT spllo(SB), $0
+
+ MOVW PSR, R7
+ MOVW R7, R10
+ OR $PSRET, R10
+ MOVW R10, PSR
+ NOOP
+ RETURN
+
+TEXT splhi(SB), $0
+
+ MOVW R15, 4(R(MACH)) /* save PC in m->splpc */
+ MOVW PSR, R7
+ MOVW R7, R10
+ AND $~PSRET, R10 /* BUG: book says this is buggy */
+ MOVW R10, PSR
+ NOOP
+ RETURN
+
+TEXT splx(SB), $0
+
+ MOVW R15, 4(R(MACH)) /* save PC in m->splpc */
+ MOVW R7, PSR /* BUG: book says this is buggy */
+ NOOP
+ RETURN
+
+TEXT spldone(SB), $0
+
+ RETURN
+
+TEXT touser(SB), $0
+ MOVW $(SYSPSR&~PSREF), R8
+ MOVW R8, PSR
+ NOOP
+
+ MOVW R7, R1
+ SAVE R0, R0 /* RETT is implicit RESTORE */
+ MOVW $(UTZERO+32), R7 /* PC; header appears in text */
+ MOVW $(UTZERO+32+4), R8 /* nPC */
+ RETT R7, R8
+
+TEXT rfnote(SB), $0
+
+ MOVW R7, R1 /* 1st arg is &uregpointer */
+ ADD $4, R1 /* point at ureg */
+ JMP restore
+
+TEXT traplink(SB), $-4
+
+ /* R8 to R23 are free to play with */
+ /* R17 contains PC, R18 contains nPC */
+ /* R19 has PSR loaded from vector code */
+
+ ANDCC $PSRPSUPER, R19, R0
+ BE usertrap
+
+kerneltrap:
+ /*
+ * Interrupt or fault from kernel
+ */
+ ANDN $7, R1, R20 /* dbl aligned */
+ MOVW R1, (0-(4*(32+6))+(4*1))(R20) /* save R1=SP */
+ /* really clumsy: store these in Ureg so can be restored below */
+ MOVW R2, (0-(4*(32+6))+(4*2))(R20) /* SB */
+ MOVW R5, (0-(4*(32+6))+(4*5))(R20) /* USER */
+ MOVW R6, (0-(4*(32+6))+(4*6))(R20) /* MACH */
+ SUB $(4*(32+6)), R20, R1
+
+trap1:
+ MOVW Y, R20
+ MOVW R20, (4*(32+0))(R1) /* Y */
+ MOVW TBR, R20
+ MOVW R20, (4*(32+1))(R1) /* TBR */
+ AND $~0x1F, R19 /* force CWP=0 */
+ MOVW R19, (4*(32+2))(R1) /* PSR */
+ MOVW R18, (4*(32+3))(R1) /* nPC */
+ MOVW R17, (4*(32+4))(R1) /* PC */
+ MOVW R0, (4*0)(R1)
+ MOVW R3, (4*3)(R1)
+ MOVW R4, (4*4)(R1)
+ MOVW R7, (4*7)(R1)
+ RESTORE R0, R0
+ /* now our registers R8-R31 are same as before trap */
+ /* save registers two at a time */
+ MOVD R8, (4*8)(R1)
+ MOVD R10, (4*10)(R1)
+ MOVD R12, (4*12)(R1)
+ MOVD R14, (4*14)(R1)
+ MOVD R16, (4*16)(R1)
+ MOVD R18, (4*18)(R1)
+ MOVD R20, (4*20)(R1)
+ MOVD R22, (4*22)(R1)
+ MOVD R24, (4*24)(R1)
+ MOVD R26, (4*26)(R1)
+ MOVD R28, (4*28)(R1)
+ MOVD R30, (4*30)(R1)
+ /* SP and SB and u and m are already set; away we go */
+ MOVW R1, R7 /* pointer to Ureg */
+ SUB $8, R1
+ MOVW $SYSPSR, R8
+ MOVW R8, PSR
+ NOOP
+ JMPL trap(SB)
+
+ ADD $8, R1
+restore:
+ MOVW (4*(32+2))(R1), R8 /* PSR */
+ MOVW R8, PSR
+ NOOP
+
+ MOVD (4*30)(R1), R30
+ MOVD (4*28)(R1), R28
+ MOVD (4*26)(R1), R26
+ MOVD (4*24)(R1), R24
+ MOVD (4*22)(R1), R22
+ MOVD (4*20)(R1), R20
+ MOVD (4*18)(R1), R18
+ MOVD (4*16)(R1), R16
+ MOVD (4*14)(R1), R14
+ MOVD (4*12)(R1), R12
+ MOVD (4*10)(R1), R10
+ MOVD (4*8)(R1), R8
+ SAVE R0, R0
+ MOVD (4*6)(R1), R6
+ MOVD (4*4)(R1), R4
+ MOVD (4*2)(R1), R2
+ MOVW (4*(32+0))(R1), R20 /* Y */
+ MOVW R20, Y
+ MOVW (4*(32+4))(R1), R17 /* PC */
+ MOVW (4*(32+3))(R1), R18 /* nPC */
+ MOVW (4*1)(R1), R1 /* restore R1=SP */
+ RETT R17, R18
+
+usertrap:
+ /*
+ * Interrupt or fault from user
+ */
+ MOVW R1, R8
+ MOVW R2, R9
+ MOVW $setSB(SB), R2
+ MOVW $(USERADDR+BY2PG), R1
+ MOVW R8, (0-(4*(32+6))+(4*1))(R1) /* save R1=SP */
+ MOVW R9, (0-(4*(32+6))+(4*2))(R1) /* save R2=SB */
+ MOVW R5, (0-(4*(32+6))+(4*5))(R1) /* save R5=USER */
+ MOVW R6, (0-(4*(32+6))+(4*6))(R1) /* save R6=MACH */
+ MOVW $USERADDR, R(USER)
+ MOVW $mach0(SB), R(MACH)
+ SUB $(4*(32+6)), R1
+ JMP trap1
+
+TEXT syslink(SB), $-4
+
+ /* R8 to R23 are free to play with */
+ /* R17 contains PC, R18 contains nPC */
+ /* R19 has PSR loaded from vector code */
+ /* assume user did it; syscall checks */
+
+ MOVW R1, R8
+ MOVW R2, R9
+ MOVW $setSB(SB), R2
+ MOVW $(USERADDR+BY2PG), R1
+ MOVW R8, (0-(4*(32+6))+4)(R1) /* save R1=SP */
+ SUB $(4*(32+6)), R1
+ MOVW R9, (4*2)(R1) /* save R2=SB */
+ MOVW R3, (4*3)(R1) /* global register */
+ MOVD R4, (4*4)(R1) /* global register, R5=USER */
+ MOVD R6, (4*6)(R1) /* save R6=MACH, R7=syscall# */
+ MOVW $USERADDR, R(USER)
+ MOVW $mach0(SB), R(MACH)
+ MOVW TBR, R20
+ MOVW R20, (4*(32+1))(R1) /* TBR */
+ AND $~0x1F, R19
+ MOVW R19, (4*(32+2))(R1) /* PSR */
+ MOVW R18, (4*(32+3))(R1) /* nPC */
+ MOVW R17, (4*(32+4))(R1) /* PC */
+ RESTORE R0, R0
+ /* now our registers R8-R31 are same as before trap */
+ MOVW R15, (4*15)(R1)
+ /* SP and SB and u and m are already set; away we go */
+ MOVW R1, R7 /* pointer to Ureg */
+ SUB $8, R1
+ MOVW $SYSPSR, R8
+ MOVW R8, PSR
+ JMPL syscall(SB)
+ /* R7 contains return value from syscall */
+
+ ADD $8, R1
+ MOVW (4*(32+2))(R1), R8 /* PSR */
+ MOVW R8, PSR
+ NOOP
+
+ MOVW (4*15)(R1), R15
+ SAVE R0, R0
+ MOVW (4*6)(R1), R6
+ MOVD (4*4)(R1), R4
+ MOVD (4*2)(R1), R2
+ MOVW (4*(32+4))(R1), R17 /* PC */
+ MOVW (4*(32+3))(R1), R18 /* nPC */
+ MOVW (4*1)(R1), R1 /* restore R1=SP */
+ RETT R17, R18
+
+TEXT puttbr(SB), $0
+
+ MOVW R7, TBR
+ NOOP
+ RETURN
+
+TEXT gettbr(SB), $0
+
+ MOVW TBR, R7
+ RETURN
+
+TEXT r1(SB), $0
+
+ MOVW R1, R7
+ RETURN
+
+TEXT getwim(SB), $0
+
+ MOVW WIM, R7
+ RETURN
+
+TEXT setlabel(SB), $0
+
+ MOVW R1, (R7)
+ MOVW R15, 4(R7)
+ MOVW $0, R7
+ RETURN
+
+TEXT gotolabel(SB), $0
+
+ MOVW (R7), R1
+ MOVW 4(R7), R15
+ MOVW $1, R7
+ RETURN
+
+TEXT putcxsegm(SB), $0
+
+ MOVW R7, R8 /* context */
+ MOVW 4(FP), R9 /* segment addr */
+ MOVW 8(FP), R10 /* segment value */
+ MOVW $0xFFE80118, R7
+ JMPL (R7)
+ RETURN
+
+TEXT getpsr(SB), $0
+
+ MOVW PSR, R7
+ RETURN
+
+TEXT putcxreg(SB), $0
+
+ MOVW $CONTEXT, R8
+ MOVB R7, (R8, 2)
+ RETURN
+
+TEXT putb2(SB), $0
+
+ MOVW 4(FP), R8
+ MOVB R8, (R7, 2)
+ RETURN
+
+TEXT getb2(SB), $0
+
+ MOVB (R7, 2), R7
+ RETURN
+
+TEXT getw2(SB), $0
+
+ MOVW (R7, 2), R7
+ RETURN
+
+TEXT putw2(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 2)
+ RETURN
+
+TEXT putw4(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 4)
+ RETURN
+
+TEXT getw4(SB), $0
+
+ MOVW (R7, 4), R7
+ RETURN
+
+TEXT putwC(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 0xC)
+ RETURN
+
+TEXT putwD(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 0xD)
+ RETURN
+
+TEXT putwD16(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xD)
+ RETURN
+
+TEXT putwE(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 0xE)
+ RETURN
+
+TEXT putwE16(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ ADD $(1<<4), R7
+ MOVW R8, (R7, 0xE)
+ RETURN
+
+TEXT putsegm(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, 3)
+ RETURN
+
+/*
+ * in savefpregs and restfpregs, incoming R7 points to doubleword
+ * below where F0 will go; doubleword align in and backfill FSR
+ */
+TEXT savefpregs(SB), $0
+
+ ADD $8, R7
+ ANDN $7, R7 /* now MOVD-aligned */
+ MOVW FSR, -4(R7)
+
+ MOVD F0, (0*4)(R7)
+ MOVD F2, (2*4)(R7)
+ MOVD F4, (4*4)(R7)
+ MOVD F6, (6*4)(R7)
+ MOVD F8, (8*4)(R7)
+ MOVD F10, (10*4)(R7)
+ MOVD F12, (12*4)(R7)
+ MOVD F14, (14*4)(R7)
+ MOVD F16, (16*4)(R7)
+ MOVD F18, (18*4)(R7)
+ MOVD F20, (20*4)(R7)
+ MOVD F22, (22*4)(R7)
+ MOVD F24, (24*4)(R7)
+ MOVD F26, (26*4)(R7)
+ MOVD F28, (28*4)(R7)
+ MOVD F30, (30*4)(R7)
+
+ MOVW PSR, R8
+ ANDN $PSREF, R8
+ MOVW R8, PSR
+ RETURN
+
+TEXT restfpregs(SB), $0
+
+ MOVW PSR, R8
+ OR $PSREF, R8
+ MOVW R8, PSR
+
+ ADD $8, R7
+ ANDN $7, R7 /* now MOVD-aligned */
+ OR R0, R0
+
+ MOVW -4(R7), FSR
+
+ MOVD (0*4)(R7), F0
+ MOVD (2*4)(R7), F2
+ MOVD (4*4)(R7), F4
+ MOVD (6*4)(R7), F6
+ MOVD (8*4)(R7), F8
+ MOVD (10*4)(R7), F10
+ MOVD (12*4)(R7), F12
+ MOVD (14*4)(R7), F14
+ MOVD (16*4)(R7), F16
+ MOVD (18*4)(R7), F18
+ MOVD (20*4)(R7), F20
+ MOVD (22*4)(R7), F22
+ MOVD (24*4)(R7), F24
+ MOVD (26*4)(R7), F26
+ MOVD (28*4)(R7), F28
+ MOVD (30*4)(R7), F30
+
+ ANDN $PSREF, R8
+ MOVW R8, PSR
+ RETURN
+
+TEXT clearfpintr(SB), $0
+
+ MOVW $fpq+BY2WD(SB), R7
+ ANDN $0x7, R7 /* must be D aligned */
+ MOVW $fsr+0(SB), R9
+clrq:
+ MOVD FQ, (R7)
+ MOVW FSR, (R9)
+ MOVW (R9), R8
+ AND $(1<<13), R8 /* queue not empty? */
+ BNE clrq
+ RETURN
+
+TEXT getfsr(SB), $0
+ MOVW $fsr+0(SB), R7
+ MOVW FSR, (R7)
+ MOVW (R7), R7
+ RETURN
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL fpq+0(SB), $(3*BY2WD)
+GLOBL fsr+0(SB), $BY2WD
diff --git a/utils/ka/lex.c b/utils/ka/lex.c
new file mode 100644
index 00000000..39c8b507
--- /dev/null
+++ b/utils/ka/lex.c
@@ -0,0 +1,722 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = 'k';
+ thestring = "sparc";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "FSR", LFSR, D_FSR,
+ "CSR", LFSR, D_CSR,
+
+ "FQ", LFPQ, D_FPQ,
+ "CQ", LFPQ, D_CPQ,
+
+ "Y", LPSR, D_Y,
+ "PSR", LPSR, D_PSR,
+ "WIM", LPSR, D_WIM,
+ "TBR", LPSR, D_TBR,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+ "R16", LREG, 16,
+ "R17", LREG, 17,
+ "R18", LREG, 18,
+ "R19", LREG, 19,
+ "R20", LREG, 20,
+ "R21", LREG, 21,
+ "R22", LREG, 22,
+ "R23", LREG, 23,
+ "R24", LREG, 24,
+ "R25", LREG, 25,
+ "R26", LREG, 26,
+ "R27", LREG, 27,
+ "R28", LREG, 28,
+ "R29", LREG, 29,
+ "R30", LREG, 30,
+ "R31", LREG, 31,
+
+ "C", LC, 0,
+ "C0", LCREG, 0,
+ "C1", LCREG, 1,
+ "C2", LCREG, 2,
+ "C3", LCREG, 3,
+ "C4", LCREG, 4,
+ "C5", LCREG, 5,
+ "C6", LCREG, 6,
+ "C7", LCREG, 7,
+ "C8", LCREG, 8,
+ "C9", LCREG, 9,
+ "C10", LCREG, 10,
+ "C11", LCREG, 11,
+ "C12", LCREG, 12,
+ "C13", LCREG, 13,
+ "C14", LCREG, 14,
+ "C15", LCREG, 15,
+ "C16", LCREG, 16,
+ "C17", LCREG, 17,
+ "C18", LCREG, 18,
+ "C19", LCREG, 19,
+ "C20", LCREG, 20,
+ "C21", LCREG, 21,
+ "C22", LCREG, 22,
+ "C23", LCREG, 23,
+ "C24", LCREG, 24,
+ "C25", LCREG, 25,
+ "C26", LCREG, 26,
+ "C27", LCREG, 27,
+ "C28", LCREG, 28,
+ "C29", LCREG, 29,
+ "C30", LCREG, 30,
+ "C31", LCREG, 31,
+
+ "F", LF, 0,
+ "F0", LFREG, 0,
+ "F2", LFREG, 2,
+ "F4", LFREG, 4,
+ "F6", LFREG, 6,
+ "F8", LFREG, 8,
+ "F10", LFREG, 10,
+ "F12", LFREG, 12,
+ "F14", LFREG, 14,
+ "F16", LFREG, 16,
+ "F18", LFREG, 18,
+ "F20", LFREG, 20,
+ "F22", LFREG, 22,
+ "F24", LFREG, 24,
+ "F26", LFREG, 26,
+ "F28", LFREG, 28,
+ "F30", LFREG, 30,
+ "F1", LFREG, 1,
+ "F3", LFREG, 3,
+ "F5", LFREG, 5,
+ "F7", LFREG, 7,
+ "F9", LFREG, 9,
+ "F11", LFREG, 11,
+ "F13", LFREG, 13,
+ "F15", LFREG, 15,
+ "F17", LFREG, 17,
+ "F19", LFREG, 19,
+ "F21", LFREG, 21,
+ "F23", LFREG, 23,
+ "F25", LFREG, 25,
+ "F27", LFREG, 27,
+ "F29", LFREG, 29,
+ "F31", LFREG, 31,
+
+ "ADD", LADDW, AADD,
+ "ADDCC", LADDW, AADDCC,
+ "ADDX", LADDW, AADDX,
+ "ADDXCC", LADDW, AADDXCC,
+ "AND", LADDW, AAND,
+ "ANDCC", LADDW, AANDCC,
+ "ANDN", LADDW, AANDN,
+ "ANDNCC", LADDW, AANDNCC,
+ "BA", LBRA, ABA,
+ "BCC", LBRA, ABCC,
+ "BCS", LBRA, ABCS,
+ "BE", LBRA, ABE,
+ "BG", LBRA, ABG,
+ "BGE", LBRA, ABGE,
+ "BGU", LBRA, ABGU,
+ "BL", LBRA, ABL,
+ "BLE", LBRA, ABLE,
+ "BLEU", LBRA, ABLEU,
+ "BN", LBRA, ABN,
+ "BNE", LBRA, ABNE,
+ "BNEG", LBRA, ABNEG,
+ "BPOS", LBRA, ABPOS,
+ "BVC", LBRA, ABVC,
+ "BVS", LBRA, ABVS,
+ "CB0", LBRA, ACB0,
+ "CB01", LBRA, ACB01,
+ "CB012", LBRA, ACB012,
+ "CB013", LBRA, ACB013,
+ "CB02", LBRA, ACB02,
+ "CB023", LBRA, ACB023,
+ "CB03", LBRA, ACB03,
+ "CB1", LBRA, ACB1,
+ "CB12", LBRA, ACB12,
+ "CB123", LBRA, ACB123,
+ "CB13", LBRA, ACB13,
+ "CB2", LBRA, ACB2,
+ "CB23", LBRA, ACB23,
+ "CB3", LBRA, ACB3,
+ "CBA", LBRA, ACBA,
+ "CBN", LBRA, ACBN,
+ "CMP", LCMP, ACMP,
+ "CPOP1", LCPOP, ACPOP1,
+ "CPOP2", LCPOP, ACPOP2,
+ "DATA", LDATA, ADATA,
+ "DIV", LADDW, ADIV,
+ "DIVL", LADDW, ADIVL,
+ "END", LEND, AEND,
+ "FABSD", LFCONV, AFABSD,
+ "FABSF", LFCONV, AFABSF,
+ "FABSX", LFCONV, AFABSX,
+ "FADDD", LFADD, AFADDD,
+ "FADDF", LFADD, AFADDF,
+ "FADDX", LFADD, AFADDX,
+ "FBA", LBRA, AFBA,
+ "FBE", LBRA, AFBE,
+ "FBG", LBRA, AFBG,
+ "FBGE", LBRA, AFBGE,
+ "FBL", LBRA, AFBL,
+ "FBLE", LBRA, AFBLE,
+ "FBLG", LBRA, AFBLG,
+ "FBN", LBRA, AFBN,
+ "FBNE", LBRA, AFBNE,
+ "FBO", LBRA, AFBO,
+ "FBU", LBRA, AFBU,
+ "FBUE", LBRA, AFBUE,
+ "FBUG", LBRA, AFBUG,
+ "FBUGE", LBRA, AFBUGE,
+ "FBUL", LBRA, AFBUL,
+ "FBULE", LBRA, AFBULE,
+ "FCMPD", LFADD, AFCMPD,
+ "FCMPED", LFADD, AFCMPED,
+ "FCMPEF", LFADD, AFCMPEF,
+ "FCMPEX", LFADD, AFCMPEX,
+ "FCMPF", LFADD, AFCMPF,
+ "FCMPX", LFADD, AFCMPX,
+ "FDIVD", LFADD, AFDIVD,
+ "FDIVF", LFADD, AFDIVF,
+ "FDIVX", LFADD, AFDIVX,
+ "FMOVD", LFMOV, AFMOVD,
+ "FMOVDF", LFCONV, AFMOVDF,
+ "FMOVDW", LFCONV, AFMOVDW,
+ "FMOVDX", LFCONV, AFMOVDX,
+ "FMOVF", LFMOV, AFMOVF,
+ "FMOVFD", LFCONV, AFMOVFD,
+ "FMOVFW", LFCONV, AFMOVFW,
+ "FMOVFX", LFCONV, AFMOVFX,
+ "FMOVWD", LFCONV, AFMOVWD,
+ "FMOVWF", LFCONV, AFMOVWF,
+ "FMOVWX", LFCONV, AFMOVWX,
+ "FMOVX", LFCONV, AFMOVX,
+ "FMOVXD", LFCONV, AFMOVXD,
+ "FMOVXF", LFCONV, AFMOVXF,
+ "FMOVXW", LFCONV, AFMOVXW,
+ "FMULD", LFADD, AFMULD,
+ "FMULF", LFADD, AFMULF,
+ "FMULX", LFADD, AFMULX,
+ "FNEGD", LFCONV, AFNEGD,
+ "FNEGF", LFCONV, AFNEGF,
+ "FNEGX", LFCONV, AFNEGX,
+ "FSQRTD", LFCONV, AFSQRTD,
+ "FSQRTF", LFCONV, AFSQRTF,
+ "FSQRTX", LFCONV, AFSQRTX,
+ "FSUBD", LFADD, AFSUBD,
+ "FSUBF", LFADD, AFSUBF,
+ "FSUBX", LFADD, AFSUBX,
+ "GLOBL", LTEXT, AGLOBL,
+ "IFLUSH", LFLUSH, AIFLUSH,
+ "JMPL", LJMPL, AJMPL,
+ "JMP", LJMPL, AJMP,
+ "MOD", LADDW, AMOD,
+ "MODL", LADDW, AMODL,
+ "MOVB", LMOVB, AMOVB,
+ "MOVBU", LMOVB, AMOVBU,
+ "MOVD", LMOVD, AMOVD,
+ "MOVH", LMOVB, AMOVH,
+ "MOVHU", LMOVB, AMOVHU,
+ "MOVW", LMOVW, AMOVW,
+ "MUL", LADDW, AMUL,
+ "MULSCC", LADDW, AMULSCC,
+ "NOP", LNOP, ANOP,
+ "OR", LADDW, AOR,
+ "ORCC", LADDW, AORCC,
+ "ORN", LADDW, AORN,
+ "ORNCC", LADDW, AORNCC,
+ "RESTORE", LADDW, ARESTORE,
+ "RETT", LRETT, ARETT,
+ "RETURN", LRETRN, ARETURN,
+ "SAVE", LADDW, ASAVE,
+ "SLL", LADDW, ASLL,
+ "SRA", LADDW, ASRA,
+ "SRL", LADDW, ASRL,
+ "SUB", LADDW, ASUB,
+ "SUBCC", LADDW, ASUBCC,
+ "SUBX", LADDW, ASUBX,
+ "SUBXCC", LADDW, ASUBXCC,
+ "SWAP", LSWAP, ASWAP,
+ "TA", LTRAP, ATA,
+ "TADDCC", LADDW, ATADDCC,
+ "TADDCCTV", LADDW, ATADDCCTV,
+ "TAS", LSWAP, ATAS,
+ "TCC", LTRAP, ATCC,
+ "TCS", LTRAP, ATCS,
+ "TE", LTRAP, ATE,
+ "TEXT", LTEXT, ATEXT,
+ "TG", LTRAP, ATG,
+ "TGE", LTRAP, ATGE,
+ "TGU", LTRAP, ATGU,
+ "TL", LTRAP, ATL,
+ "TLE", LTRAP, ATLE,
+ "TLEU", LTRAP, ATLEU,
+ "TN", LTRAP, ATN,
+ "TNE", LTRAP, ATNE,
+ "TNEG", LTRAP, ATNEG,
+ "TPOS", LTRAP, ATPOS,
+ "TSUBCC", LADDW, ATSUBCC,
+ "TSUBCCTV", LADDW, ATSUBCCTV,
+ "TVC", LTRAP, ATVC,
+ "TVS", LTRAP, ATVS,
+ "UNIMP", LUNIMP, AUNIMP,
+ "WORD", LUNIMP, AWORD,
+ "XNOR", LADDW, AXNOR,
+ "XNORCC", LADDW, AXNORCC,
+ "XOR", LXORW, AXOR,
+ "XORCC", LADDW, AXORCC,
+
+ "SCHED", LSCHED, 0,
+ "NOSCHED", LSCHED, 0x80,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ nullgen.xreg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_CREG:
+ case D_PREG:
+ break;
+
+ case D_OREG:
+ case D_ASI:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+ }
+}
+
+void
+outcode(int a, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+ if(g1->xreg != NREG) {
+ if(reg != NREG || g2->xreg != NREG)
+ yyerror("bad addressing modes");
+ reg = g1->xreg;
+ } else
+ if(g2->xreg != NREG) {
+ if(reg != NREG)
+ yyerror("bad addressing modes");
+ reg = g2->xreg;
+ }
+jackpot:
+ sf = 0;
+ s = g1->sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g1->name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, reg|nosched);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/ka/mkfile b/utils/ka/mkfile
new file mode 100644
index 00000000..6251c038
--- /dev/null
+++ b/utils/ka/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=ka
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../kc/k.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/ka/note b/utils/ka/note
new file mode 100644
index 00000000..3ecf7bc7
--- /dev/null
+++ b/utils/ka/note
@@ -0,0 +1,274 @@
+/* load instructions */
+
+ LDSB MOVB x, R
+ LDSBA MOVB x, R, asi
+ LDSH MOVH x, R
+ LDSHA MOVH x, R, asi
+ LDUB MOVBU x, R
+ LDUBA MOVBU x, R, asi
+ LDUH MOVHU x, R
+ LDUHA MOVHU x, R, asi
+ LD MOVW x, R
+ LDA MOVW x, R, asi
+ LDD MOVD x, R
+ LDDA MOVD x, R, asi
+
+note: x is (R+R) or offset(R)
+note: MOVD is a bad name, means double word
+
+/* load floating */
+
+ LDF MOVF x, FR
+ LDDF MOVD x, FR
+ LDFSR MOVW x, FPSR
+
+note: MOVF maybe is MOVW
+
+/* load coprocessor */
+
+ LDC MOVW x, CR
+ LDDC MOVD x, CR
+ LDCSR MOVW x, CPSR
+
+/* store */
+
+ STB MOVB R, x
+ STBA MOVB R, x, asi
+ STH MOVH R, x
+ STHA MOVH R, x, asi
+ ST MOVW R, x
+ STA MOVW R, x, asi
+ STD MOVD R, x
+ STDA MOVD R, x, asi
+
+/* store floating *
+
+ STF MOVF FR, x
+ STDF MOVD FR, x
+ STFSR MOVW FPSR, x
+ STDFQ MOVD FPQ, x
+
+note: STDFQ gok
+
+/* store coprocessor */
+
+ STC MOVW CR, x
+ STDC MOVD CR, x
+ STCSR MOVW CPSR, x
+ STDCQ MOVD CPQ, x
+
+/* atomic load/store */
+
+ LDSTUB TAS x
+ LDSTUBA TAS x, asi
+
+/* swap */
+
+ SWAP SWAP R, x
+ SWAPA SWAP R, x, asi
+
+/* calc */
+
+ ADD ADDW y,R, R
+ ADDcc ADDWT y,R, R
+ ADDX ADDC y,R, R
+ ADDXcc ADDCT y,R, R
+ TADDcc
+ TADDccTV
+ SUB
+ SUBcc
+ SUBX
+ SUBXcc
+ TSUBcc
+ TSUBccTV
+ MULScc
+ AND
+ ANDcc
+ ANDN
+ ANDNcc
+ OR
+ ORcc
+ ORN
+ ORNcc
+ XOR
+ XORcc
+ XNOR
+ XNORcc
+ SLL
+ SRL
+ SRA
+
+note: y is R or $simm13
+
+/* sethi */
+
+ SETHI MOVW $c, R /* high 22 bits */
+
+/* save/restore (same as add) */
+
+ SAVE SAVE y,R, R
+ RESTORE RESTORE y,R, R
+
+/* branch on cc */
+
+ BA
+ BN
+ BNE
+ BE
+ BG
+ BLE
+ BGE
+ BL
+ BGU
+ BLEU
+ BCC
+ BCS
+ BPOS
+ BNEG
+ BVC
+ BVS
+
+note: annul bit?
+
+/* branch on fcc */
+
+ FBA
+ FBN
+ FBU
+ FBG
+ FBUG
+ FBL
+ FBUL
+ FBLG
+ FBNE
+ FBE
+ FBUE
+ FBGE
+ FBUGE
+ FBLE
+ FBULE
+ FBO
+
+note: annul bit?
+
+/* branch on coprocecssor cc */
+
+ CBA
+ CBN
+ CB3
+ CB2
+ CB23
+ CB1
+ CB13
+ CB12
+ CB123
+ CB0
+ CB03
+ CB02
+ CB023
+ CB01
+ CB013
+ CB012
+
+note: annul bit?
+
+/* call */
+
+ CALL
+ JAL x, R
+
+/* return from trap */
+
+ RETT x
+
+/* trap on integer cc */
+
+ TA
+ TN
+ TNE
+ TE
+ TG
+ TLE
+ TGE
+ TL
+ TGU
+ TLEU
+ TCC
+ TCS
+ TPOS
+ TNEG
+ TVC
+ TVS
+
+/* read state register */
+
+ RDY MOVW Y, R
+ RDPSR MOVW PSR, R
+ RDWIM MOVW WIM, R
+ RDTBR MOVW TBR, R
+
+/* write state register */
+
+ WRY MOVW R, Y
+ WRPSR MOVW R, PSR
+ WRWIM MOVW R, WIM
+ WRTBR MOVW R, TBR
+
+/* unimplemented */
+
+ UNIMP $C22
+
+/* instruction cache flush */
+
+ IFLUSH x
+
+/* floating op */
+
+ FiTOs
+ FiTOd
+ FiTOx
+
+ FsTOi
+ FdTOi
+ FxTOi
+
+ FsTOd
+ FsTOx
+ FdTOs
+ FdTOx
+ FxTOs
+ FxTOd
+
+ FMOVs
+ FNEGs
+ FABSs
+
+ FSQRTs
+ FSQRTd
+ FSQRTx
+
+ FADDs
+ FADDd
+ FADDx
+ FSUBs
+ FSUBd
+ FSUBx
+
+ FMULs
+ FMULd
+ FMULx
+ FDIVs
+ FDIVd
+ FDIVx
+
+ FCMPs
+ FCMPd
+ FCMPx
+ FCMPEs
+ FCMPEd
+ FCMPEx
+
+/* coprocessor op */
+
+ CPop1
+ CPop2
diff --git a/utils/kc/cgen.c b/utils/kc/cgen.c
new file mode 100644
index 00000000..e4e54d48
--- /dev/null
+++ b/utils/kc/cgen.c
@@ -0,0 +1,1087 @@
+#include "gc.h"
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o;
+ long v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OMUL:
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case ODIV:
+ case OMOD:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ if(debug['M'])
+ print("%L multiply\n", n->lineno);
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, n, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, n, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+ regalloc(&nod1, n, Z);
+ gopcode(OAS, &nod2, Z, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ regalloc(&nod3, r, Z);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ cgen(r, &nod3);
+ } else {
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(n->op, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ cgen(l, nn);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ if(n->op == OCONST) {
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ nodreg(&nod1, n, NREG+FREGZERO);
+ gopcode(o, &nod, Z, &nod1);
+ } else
+ gopcode(o, &nod, Z, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(sconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, Z, r);
+ regfree(&nod);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod1, Z, &nod);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1L), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0L), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && nn->complex >= FNX) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ /* BOTCH -- functions can clobber rathole */
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 5) {
+ layout(&nod1, &nod2, w, 0, Z);
+ goto out;
+ }
+
+ /*
+ * minimize space for unrolling loop
+ * 3,4,5 times. (6 or more is never minimum)
+ * if small structure, try 2 also.
+ */
+ c = 0; /* set */
+ m = 100;
+ i = 3;
+ if(w <= 15)
+ i = 2;
+ for(; i<=5; i++)
+ if(i + w%i <= m) {
+ c = i;
+ m = c + w%c;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ layout(&nod1, &nod2, w%c, w/c, &nod3);
+
+ pc1 = pc;
+ layout(&nod1, &nod2, c, 0, Z);
+
+ gopcode(OSUB, nodconst(1L), Z, &nod3);
+ nod1.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
+ nod2.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
+
+ gopcode(OGT, &nod3, Z, nodconst(0));
+ patch(p, pc1);
+
+ regfree(&nod3);
+out:
+ regfree(&nod1);
+ regfree(&nod2);
+}
+
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, &regnode, Z);
+ regalloc(&t2, &regnode, Z);
+ if(c > 0) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(cn != Z)
+ gopcode(OAS, nodconst(cv), Z, cn);
+ if(c > 1) {
+ gopcode(OAS, f, Z, &t2);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 0) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 1) {
+ gopcode(OAS, &t2, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
diff --git a/utils/kc/enam.c b/utils/kc/enam.c
new file mode 100644
index 00000000..fd7a8411
--- /dev/null
+++ b/utils/kc/enam.c
@@ -0,0 +1,175 @@
+char *anames[] =
+{
+ "XXX",
+ "ADD",
+ "ADDCC",
+ "ADDX",
+ "ADDXCC",
+ "AND",
+ "ANDCC",
+ "ANDN",
+ "ANDNCC",
+ "BA",
+ "BCC",
+ "BCS",
+ "BE",
+ "BG",
+ "BGE",
+ "BGU",
+ "BL",
+ "BLE",
+ "BLEU",
+ "BN",
+ "BNE",
+ "BNEG",
+ "BPOS",
+ "BVC",
+ "BVS",
+ "CB0",
+ "CB01",
+ "CB012",
+ "CB013",
+ "CB02",
+ "CB023",
+ "CB03",
+ "CB1",
+ "CB12",
+ "CB123",
+ "CB13",
+ "CB2",
+ "CB23",
+ "CB3",
+ "CBA",
+ "CBN",
+ "CMP",
+ "CPOP1",
+ "CPOP2",
+ "DATA",
+ "DIV",
+ "DIVL",
+ "FABSD",
+ "FABSF",
+ "FABSX",
+ "FADDD",
+ "FADDF",
+ "FADDX",
+ "FBA",
+ "FBE",
+ "FBG",
+ "FBGE",
+ "FBL",
+ "FBLE",
+ "FBLG",
+ "FBN",
+ "FBNE",
+ "FBO",
+ "FBU",
+ "FBUE",
+ "FBUG",
+ "FBUGE",
+ "FBUL",
+ "FBULE",
+ "FCMPD",
+ "FCMPED",
+ "FCMPEF",
+ "FCMPEX",
+ "FCMPF",
+ "FCMPX",
+ "FDIVD",
+ "FDIVF",
+ "FDIVX",
+ "FMOVD",
+ "FMOVDF",
+ "FMOVDW",
+ "FMOVDX",
+ "FMOVF",
+ "FMOVFD",
+ "FMOVFW",
+ "FMOVFX",
+ "FMOVWD",
+ "FMOVWF",
+ "FMOVWX",
+ "FMOVX",
+ "FMOVXD",
+ "FMOVXF",
+ "FMOVXW",
+ "FMULD",
+ "FMULF",
+ "FMULX",
+ "FNEGD",
+ "FNEGF",
+ "FNEGX",
+ "FSQRTD",
+ "FSQRTF",
+ "FSQRTX",
+ "FSUBD",
+ "FSUBF",
+ "FSUBX",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "IFLUSH",
+ "JMPL",
+ "JMP",
+ "MOD",
+ "MODL",
+ "MOVB",
+ "MOVBU",
+ "MOVD",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MUL",
+ "MULSCC",
+ "NAME",
+ "NOP",
+ "OR",
+ "ORCC",
+ "ORN",
+ "ORNCC",
+ "RESTORE",
+ "RETT",
+ "RETURN",
+ "SAVE",
+ "SLL",
+ "SRA",
+ "SRL",
+ "SUB",
+ "SUBCC",
+ "SUBX",
+ "SUBXCC",
+ "SWAP",
+ "TA",
+ "TADDCC",
+ "TADDCCTV",
+ "TAS",
+ "TCC",
+ "TCS",
+ "TE",
+ "TEXT",
+ "TG",
+ "TGE",
+ "TGU",
+ "TL",
+ "TLE",
+ "TLEU",
+ "TN",
+ "TNE",
+ "TNEG",
+ "TPOS",
+ "TSUBCC",
+ "TSUBCCTV",
+ "TVC",
+ "TVS",
+ "UNIMP",
+ "WORD",
+ "XNOR",
+ "XNORCC",
+ "XOR",
+ "XORCC",
+ "END",
+ "DYNT",
+ "INIT",
+ "SIGNAME",
+ "LAST"
+};
diff --git a/utils/kc/gc.h b/utils/kc/gc.h
new file mode 100644
index 00000000..a081f4dd
--- /dev/null
+++ b/utils/kc/gc.h
@@ -0,0 +1,338 @@
+#include "../cc/cc.h"
+#include "../kc/k.out.h"
+
+/*
+ * kc/sparc
+ * Sun sparc
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_VLONG 8
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Adr
+{
+ long offset;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+ char reg;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN int hintabsize;
+EXTERN long maxargsafe;
+EXTERN Multab multab[20];
+EXTERN int mnstring;
+EXTERN int retok;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN char reg[NREG+NREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void usedset(Node*, int);
+void noretval(int);
+void xcom(Node*);
+void bcomplex(Node*);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+int sval(long);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(Node*, long);
+int mulcon1(Node*, long, Node*);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+/*
+ * com64.c
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/utils/kc/k.out.h b/utils/kc/k.out.h
new file mode 100644
index 00000000..2b3bd7f2
--- /dev/null
+++ b/utils/kc/k.out.h
@@ -0,0 +1,263 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 32
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+enum
+{
+ REGZERO = 0, /* always zero */
+ REGSP = 1, /* stack pointer */
+ REGSB = 2, /* static pointer */
+ REGSB1 = 3, /* (possible) second static pointer */
+ REGEXT = 6, /* first external register, grows-- */
+ REGRET = 7, /* return register and first temp, grows++ */
+ REGTMP = 14, /* used by the loader */
+ REGLINK = 15, /* subroutine linkage */
+ REGARG = 7, /* first arg passed in */
+
+ FREGRET = 0,
+ FREGEXT = 22, /* first external register */
+ FREGZERO = 24, /* both float and double */
+ FREGHALF = 26, /* double */
+ FREGONE = 28, /* double */
+ FREGTWO = 30 /* double */
+/*
+ * GENERAL:
+ *
+ * compiler allocates R7 up as temps
+ * compiler allocates external registers R6 down
+ * compiler allocates register variables F4-F22
+ * compiler allocates external registers F22 down
+ */
+};
+
+enum as
+{
+ AXXX = 0,
+ AADD,
+ AADDCC,
+ AADDX,
+ AADDXCC,
+ AAND,
+ AANDCC,
+ AANDN,
+ AANDNCC,
+ ABA,
+ ABCC,
+ ABCS,
+ ABE,
+ ABG,
+ ABGE,
+ ABGU,
+ ABL,
+ ABLE,
+ ABLEU,
+ ABN,
+ ABNE,
+ ABNEG,
+ ABPOS,
+ ABVC,
+ ABVS,
+ ACB0,
+ ACB01,
+ ACB012,
+ ACB013,
+ ACB02,
+ ACB023,
+ ACB03,
+ ACB1,
+ ACB12,
+ ACB123,
+ ACB13,
+ ACB2,
+ ACB23,
+ ACB3,
+ ACBA,
+ ACBN,
+ ACMP, /* pseudo op */
+ ACPOP1,
+ ACPOP2,
+ ADATA,
+ ADIV,
+ ADIVL,
+ AFABSD, /* pseudo op */
+ AFABSF,
+ AFABSX, /* pseudo op */
+ AFADDD,
+ AFADDF,
+ AFADDX,
+ AFBA,
+ AFBE,
+ AFBG,
+ AFBGE,
+ AFBL,
+ AFBLE,
+ AFBLG,
+ AFBN,
+ AFBNE,
+ AFBO,
+ AFBU,
+ AFBUE,
+ AFBUG,
+ AFBUGE,
+ AFBUL,
+ AFBULE,
+ AFCMPD,
+ AFCMPED,
+ AFCMPEF,
+ AFCMPEX,
+ AFCMPF,
+ AFCMPX,
+ AFDIVD,
+ AFDIVF,
+ AFDIVX,
+ AFMOVD, /* pseudo op */
+ AFMOVDF,
+ AFMOVDW,
+ AFMOVDX,
+ AFMOVF,
+ AFMOVFD,
+ AFMOVFW,
+ AFMOVFX,
+ AFMOVWD,
+ AFMOVWF,
+ AFMOVWX,
+ AFMOVX, /* pseudo op */
+ AFMOVXD,
+ AFMOVXF,
+ AFMOVXW,
+ AFMULD,
+ AFMULF,
+ AFMULX,
+ AFNEGD, /* pseudo op */
+ AFNEGF,
+ AFNEGX, /* pseudo op */
+ AFSQRTD,
+ AFSQRTF,
+ AFSQRTX,
+ AFSUBD,
+ AFSUBF,
+ AFSUBX,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AIFLUSH,
+ AJMPL,
+ AJMP,
+ AMOD,
+ AMODL,
+ AMOVB,
+ AMOVBU,
+ AMOVD,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMUL,
+ AMULSCC,
+ ANAME,
+ ANOP,
+ AOR,
+ AORCC,
+ AORN,
+ AORNCC,
+ ARESTORE,
+ ARETT,
+ ARETURN,
+ ASAVE,
+ ASLL,
+ ASRA,
+ ASRL,
+ ASUB,
+ ASUBCC,
+ ASUBX,
+ ASUBXCC,
+ ASWAP,
+ ATA,
+ ATADDCC,
+ ATADDCCTV,
+ ATAS,
+ ATCC,
+ ATCS,
+ ATE,
+ ATEXT,
+ ATG,
+ ATGE,
+ ATGU,
+ ATL,
+ ATLE,
+ ATLEU,
+ ATN,
+ ATNE,
+ ATNEG,
+ ATPOS,
+ ATSUBCC,
+ ATSUBCCTV,
+ ATVC,
+ ATVS,
+ AUNIMP,
+ AWORD,
+ AXNOR,
+ AXNORCC,
+ AXOR,
+ AXORCC,
+ AEND,
+ ADYNT,
+ AINIT,
+ ASIGNAME,
+ ALAST
+};
+
+/* type/name */
+enum
+{
+ D_GOK = 0,
+ D_NONE,
+
+/* name */
+ D_EXTERN,
+ D_STATIC,
+ D_AUTO,
+ D_PARAM,
+
+/* type */
+ D_BRANCH,
+ D_OREG,
+ D_ASI,
+ D_CONST,
+ D_FCONST,
+ D_SCONST,
+ D_REG,
+ D_FREG,
+ D_CREG,
+ D_PREG,
+ D_FILE,
+ D_FILE1,
+
+/* reg names iff type is D_PREG */
+ D_CPQ = 0,
+ D_CSR,
+ D_FPQ,
+ D_FSR,
+ D_PSR,
+ D_TBR,
+ D_WIM,
+ D_Y
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/kc/list.c b/utils/kc/list.c
new file mode 100644
index 00000000..3538c621
--- /dev/null
+++ b/utils/kc/list.c
@@ -0,0 +1,229 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('B', Bconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a <= AEND)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(F%d)(REG)", a, a->reg);
+ break;
+
+ case D_CREG:
+ sprint(str, "C%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(C%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/kc/mkenam b/utils/kc/mkenam
new file mode 100644
index 00000000..e0857f17
--- /dev/null
+++ b/utils/kc/mkenam
@@ -0,0 +1,17 @@
+ed - ../kc/k.out.h <<'!'
+v/^ A/d
+g/^ AEND/s//&,/
+g/[ ]*=.*,/s//,/
+v/,/p
+,s/^ A/ "/
+,s/,.*$/",/
+1i
+char *anames[] =
+{
+.
+,a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/kc/mkfile b/utils/kc/mkfile
new file mode 100644
index 00000000..26f16f10
--- /dev/null
+++ b/utils/kc/mkfile
@@ -0,0 +1,32 @@
+<../../mkconfig
+
+TARG=kc
+
+OFILES=\
+ peep.$O\
+ reg.$O\
+ cgen.$O\
+ enam.$O\
+ list.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ k.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/kc/mul.c b/utils/kc/mul.c
new file mode 100644
index 00000000..17e19be6
--- /dev/null
+++ b/utils/kc/mul.c
@@ -0,0 +1,609 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3 /* r0 has not been used */
+};
+
+Multab*
+mulcon0(Node *n, long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("%L: multiply table failure %ld\n", n->lineno, v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=6; g++) {
+ if(g >= 6 && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("%L: multiply table failure (g=%d h=%s) %ld\n",
+ n->lineno, g, hint, v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(n, v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/utils/kc/peep.c b/utils/kc/peep.c
new file mode 100644
index 00000000..da6c1449
--- /dev/null
+++ b/utils/kc/peep.c
@@ -0,0 +1,691 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVW || p->as == AFMOVF || p->as == AFMOVD)
+ if(regtyp(&p->to)) {
+ if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(regzer(&p->from))
+ if(p->to.type == D_REG) {
+ p->from.type = D_REG;
+ p->from.reg = 0;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+regzer(Adr *a)
+{
+
+ if(a->type == D_CONST)
+ if(a->sym == S)
+ if(a->offset == 0)
+ return 1;
+ if(a->type == D_REG)
+ if(a->reg == 0)
+ return 1;
+ return 0;
+}
+
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG) {
+ if(a->reg != 0)
+ return 1;
+ return 0;
+ }
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case AJMPL:
+ return 0;
+
+ case AADD:
+ case ASUB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+
+ case AFADDD:
+ case AFADDF:
+ case AFSUBD:
+ case AFSUBF:
+ case AFMULD:
+ case AFMULF:
+ case AFDIVD:
+ case AFDIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AFMOVF:
+ case AFMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+
+ case AFMOVF:
+ case AFMOVD:
+ case AFMOVDW:
+ case AFMOVWD:
+ case AFMOVFW:
+ case AFMOVWF:
+ case AFMOVFD:
+ case AFMOVDF:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case AADD: /* read read write */
+ case ASUB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+
+ case AFADDF:
+ case AFADDD:
+ case AFSUBF:
+ case AFSUBD:
+ case AFMULF:
+ case AFMULD:
+ case AFDIVF:
+ case AFDIVD:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABA: /* no reference */
+ case ABCC:
+ case ABCS:
+ case ABE:
+ case ABG:
+ case ABGE:
+ case ABGU:
+ case ABL:
+ case ABLE:
+ case ABLEU:
+ case ABN:
+ case ABNE:
+ case ABNEG:
+ case ABPOS:
+ case ABVC:
+ case ABVS:
+ case AFBA:
+ case AFBE:
+ case AFBG:
+ case AFBGE:
+ case AFBL:
+ case AFBLE:
+ case AFBNE:
+ case AFBN:
+ case AFBLG:
+ case AFBO:
+ case AFBU:
+ case AFBUE:
+ case AFBUG:
+ case AFBUGE:
+ case AFBUL:
+ case AFBULE:
+ break;
+
+ case ACMP: /* read read */
+ case AFCMPD:
+ case AFCMPF:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJMP: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARETURN: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case AJMPL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG) {
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+ }
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+ case AADD:
+ case ASUB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+ return D_REG;
+
+ case AFADDF:
+ case AFADDD:
+ case AFSUBF:
+ case AFSUBD:
+ case AFMULF:
+ case AFMULD:
+ case AFDIVF:
+ case AFDIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v))
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG)
+ if(a->type == D_OREG)
+ if(v->reg == a->reg)
+ return 1;
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v))
+ if(p->from.type == v->type || p->to.type == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v))
+ a->reg = s->reg;
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
diff --git a/utils/kc/reg.c b/utils/kc/reg.c
new file mode 100644
index 00000000..35c2e7db
--- /dev/null
+++ b/utils/kc/reg.c
@@ -0,0 +1,1121 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARETURN:
+ case AJMP:
+ case ARETT:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AFMOVF:
+ case AFMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case AJMPL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] | r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARETURN)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n set = %B; rah = %B; cal = %B\n",
+ r->prog, r->set, r->refahead, r->calahead);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set an not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L$%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L$%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L$%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AFMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AFMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case AJMPL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARETURN:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(p->to.type == D_FREG && p->as == AMOVW)
+ change = -CINF; /* cant go Rreg to Freg */
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(p->from.type == D_FREG && p->as == AMOVW)
+ change = -CINF; /* cant go Rreg to Freg */
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R9
+ * 1 R10
+ * ... ...
+ * 4 R13
+ * 5 R16
+ * ... ...
+ * 20 R31
+ */
+long
+RtoB(int r)
+{
+
+ if(r >= 9 && r <= 13)
+ return 1L << (r-9);
+ if(r >= 16 && r <= 31)
+ return 1L << (r-11);
+ return 0;
+}
+
+int
+BtoR(long b)
+{
+ int r;
+
+ b &= 0x001fffffL;
+ if(b == 0)
+ return 0;
+ r = bitno(b) + 9;
+ if(r >= 14)
+ r += 2;
+ return r;
+}
+
+/*
+ * bit reg
+ * 22 F4
+ * 23 F6
+ * ... ...
+ * 31 F22
+ */
+long
+FtoB(int f)
+{
+
+ if(f < 4 || f > 22 || (f&1))
+ return 0;
+ return 1L << (f/2 + 20);
+}
+
+BtoF(long b)
+{
+
+ b &= 0xffc00000L;
+ if(b == 0)
+ return 0;
+ return bitno(b)*2 - 40;
+}
diff --git a/utils/kc/sgen.c b/utils/kc/sgen.c
new file mode 100644
index 00000000..3836f2f3
--- /dev/null
+++ b/utils/kc/sgen.c
@@ -0,0 +1,590 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ }
+ }
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ sp->to.offset += maxargsafe;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ gbranch(OGOTO);
+ if(n->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ bcomplex(l);
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int v;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASASHL;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASHL;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ v = vlog(l);
+ if(v >= 0) {
+ n->op = OASHL;
+ n->left = r;
+ n->right = l;
+ r = l;
+ l = n->left;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASLSHR;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OLSHR;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
+
+void
+bcomplex(Node *n)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+}
diff --git a/utils/kc/swt.c b/utils/kc/swt.c
new file mode 100644
index 00000000..6b812c2f
--- /dev/null
+++ b/utils/kc/swt.c
@@ -0,0 +1,715 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+ Node tn;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ regalloc(&tn, &regnode, Z);
+ swit1(iq, nc, def, n, &tn);
+ regfree(&tn);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n, Node *tn)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(sval(q->val)) {
+ gopcode(OEQ, n, Z, nodconst(q->val));
+ } else {
+ gopcode(OSUB, nodconst(q->val), n, tn);
+ gopcode(OEQ, tn, Z, nodconst(0));
+ }
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(sval(r->val)) {
+ gopcode(OGT, n, Z, nodconst(r->val));
+ sp = p;
+ } else {
+ gopcode(OSUB, nodconst(r->val), n, tn);
+ gopcode(OGT, tn, Z, nodconst(0));
+ sp = p;
+ }
+ gbranch(OGOTO);
+ p->as = ABE;
+ patch(p, r->label);
+ swit1(q, i, def, n, tn);
+
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n, tn);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(n, v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ if(v < 0)
+ gopcode(OSUB, &nod1, nodconst(0), &nod1);
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ long l;
+
+ Bputc(b, p->as);
+ Bputc(b, p->reg);
+ l = p->lineno;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ zaddr(b, &p->from, sf);
+ zaddr(b, &p->to, st);
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else
+ Bputc(b, ANAME); /* as */
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(b, a->type);
+ Bputc(b, a->reg);
+ Bputc(b, s);
+ Bputc(b, a->name);
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_CREG:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ break;
+ }
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ o += SZ_LONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/utils/kc/txt.c b/utils/kc/txt.c
new file mode 100644
index 00000000..71f804ba
--- /dev/null
+++ b/utils/kc/txt.c
@@ -0,0 +1,1269 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = 'k';
+ thestring = "sparc";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = 0;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ memset(reg, 0, sizeof(reg));
+ reg[REGZERO] = 1;
+ reg[REGLINK] = 1;
+ reg[REGTMP] = 1;
+ for(i=NREG; i<NREG+NREG; i+=2)
+ reg[i+1] = 1;
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(i != REGZERO && i != REGTMP && i != REGLINK)
+ if(reg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NREG; i+=2)
+ if(reg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesuv[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gopcode(OAS, n, Z, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i > 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<NREG; i++) {
+ if(j >= NREG)
+ j = REGRET+1;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NREG)
+ goto out;
+ }
+ j = lasti*2 + NREG;
+ for(i=NREG; i<NREG+NREG; i+=2) {
+ if(j >= NREG+NREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j += 2;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ lasti++;
+ if(lasti >= 5)
+ lasti = 0;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_LONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod;
+ Prog *p1;
+ double d;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0.0) {
+ a = FREGZERO;
+ goto ffreg;
+ }
+ if(d == 0.5) {
+ a = FREGHALF;
+ goto ffreg;
+ }
+ if(d == 1.0) {
+ a = FREGONE;
+ goto ffreg;
+ }
+ if(d == 2.0) {
+ a = FREGTWO;
+ goto ffreg;
+ }
+ if(d == -.5) {
+ fop(OSUB, FREGHALF, FREGZERO, t);
+ return;
+ }
+ if(d == -1.0) {
+ fop(OSUB, FREGONE, FREGZERO, t);
+ return;
+ }
+ if(d == -2.0) {
+ fop(OSUB, FREGTWO, FREGZERO, t);
+ return;
+ }
+ if(d == 1.5) {
+ fop(OADD, FREGONE, FREGHALF, t);
+ return;
+ }
+ if(d == 2.5) {
+ fop(OADD, FREGTWO, FREGHALF, t);
+ return;
+ }
+ if(d == 3.0) {
+ fop(OADD, FREGTWO, FREGONE, t);
+ return;
+ }
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0) {
+ a = FREGZERO;
+ ffreg:
+ nodreg(&nod, f, NREG+a);
+ gmove(&nod, t);
+ return;
+ }
+ }
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ if(typefd[tt]) {
+ /* special case can load mem to Freg */
+ regalloc(&nod, t, t);
+ gins(AMOVW, f, &nod);
+ a = AFMOVWD;
+ if(tt == TFLOAT)
+ a = AFMOVWF;
+ gins(a, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVW;
+ break;
+ case TFLOAT:
+ a = AFMOVF;
+ break;
+ case TDOUBLE:
+ a = AFMOVD;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ }
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ if(typefd[ft]) {
+ /* special case can store mem from Freg */
+ regalloc(&nod, f, Z);
+ a = AFMOVDW;
+ if(ft == TFLOAT)
+ a = AFMOVFW;
+ gins(a, f, &nod);
+ gins(AMOVW, &nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AFMOVF;
+ break;
+ case TVLONG:
+ case TDOUBLE:
+ a = AFMOVD;
+ break;
+ }
+ if(!typefd[ft] && vconst(f) == 0) {
+ gins(a, f, t);
+ return;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ a = AFMOVD;
+ if(ft == TFLOAT)
+ a = AFMOVFD;
+ break;
+ case TFLOAT:
+ a = AFMOVDF;
+ if(ft == TFLOAT)
+ a = AFMOVF;
+ break;
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TINT:
+ case TUINT:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ regalloc(&nod, f, Z); /* should be type float */
+ a = AFMOVDW;
+ if(ft == TFLOAT)
+ a = AFMOVFW;
+ gins(a, f, &nod);
+ gins(AFMOVF, &nod, nodrat);
+ regfree(&nod);
+ gins(AMOVW, nodrat, t);
+ gmove(t, t);
+ if(nrathole < SZ_LONG)
+ nrathole = SZ_LONG;
+ return;
+ }
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ goto fxtofl;
+ case TLONG:
+ case TULONG:
+ case TINT:
+ case TUINT:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ goto fxtofl;
+ case TUINT:
+ case TINT:
+ case TULONG:
+ case TLONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ goto fxtofl;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ goto fxtofl;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ fxtofl:
+ regalloc(&nod, t, t); /* should be type float */
+ gins(AMOVW, f, nodrat);
+ gins(AFMOVF, nodrat, &nod);
+ a = AFMOVWD;
+ if(tt == TFLOAT)
+ a = AFMOVWF;
+ gins(a, &nod, t);
+ regfree(&nod);
+ if(nrathole < SZ_LONG)
+ nrathole = SZ_LONG;
+ if(ft == TULONG) {
+ regalloc(&nod, t, Z);
+ if(tt == TFLOAT) {
+ gins(AFCMPF, t, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGZERO;
+ gins(AFBGE, Z, Z);
+ p1 = p;
+ gins(AFMOVF, nodfconst(4294967296.), &nod);
+ gins(AFADDF, &nod, t);
+ } else {
+ gins(AFCMPD, t, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGZERO;
+ gins(AFBGE, Z, Z);
+ p1 = p;
+ gins(AFMOVD, nodfconst(4294967296.), &nod);
+ gins(AFADDD, &nod, t);
+ }
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AFMOVF || a == AFMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et;
+ Adr ta;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADD;
+ if(et == TFLOAT)
+ a = AFADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AFADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUB;
+ if(et == TFLOAT)
+ a = AFSUBF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AFSUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AOR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ break;
+
+ case OFUNC:
+ a = AJMPL;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT) {
+ a = AFMULF;
+ break;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFMULD;
+ break;
+ }
+ a = AMUL;
+ break;
+
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = AFDIVF;
+ break;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AFDIVD;
+ break;
+ }
+ a = ADIV;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ a = AMOD;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ a = AMODL;
+ break;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ break;
+
+ case OEQ:
+ a = ABE;
+ if(typefd[et])
+ a = AFBE;
+ goto cmp;
+
+ case ONE:
+ a = ABNE;
+ if(typefd[et])
+ a = AFBLG;
+ goto cmp;
+
+ case OLT:
+ a = ABL;
+ if(typefd[et])
+ a = AFBL;
+ goto cmp;
+
+ case OLE:
+ a = ABLE;
+ if(typefd[et])
+ a = AFBLE;
+ goto cmp;
+
+ case OGE:
+ a = ABGE;
+ if(typefd[et])
+ a = AFBGE;
+ goto cmp;
+
+ case OGT:
+ a = ABG;
+ if(typefd[et])
+ a = AFBG;
+ goto cmp;
+
+ case OLO:
+ a = ABCS;
+ goto cmp;
+
+ case OLS:
+ a = ABLEU;
+ goto cmp;
+
+ case OHS:
+ a = ABCC;
+ goto cmp;
+
+ case OHI:
+ a = ABGU;
+ goto cmp;
+
+ cmp:
+ nextpc();
+ p->as = ACMP;
+ if(et == TFLOAT)
+ p->as = AFCMPF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ p->as = AFCMPD;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(f1 == Z || t == Z || f2 != Z)
+ diag(Z, "bad cmp in gopcode %O", o);
+ if(debug['g'])
+ print("%P\n", p);
+ f1 = Z;
+ f2 = Z;
+ t = Z;
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0)
+ p->reg = REGZERO;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARETURN;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ if(a == ATEXT)
+ p->reg = (profileflg ? 0 : NOPROF);
+ p->from.name = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sval(long v)
+{
+
+ if(v >= -(1<<12) && v < (1<<12))
+ return 1;
+ return 0;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= -(vlong)(1<<12) && vv < (vlong)(1<<12))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= 3)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 16)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/kl/Nt.c b/utils/kl/Nt.c
new file mode 100644
index 00000000..6be99a36
--- /dev/null
+++ b/utils/kl/Nt.c
@@ -0,0 +1,88 @@
+#include <windows.h>
+
+/*
+ * We can't include l.h, because Windoze wants to use some names
+ * like FLOAT which we declare. Define what we need here.
+ */
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+extern char *hunk;
+extern long nhunk;
+
+void gethunk(void);
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/kl/Plan9.c b/utils/kl/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/kl/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/kl/Posix.c b/utils/kl/Posix.c
new file mode 100644
index 00000000..7c3a661f
--- /dev/null
+++ b/utils/kl/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fials if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
diff --git a/utils/kl/asm.c b/utils/kl/asm.c
new file mode 100644
index 00000000..dde73d6d
--- /dev/null
+++ b/utils/kl/asm.c
@@ -0,0 +1,1237 @@
+#include "l.h"
+
+#define LPUT(c)\
+ {\
+ cbp[0] = (c)>>24;\
+ cbp[1] = (c)>>16;\
+ cbp[2] = (c)>>8;\
+ cbp[3] = (c);\
+ cbp += 4;\
+ cbc -= 4;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define CPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp++;\
+ cbc--;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT && s->type != SLEAF)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long t;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asm\n", cputime());
+ Bflush(&bso);
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ }
+ if(p->pc != pc) {
+ diag("phase error %lux sb %lux",
+ p->pc, pc);
+ if(!debug['a'])
+ prasm(curp);
+ pc = p->pc;
+ }
+ curp = p;
+ o = oplook(p); /* could probably avoid this call */
+ if(asmout(p, o, 0)) {
+ p = p->link;
+ pc += 4;
+ }
+ pc += o->size;
+ }
+ if(debug['a'])
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ cflush();
+
+ curtext = P;
+ switch(HEADTYPE) {
+ case 0:
+ case 3:
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 1:
+ case 2:
+ seek(cout, HEADR+textsize, 0);
+ break;
+ }
+ for(t = 0; t < datsize; t += sizeof(buf)-100) {
+ if(datsize-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100);
+ else
+ datblk(t, datsize-t);
+ }
+
+ symsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ case 0:
+ case 3:
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 2:
+ case 1:
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ /* round up file length for boot image */
+ if(HEADTYPE == 0 || HEADTYPE == 3)
+ if((symsize+lcsize) & 1)
+ CPUT(0);
+ cflush();
+ }
+
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ case 0:
+ lput(0x1030107); /* magic and sections */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case 1:
+ break;
+ case 2:
+ lput(4*13*13+7); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case 3:
+ lput(0x1030107); /* magic and sections */
+ lput(0x90100000);
+#define SPARC_NOOP 0x01000000
+ lput(SPARC_NOOP);
+ lput(SPARC_NOOP);
+ lput(SPARC_NOOP);
+ lput(SPARC_NOOP);
+ lput(SPARC_NOOP);
+ lput(SPARC_NOOP);
+ break;
+ }
+ cflush();
+}
+
+void
+lput(long l)
+{
+
+ LPUT(l);
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->cond) {
+ s = p->from.sym;
+ if(s->type != STEXT && s->type != SLEAF)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+ else
+ putsymb(s->name, 'L', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+4, 0);
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+putsymb(char *s, int t, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ LPUT(v);
+ if(ver)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ CPUT(s[i]);
+ CPUT(s[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ CPUT(s[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, s);
+ }
+}
+
+#define MINLC 4
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j, d;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->reg;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ default:
+ diag("unknown mode in initialization\n%P", p);
+ break;
+
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (char*)&fl;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i+4]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.sval[i];
+ l++;
+ }
+ break;
+
+ case D_CONST:
+ d = p->to.offset;
+ if(p->to.sym) {
+ if(p->to.sym->type == STEXT ||
+ p->to.sym->type == SLEAF)
+ d += p->to.sym->value;
+ if(p->to.sym->type == SDATA)
+ d += p->to.sym->value + INITDAT;
+ if(p->to.sym->type == SBSS)
+ d += p->to.sym->value + INITDAT;
+ }
+ cast = (char*)&d;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+#define OP2(x) (0x80000000|((x)<<19))
+#define OP3(x) (0xc0000000|((x)<<19))
+#define OPB(x) (0x00800000|((x)<<25))
+#define OPT(x) (0x81d02000|((x)<<25))
+#define OPF1(x) (0x81a00000|((x)<<5))
+#define OPF2(x) (0x81a80000|((x)<<5))
+#define OPFB(x) (0x01800000|((x)<<25))
+
+#define OP_RRR(op,r1,r2,r3)\
+ (0x00000000 | op |\
+ (((r1)&31L)<<0) |\
+ (((r2)&31L)<<14) |\
+ (((r3)&31L)<<25))
+#define OP_IRR(op,i,r2,r3)\
+ (0x00002000L | (op) |\
+ (((i)&0x1fffL)<<0) |\
+ (((r2)&31L)<<14) |\
+ (((r3)&31L)<<25))
+#define OP_BRA(op,pc)\
+ ((op) |\
+ (((pc)&0x3fffff)<<0))
+
+int
+asmout(Prog *p, Optab *o, int aflag)
+{
+ long o1, o2, o3, o4, o5, v;
+ Prog *ct;
+ int r;
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+
+ switch(o->type) {
+ default:
+ if(aflag)
+ return 0;
+ diag("unknown type %d", o->type);
+ if(!debug['a'])
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ if(aflag) {
+ if(p->link) {
+ if(p->as == ATEXT) {
+ ct = curtext;
+ o2 = autosize;
+ curtext = p;
+ autosize = p->to.offset + 4;
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ curtext = ct;
+ autosize = o2;
+ } else
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ }
+ return o1;
+ }
+ break;
+
+ case 1: /* mov r1,r2 ==> OR r1,r0,r2 */
+ o1 = OP_RRR(opcode(AOR), p->from.reg, REGZERO, p->to.reg);
+ break;
+
+ case 2: /* mov $c,r ==> add r1,r0,r2 */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = OP_IRR(opcode(AADD), v, r, p->to.reg);
+ break;
+
+ case 3: /* mov soreg, r */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ if(v == 0 && p->reg != NREG)
+ o1 = OP_RRR(opcode(p->as), p->reg, r, p->to.reg);
+ else
+ o1 = OP_IRR(opcode(p->as), v, r, p->to.reg);
+ break;
+
+ case 4: /* mov r, soreg */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ if(v == 0 && p->reg != NREG)
+ o1 = OP_RRR(opcode(p->as+AEND), p->reg, r, p->from.reg);
+ else
+ o1 = OP_IRR(opcode(p->as+AEND), v, r, p->from.reg);
+ break;
+
+ case 5: /* mov $lcon, reg => sethi, add */
+ v = regoff(&p->from);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, p->to.reg);
+ break;
+
+ case 6: /* mov asi, r[+r] */
+ o1 = OP_RRR(opcode(p->as), p->reg, p->from.reg, p->to.reg);
+ o1 |= (1<<23) | ((p->from.offset&0xff)<<5);
+ break;
+
+ case 7: /* mov [+r]r, asi */
+ o1 = OP_RRR(opcode(p->as+AEND), p->reg, p->to.reg, p->from.reg);
+ o1 |= (1<<23) | ((p->to.offset&0xff)<<5);
+ break;
+
+ case 8: /* mov r, preg and mov preg, r */
+ if(p->to.type == D_PREG) {
+ r = p->from.reg;
+ switch(p->to.reg)
+ {
+ default:
+ diag("unknown register P%d", p->to.reg);
+ case D_Y:
+ o1 = OP2(48); /* wry */
+ break;
+ case D_PSR:
+ o1 = OP2(49); /* wrpsr */
+ break;
+ case D_WIM:
+ o1 = OP2(50); /* wrwim */
+ break;
+ case D_TBR:
+ o1 = OP2(51); /* wrtbr */
+ break;
+ }
+ o1 = OP_IRR(o1, 0, r, 0);
+ break;
+ }
+ if(p->from.type == D_PREG) {
+ r = p->to.reg;
+ switch(p->from.reg)
+ {
+ default:
+ diag("unknown register P%d", p->to.reg);
+ case D_Y:
+ o1 = OP2(40); /* rdy */
+ break;
+ case D_PSR:
+ o1 = OP2(41); /* rdpsr */
+ break;
+ case D_WIM:
+ o1 = OP2(42); /* rdwim */
+ break;
+ case D_TBR:
+ o1 = OP2(43); /* rdtbr */
+ break;
+ }
+ o1 = OP_RRR(o1, 0, 0, r);
+ break;
+ }
+ break;
+
+ case 9: /* movb r,r */
+ v = 24;
+ if(p->as == AMOVH || p->as == AMOVHU)
+ v = 16;
+ r = ASRA;
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ r = ASRL;
+ o1 = OP_IRR(opcode(ASLL), v, p->from.reg, p->to.reg);
+ o2 = OP_IRR(opcode(r), v, p->to.reg, p->to.reg);
+ break;
+
+ case 10: /* mov $loreg, reg */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, p->to.reg);
+ break;
+
+ case 11: /* mov loreg, r */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(opcode(p->as), (v&0x3ff), REGTMP, p->to.reg);
+ break;
+
+ case 12: /* mov r, loreg */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(opcode(p->as+AEND), (v&0x3ff), REGTMP, p->from.reg);
+ break;
+
+ case 13: /* mov $ucon, r */
+ v = regoff(&p->from);
+ o1 = 0x1000000 | (p->to.reg<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ break;
+
+ case 20: /* op $scon,r */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(opcode(p->as), v, r, p->to.reg);
+ break;
+
+ case 21: /* op r1,r2 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(opcode(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 22: /* op $lcon,r */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, REGTMP);
+ o3 = OP_RRR(opcode(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 23: /* cmp r,r */
+ o1 = OP_RRR(opcode(ASUBCC), p->to.reg, p->from.reg, REGZERO);
+ break;
+
+ case 24: /* cmp r,$c */
+ v = regoff(&p->to);
+ o1 = OP_IRR(opcode(ASUBCC), v, p->from.reg, REGZERO);
+ break;
+
+ case 25: /* cmp $c,r BOTCH, fix compiler */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opcode(AADD), v, NREG, REGTMP);
+ o2 = OP_RRR(opcode(ASUBCC), p->to.reg, REGTMP, REGZERO);
+ break;
+
+ case 26: /* op $ucon,r */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 30: /* jmp/jmpl soreg */
+ if(aflag)
+ return 0;
+ v = regoff(&p->to);
+ r = p->reg;
+ if(r == NREG && p->as == AJMPL)
+ r = 15;
+ o1 = OP_IRR(opcode(AJMPL), v, p->to.reg, r);
+ break;
+
+ case 31: /* ba jmp */
+ if(aflag)
+ return 0;
+ r = p->as;
+ if(r == AJMP)
+ r = ABA;
+ v = 0;
+ if(p->cond)
+ v = p->cond->pc - p->pc;
+ o1 = OP_BRA(opcode(r), v/4);
+ if(r == ABA && p->link && p->cond && isnop(p->link)) {
+ o2 = asmout(p->cond, oplook(p->cond), 1);
+ if(o2) {
+ o1 += 1;
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ return 1;
+ }
+ /* cant set annul here because pc has already been counted */
+ }
+ break;
+
+ case 32: /* jmpl lbra */
+ if(aflag)
+ return 0;
+ v = 0;
+ if(p->cond)
+ v = p->cond->pc - p->pc;
+ r = p->reg;
+ if(r != NREG && r != 15)
+ diag("cant jmpl other than R15");
+ o1 = 0x40000000 | ((v/4) & 0x3fffffffL); /* call */
+ if(p->link && p->cond && isnop(p->link)) {
+ o2 = asmout(p->cond, oplook(p->cond), 1);
+ if(o2) {
+ o1 += 1;
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ return 1;
+ }
+ }
+ break;
+
+ case 33: /* trap r */
+ if(aflag)
+ return 0;
+ o1 = opcode(p->as) | (p->from.reg<<14);
+ break;
+
+ case 34: /* rett r1,r2 -> jmpl (r1); rett (r2) */
+ if(aflag)
+ return 0;
+ o1 = OP_IRR(opcode(AJMPL), 0, p->from.reg, REGZERO);
+ o2 = OP_IRR(opcode(ARETT), 0, p->to.reg, REGZERO);
+ break;
+
+ case 40: /* ldfsr, stfsr, stdq */
+ if(p->to.type == D_PREG) {
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ if(p->to.reg == D_FSR) {
+ o1 = OP_IRR(OP3(33), v, r, 0);
+ break;
+ }
+ diag("unknown reg load %d", p->to.reg);
+ } else {
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ if(p->from.reg == D_FSR) {
+ o1 = OP_IRR(OP3(37), v, r, 0);
+ break;
+ }
+ if(p->as == AMOVD && p->from.reg == D_FPQ) {
+ o1 = OP_IRR(OP3(38), v, r, 0);
+ break;
+ }
+ diag("unknown reg store %d", p->from.reg);
+ }
+ break;
+
+ case 41: /* ldf,ldd */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ if(p->as == AFMOVF || p->as == AMOVW) {
+ o1 = OP_IRR(OP3(32), v, r, p->to.reg);
+ break;
+ }
+ if(p->as == AMOVD || p->as == AFMOVD) {
+ o1 = OP_IRR(OP3(35), v, r, p->to.reg);
+ break;
+ }
+ diag("only MOVD and MOVW to FREG");
+ break;
+
+ case 42: /* ldd -> ldf,ldf */
+ /* note should be ldd with proper allignment */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = OP_IRR(OP3(32), v, r, p->to.reg);
+ o2 = OP_IRR(OP3(32), v+4, r, p->to.reg+1);
+ break;
+
+ case 43: /* stf */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ if(p->as == AFMOVF || p->as == AMOVW) {
+ o1 = OP_IRR(OP3(36), v, r, p->from.reg);
+ break;
+ }
+ if(p->as == AMOVD || p->as == AFMOVD) {
+ o1 = OP_IRR(OP3(39), v, r, p->from.reg);
+ break;
+ }
+ diag("only MOVD and MOVW from FREG");
+ break;
+
+ case 44: /* std -> stf,stf */
+ /* note should be std with proper allignment */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = OP_IRR(OP3(36), v, r, p->from.reg);
+ o2 = OP_IRR(OP3(36), v+4, r, p->from.reg+1);
+ break;
+
+ case 45: /* ldf lorg */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(OP3(32), v&0x3ff, REGTMP, p->to.reg);
+ break;
+
+ case 46: /* ldd lorg -> ldf,ldf */
+ /* note should be ldd with proper allignment */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(OP3(32), (v&0x3ff), REGTMP, p->to.reg);
+ o4 = OP_IRR(OP3(32), (v&0x3ff)+4, REGTMP, p->to.reg+1);
+ break;
+
+ case 47: /* stf lorg */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(OP3(36), v&0x3ff, REGTMP, p->from.reg);
+ break;
+
+ case 48: /* std lorg -> stf,stf */
+ /* note should be std with proper allignment */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */
+ o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP);
+ o3 = OP_IRR(OP3(36), (v&0x3ff), REGTMP, p->from.reg);
+ o4 = OP_IRR(OP3(36), (v&0x3ff)+4, REGTMP, p->from.reg+1);
+ break;
+
+ case 49: /* fmovd -> fmovf,fmovf */
+ o1 = OP_RRR(opcode(AFMOVF), p->from.reg, 0, p->to.reg);
+ o2 = OP_RRR(opcode(AFMOVF), p->from.reg+1, 0, p->to.reg+1);
+ break;
+
+ case 50: /* fcmp */
+ o1 = OP_RRR(opcode(p->as), p->to.reg, p->from.reg, 0);
+ break;
+
+ case 51: /* word */
+ if(aflag)
+ return 0;
+ o1 = regoff(&p->from);
+ break;
+
+ case 52: /* div */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(opcode(ASRA), 31, r, REGTMP);
+ o2 = OP_IRR(OP2(48), 0, REGTMP, 0);
+ o3 = OP_RRR(opcode(ADIV), p->from.reg, r, p->to.reg);
+ break;
+
+ case 53: /* divl */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(OP2(48), 0, REGZERO, 0);
+ o2 = OP_RRR(opcode(ADIVL), p->from.reg, r, p->to.reg);
+ break;
+
+ case 54: /* mod */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(opcode(ASRA), 31, r, REGTMP);
+ o2 = OP_IRR(OP2(48), 0, REGTMP, 0);
+ o3 = OP_RRR(opcode(ADIV), p->from.reg, r, REGTMP);
+ o4 = OP_RRR(opcode(AMUL), p->from.reg, REGTMP, REGTMP);
+ o5 = OP_RRR(opcode(ASUB), REGTMP, r, p->to.reg);
+ break;
+
+ case 55: /* modl */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(OP2(48), 0, REGZERO, 0);
+ o2 = OP_RRR(opcode(ADIVL), p->from.reg, r, REGTMP);
+ o3 = OP_RRR(opcode(AMUL), p->from.reg, REGTMP, REGTMP);
+ o4 = OP_RRR(opcode(ASUB), REGTMP, r, p->to.reg);
+ break;
+
+ case 56: /* b(cc) -- annullable */
+ if(aflag)
+ return 0;
+ r = p->as;
+ v = 0;
+ if(p->cond)
+ v = p->cond->pc - p->pc;
+ o1 = OP_BRA(opcode(r), v/4);
+ if(p->link && p->cond && isnop(p->link))
+ if(!debug['A']) {
+ o2 = asmout(p->cond, oplook(p->cond), 2);
+ if(o2) {
+ o1 |= 1<<29; /* annul */
+ o1 += 1;
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ return 1;
+ }
+ }
+ break;
+ }
+ if(aflag)
+ return o1;
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ LPUT(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ LPUT(o5);
+ break;
+ }
+ return 0;
+}
+
+int
+isnop(Prog *p)
+{
+ if(p->as != AORN)
+ return 0;
+ if(p->reg != REGZERO && p->reg != NREG)
+ return 0;
+ if(p->from.type != D_REG || p->from.reg != REGZERO)
+ return 0;
+ if(p->to.type != D_REG || p->to.reg != REGZERO)
+ return 0;
+ return 1;
+}
+
+long
+opcode(int a)
+{
+ switch(a) {
+ case AADD: return OP2(0);
+ case AADDCC: return OP2(16);
+ case AADDX: return OP2(8);
+ case AADDXCC: return OP2(24);
+
+ case AMUL: return OP2(10);
+ case ADIV: return OP2(15);
+ case ADIVL: return OP2(14);
+
+ case ATADDCC: return OP2(32);
+ case ATADDCCTV: return OP2(34);
+
+ case ASUB: return OP2(4);
+ case ASUBCC: return OP2(20);
+ case ASUBX: return OP2(12);
+ case ASUBXCC: return OP2(28);
+
+ case ATSUBCC: return OP2(33);
+ case ATSUBCCTV: return OP2(35);
+
+ case AMULSCC: return OP2(36);
+ case ASAVE: return OP2(60);
+ case ARESTORE: return OP2(61);
+
+ case AAND: return OP2(1);
+ case AANDCC: return OP2(17);
+ case AANDN: return OP2(5);
+ case AANDNCC: return OP2(21);
+
+ case AOR: return OP2(2);
+ case AORCC: return OP2(18);
+ case AORN: return OP2(6);
+ case AORNCC: return OP2(22);
+
+ case AXOR: return OP2(3);
+ case AXORCC: return OP2(19);
+ case AXNOR: return OP2(7);
+ case AXNORCC: return OP2(23);
+
+ case ASLL: return OP2(37);
+ case ASRL: return OP2(38);
+ case ASRA: return OP2(39);
+
+ case AJMPL:
+ case AJMP: return OP2(56);
+ case ARETT: return OP2(57);
+
+ case AMOVBU: return OP3(1); /* ldub */
+ case AMOVB: return OP3(9); /* ldsb */
+ case AMOVHU: return OP3(2); /* lduh */
+ case AMOVH: return OP3(10); /* ldsh */
+ case AMOVW: return OP3(0); /* ld */
+ case AMOVD: return OP3(3); /* ldd */
+
+ case AMOVBU+AEND:
+ case AMOVB+AEND:return OP3(5); /* stb */
+
+ case AMOVHU+AEND:
+ case AMOVH+AEND:return OP3(6); /* sth */
+
+ case AMOVW+AEND:return OP3(4); /* st */
+
+ case AMOVD+AEND:return OP3(7); /* std */
+
+ case ASWAP: /* swap is symmetric */
+ case ASWAP+AEND:return OP3(15);
+
+ case ATAS: return OP3(13); /* tas is really ldstub */
+
+ case ABN: return OPB(0);
+ case ABE: return OPB(1);
+ case ABLE: return OPB(2);
+ case ABL: return OPB(3);
+ case ABLEU: return OPB(4);
+ case ABCS: return OPB(5);
+ case ABNEG: return OPB(6);
+ case ABVS: return OPB(7);
+ case ABA: return OPB(8);
+ case ABNE: return OPB(9);
+ case ABG: return OPB(10);
+ case ABGE: return OPB(11);
+ case ABGU: return OPB(12);
+ case ABCC: return OPB(13);
+ case ABPOS: return OPB(14);
+ case ABVC: return OPB(15);
+
+ case AFBA: return OPFB(8);
+ case AFBE: return OPFB(9);
+ case AFBG: return OPFB(6);
+ case AFBGE: return OPFB(11);
+ case AFBL: return OPFB(4);
+ case AFBLE: return OPFB(13);
+ case AFBLG: return OPFB(2);
+ case AFBN: return OPFB(0);
+ case AFBNE: return OPFB(1);
+ case AFBO: return OPFB(15);
+ case AFBU: return OPFB(7);
+ case AFBUE: return OPFB(10);
+ case AFBUG: return OPFB(5);
+ case AFBUGE: return OPFB(12);
+ case AFBUL: return OPFB(3);
+ case AFBULE: return OPFB(14);
+
+ case ATN: return OPT(0);
+ case ATE: return OPT(1);
+ case ATLE: return OPT(2);
+ case ATL: return OPT(3);
+ case ATLEU: return OPT(4);
+ case ATCS: return OPT(5);
+ case ATNEG: return OPT(6);
+ case ATVS: return OPT(7);
+ case ATA: return OPT(8);
+ case ATNE: return OPT(9);
+ case ATG: return OPT(10);
+ case ATGE: return OPT(11);
+ case ATGU: return OPT(12);
+ case ATCC: return OPT(13);
+ case ATPOS: return OPT(14);
+ case ATVC: return OPT(15);
+
+ case AFADDF: return OPF1(65);
+ case AFADDD: return OPF1(66);
+ case AFADDX: return OPF1(67);
+ case AFSUBF: return OPF1(69);
+ case AFSUBD: return OPF1(70);
+ case AFSUBX: return OPF1(71);
+ case AFMULF: return OPF1(73);
+ case AFMULD: return OPF1(74);
+ case AFMULX: return OPF1(75);
+ case AFDIVF: return OPF1(77);
+ case AFDIVD: return OPF1(78);
+ case AFDIVX: return OPF1(79);
+
+ case AFMOVF: return OPF1(1);
+ case AFNEGF: return OPF1(5);
+ case AFABSF: return OPF1(9);
+
+ case AFSQRTF: return OPF1(41);
+ case AFSQRTD: return OPF1(42);
+ case AFSQRTX: return OPF1(43);
+
+ case AFMOVWF: return OPF1(196);
+ case AFMOVWD: return OPF1(200);
+ case AFMOVWX: return OPF1(204);
+ case AFMOVFW: return OPF1(209);
+ case AFMOVDW: return OPF1(210);
+ case AFMOVXW: return OPF1(211);
+ case AFMOVFD: return OPF1(201);
+ case AFMOVFX: return OPF1(205);
+ case AFMOVDF: return OPF1(198);
+ case AFMOVDX: return OPF1(206);
+ case AFMOVXF: return OPF1(199);
+ case AFMOVXD: return OPF1(203);
+
+ case AFCMPF: return OPF2(81);
+ case AFCMPD: return OPF2(82);
+ case AFCMPX: return OPF2(83);
+ case AFCMPEF: return OPF2(85);
+ case AFCMPED: return OPF2(86);
+ case AFCMPEX: return OPF2(87);
+
+ case AUNIMP: return 0;
+ }
+ diag("bad opcode %A", a);
+ return 0;
+}
diff --git a/utils/kl/foo.c b/utils/kl/foo.c
new file mode 100644
index 00000000..5c8fa36b
--- /dev/null
+++ b/utils/kl/foo.c
@@ -0,0 +1,15 @@
+int foo(void)
+{
+ return 100;
+}
+
+main()
+{
+ int x;
+
+ x = foo();
+}
+
+_main()
+{
+}
diff --git a/utils/kl/l.h b/utils/kl/l.h
new file mode 100644
index 00000000..21ca6294
--- /dev/null
+++ b/utils/kl/l.h
@@ -0,0 +1,322 @@
+/* #include <u.h> */
+#include <lib9.h>
+#include <bio.h>
+#include "../kc/k.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Adr Adr;
+typedef struct Sym Sym;
+typedef struct Autom Auto;
+typedef struct Prog Prog;
+typedef struct Optab Optab;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ long u0offset;
+ char u0sval[NSNAME];
+ Ieee u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ char type;
+ char reg;
+ char name;
+ char class;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog *forwd;
+ Prog *cond;
+ Prog *link;
+ long pc;
+ long regused;
+ short line;
+ short mark;
+ uchar optab;
+ uchar as;
+ char reg;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ long value;
+ Sym *link;
+};
+struct Autom
+{
+ Sym *asym;
+ Auto *link;
+ long aoffset;
+ short type;
+};
+struct Optab
+{
+ uchar as;
+ char a1;
+ char a2;
+ char a3;
+ char type;
+ char size;
+ char param;
+};
+EXTERN struct
+{
+ Optab* start;
+ Optab* stop;
+} oprange[AEND];
+
+enum
+{
+ AXLD = AEND+1,
+ AXST,
+ FPCHIP = 1,
+ BIG = 4096-8,
+ STRINGSZ = 200,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ DATBLK = 1024,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ NSCHED = 20,
+
+/* mark flags */
+ LABEL = 1<<0,
+ LEAF = 1<<1,
+ FLOAT = 1<<2,
+ BRANCH = 1<<3,
+ LOAD = 1<<4,
+ FCMP = 1<<5,
+ SYNC = 1<<6,
+ LIST = 1<<7,
+ FOLL = 1<<8,
+ NOSCHED = 1<<9,
+
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SLEAF,
+ SFILE,
+ SCONST,
+
+ C_NONE = 0,
+
+ C_REG,
+ C_FREG,
+ C_CREG,
+ C_PREG,
+ C_FSR,
+ C_FQ,
+
+ C_ZCON, /* 0 */
+ C_SCON, /* 13 bit signed */
+ C_UCON, /* low 10 bits 0 */
+ C_LCON, /* other */
+
+ C_SACON,
+ C_SECON,
+ C_LACON,
+ C_LECON,
+
+ C_SBRA,
+ C_LBRA,
+
+ C_ESAUTO,
+ C_OSAUTO,
+ C_SAUTO,
+ C_OLAUTO,
+ C_ELAUTO,
+ C_LAUTO,
+
+ C_ESEXT,
+ C_OSEXT,
+ C_SEXT,
+ C_ELEXT,
+ C_OLEXT,
+ C_LEXT,
+
+ C_ZOREG,
+ C_SOREG,
+ C_LOREG,
+ C_ASI,
+
+ C_ANY,
+
+ C_GOK,
+
+ C_NCLASS
+};
+
+EXTERN union
+{
+ struct
+ {
+ uchar obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+EXTERN long HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN long INITDAT; /* data location */
+EXTERN long INITRND; /* data round above text location */
+EXTERN long INITTEXT; /* text location */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN long autosize;
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN uchar* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN Prog* prog_mul;
+EXTERN Prog* prog_div;
+EXTERN Prog* prog_divl;
+EXTERN Prog* prog_mod;
+EXTERN Prog* prog_modl;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* firstp;
+EXTERN char fnuxi8[8];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN char* noname;
+EXTERN long instoffset;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN long symsize;
+EXTERN long staticgen;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long tothunk;
+EXTERN char xcmp[C_NCLASS][C_NCLASS];
+EXTERN int version;
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+extern Optab optab[];
+extern char* anames[];
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Nconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int aclass(Adr*);
+void addhist(long, int);
+void histtoauto(void);
+void addnop(Prog*);
+void append(Prog*, Prog*);
+void asmb(void);
+void asmlc(void);
+int asmout(Prog*, Optab*, int);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void cflush(void);
+int cmp(int, int);
+int compound(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+long entryvalue(void);
+void errorexit(void);
+void exchange(Prog*);
+int find1(long, int);
+void follow(void);
+void gethunk(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+int isnop(Prog*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+void initmuldiv(void);
+Sym* lookup(char*, int);
+void lput(long);
+void mkfwd(void);
+void* mysbrk(ulong);
+void names(void);
+void nocache(Prog*);
+void noops(void);
+void nuxiinit(void);
+void objfile(char*);
+int ocmp(const void*, const void*);
+long opcode(int);
+Optab* oplook(Prog*);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+void putsymb(char*, int, long, int);
+long regoff(Adr*);
+int relinv(int);
+long rnd(long, long);
+void sched(Prog*, Prog*);
+void span(void);
+void undef(void);
+void xdefine(char*, int, long);
+void xfol(Prog*);
diff --git a/utils/kl/list.c b/utils/kl/list.c
new file mode 100644
index 00000000..00fcb7ee
--- /dev/null
+++ b/utils/kl/list.c
@@ -0,0 +1,258 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ if(a == ADATA || a == AINIT || a == ADYNT)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else{
+ s = str;
+ if(p->mark & NOSCHED)
+ s += sprint(s, "*");
+ if(p->reg == NREG)
+ sprint(s, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type == D_OREG) {
+ sprint(s, " %A %ld(R%d+R%d),%D", a,
+ p->from.offset, p->from.reg, p->reg, &p->to);
+ } else
+ if(p->to.type == D_OREG) {
+ sprint(s, " %A %D,%ld(R%d+R%d)", a,
+ &p->from, p->to.offset, p->to.reg, p->reg);
+ } else
+ if(p->from.type == D_FREG)
+ sprint(s, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(s, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a <= ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ long v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_ASI:
+ if(a->reg != NREG)
+ sprint(str, "(R%d,%ld)", a->reg, a->offset);
+ else
+ sprint(str, "(R%d,%ld)", 0, a->offset);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(F%d)(REG)", a, a->reg);
+ break;
+
+ case D_CREG:
+ sprint(str, "C%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(C%d)(REG)", a, a->reg);
+ break;
+
+ case D_PREG:
+ sprint(str, "P%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(P%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH:
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(v >= INITTEXT)
+ v -= INITTEXT-HEADR;
+ if(a->sym != S)
+ sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5lux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%ld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(long); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/kl/mkfile b/utils/kl/mkfile
new file mode 100644
index 00000000..cf406d8f
--- /dev/null
+++ b/utils/kl/mkfile
@@ -0,0 +1,31 @@
+<../../mkconfig
+
+CFLAGS=$CFLAGS -I../include
+
+TARG=kl
+
+OFILES=\
+ asm.$O\
+ list.$O\
+ noop.$O\
+ sched.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../kc/k.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+enam.$O: ../kc/enam.c
+ $CC $CFLAGS ../kc/enam.c
diff --git a/utils/kl/noop.c b/utils/kl/noop.c
new file mode 100644
index 00000000..23d157f2
--- /dev/null
+++ b/utils/kl/noop.c
@@ -0,0 +1,650 @@
+#include "l.h"
+
+void
+noops(void)
+{
+ Prog *p, *p1, *q, *q1;
+ int o, curframe, curbecome, maxbecome;
+
+ /*
+ * find leaf subroutines
+ * become sizes
+ * frame sizes
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+ q = P;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == D_OREG && p->to.reg == REGSP)
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ /* too hard, just leave alone */
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ q = p;
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ curtext = p;
+ break;
+
+ case AORN:
+ q = p;
+ if(p->to.type == D_REG)
+ if(p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case AUNIMP:
+ case ATAS:
+ case ASWAP:
+ case ATA:
+ case ATCC:
+ case ATCS:
+ case ATE:
+ case ATG:
+ case ATGE:
+ case ATGU:
+ case ATL:
+ case ATLE:
+ case ATLEU:
+ case ATN:
+ case ATNE:
+ case ATNEG:
+ case ATPOS:
+ case ATVC:
+ case ATVS:
+ case AWORD:
+ q = p;
+ p->mark |= LABEL|SYNC;
+ continue;
+
+ case AFABSD:
+ case AFABSF:
+ case AFABSX:
+ case AFADDD:
+ case AFADDF:
+ case AFADDX:
+ case AFDIVD:
+ case AFDIVF:
+ case AFDIVX:
+ case AFMOVD:
+ case AFMOVDF:
+ case AFMOVDW:
+ case AFMOVDX:
+ case AFMOVF:
+ case AFMOVFD:
+ case AFMOVFW:
+ case AFMOVFX:
+ case AFMOVWD:
+ case AFMOVWF:
+ case AFMOVWX:
+ case AFMOVX:
+ case AFMOVXD:
+ case AFMOVXF:
+ case AFMOVXW:
+ case AFMULD:
+ case AFMULF:
+ case AFMULX:
+ case AFNEGD:
+ case AFNEGF:
+ case AFNEGX:
+ case AFSQRTD:
+ case AFSQRTF:
+ case AFSQRTX:
+ case AFSUBD:
+ case AFSUBF:
+ case AFSUBX:
+ q = p;
+ p->mark |= FLOAT;
+ continue;
+
+ case AMUL:
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+ q = p;
+ if(!debug['M']) {
+ if(prog_mul == P)
+ initmuldiv();
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+ }
+ continue;
+
+ case AJMPL:
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+
+ case AJMP:
+
+ case ABA:
+ case ABN:
+ case ABE:
+ case ABNE:
+ case ABLE:
+ case ABG:
+ case ABL:
+ case ABGE:
+ case ABLEU:
+ case ABGU:
+ case ABCS:
+ case ABCC:
+ case ABNEG:
+ case ABPOS:
+ case ABVC:
+ case ABVS:
+
+ case AFBN:
+ case AFBO:
+ case AFBE:
+ case AFBLG:
+ case AFBG:
+ case AFBLE:
+ case AFBGE:
+ case AFBL:
+ case AFBNE:
+ case AFBUE:
+ case AFBA:
+ case AFBU:
+ case AFBUG:
+ case AFBULE:
+ case AFBUGE:
+ case AFBUL:
+ p->mark |= BRANCH;
+ q = p;
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != P)
+ q1->mark |= LABEL;
+ continue;
+
+ case AFCMPD:
+ case AFCMPED:
+ case AFCMPEF:
+ case AFCMPEX:
+ case AFCMPF:
+ case AFCMPX:
+ q = p;
+ p->mark |= FCMP|FLOAT;
+ continue;
+
+ case ARETURN:
+ /* special form of RETURN is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+
+ q = p;
+ if(p->link != P)
+ p->link->mark |= LABEL;
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ default:
+ q = p;
+ continue;
+ }
+ }
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+
+ case AJMPL:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ o = maxbecome - curtext->from.sym->frame;
+ if(o <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += o;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, o);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ curtext = P;
+ for(p = firstp; p != P; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if((p->mark & LEAF) && autosize <= 4)
+ autosize = 0;
+ else
+ if(autosize & 4)
+ autosize += 4;
+ p->to.offset = autosize - 4;
+
+ q = p;
+ if(autosize) {
+ q = prg();
+ q->as = ASUB;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ } else
+ if(!(curtext->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ curtext->from.sym->name);
+ curtext->mark |= LEAF;
+ }
+
+ if(curtext->mark & LEAF) {
+ if(curtext->from.sym)
+ curtext->from.sym->type = SLEAF;
+ break;
+ }
+
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGLINK;
+ q1->to.type = D_OREG;
+ q1->from.offset = 0;
+ q1->to.reg = REGSP;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case AMUL:
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+ if(debug['M'])
+ break;
+ if(p->from.type != D_REG)
+ break;
+ if(p->to.type != D_REG)
+ break;
+ q1 = p;
+
+ /* MOV a,4(SP) */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AMOVW;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->from.reg;
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+
+ /* MOV b,REGTMP */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AMOVW;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->reg;
+ if(q1->reg == NREG)
+ p->from.reg = q1->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AJMPL;
+ p->line = q1->line;
+ p->to.type = D_BRANCH;
+ p->cond = p;
+ p->mark |= BRANCH;
+ switch(o) {
+ case AMUL:
+ p->cond = prog_mul;
+ break;
+ case ADIV:
+ p->cond = prog_div;
+ break;
+ case ADIVL:
+ p->cond = prog_divl;
+ break;
+ case AMOD:
+ p->cond = prog_mod;
+ break;
+ case AMODL:
+ p->cond = prog_modl;
+ break;
+ }
+
+ /* MOV REGTMP, b */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AMOVW;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = q1->to.reg;
+
+ /* ADD $8,SP */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.reg = NREG;
+ p->from.offset = 8;
+ p->reg = NREG;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ /* SUB $8,SP */
+ q1->as = ASUB;
+ q1->from.type = D_CONST;
+ q1->from.offset = 8;
+ q1->from.reg = NREG;
+ q1->reg = NREG;
+ q1->to.type = D_REG;
+ q1->to.reg = REGSP;
+ break;
+
+ case ARETURN:
+ if(p->from.type == D_CONST)
+ goto become;
+ if(curtext->mark & LEAF) {
+ if(!autosize) {
+ p->as = AJMP;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 8;
+ p->to.reg = REGLINK;
+ p->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_OREG;
+ q->to.offset = 8;
+ q->to.reg = REGLINK;
+ q->mark |= BRANCH;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGRET+1;
+
+ q = p;
+ if(autosize) {
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = prg();
+ q1->as = AJMP;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 8;
+ q1->to.reg = REGRET+1;
+ q1->mark |= BRANCH;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ become:
+ if(curtext->mark & LEAF) {
+
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ p->as = AADD;
+ p->from = zprg.from;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ break;
+ }
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->mark |= BRANCH;
+ q->link = p->link;
+ p->link = q;
+
+ q = prg();
+ q->line = p->line;
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+
+ p->as = AMOVW;
+ p->from = zprg.from;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGLINK;
+
+ break;
+ }
+ }
+
+ curtext = P;
+ q = P; /* p - 1 */
+ q1 = firstp; /* top of block */
+ o = 0; /* count of instructions */
+ for(p = firstp; p != P; p = p1) {
+ p1 = p->link;
+ o++;
+ if(p->mark & NOSCHED){
+ if(q1 != p){
+ sched(q1, q);
+ }
+ for(; p != P; p = p->link){
+ if(!(p->mark & NOSCHED))
+ break;
+ q = p;
+ }
+ p1 = p;
+ q1 = p;
+ o = 0;
+ continue;
+ }
+ if(p->mark & (LABEL|SYNC)) {
+ if(q1 != p)
+ sched(q1, q);
+ q1 = p;
+ o = 1;
+ }
+ if(p->mark & (BRANCH|SYNC)) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ if(o >= NSCHED) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ q = p;
+ }
+}
+
+void
+addnop(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = AORN;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGZERO;
+ q->to.type = D_REG;
+ q->to.reg = REGZERO;
+
+ q->link = p->link;
+ p->link = q;
+}
+
+void
+initmuldiv(void)
+{
+ Sym *s1, *s2, *s3, *s4, *s5;
+ Prog *p;
+
+ s1 = lookup("_mul", 0);
+ s2 = lookup("_div", 0);
+ s3 = lookup("_divl", 0);
+ s4 = lookup("_mod", 0);
+ s5 = lookup("_modl", 0);
+ for(p = firstp; p != P; p = p->link)
+ if(p->as == ATEXT) {
+ if(p->from.sym == s1)
+ prog_mul = p;
+ if(p->from.sym == s2)
+ prog_div = p;
+ if(p->from.sym == s3)
+ prog_divl = p;
+ if(p->from.sym == s4)
+ prog_mod = p;
+ if(p->from.sym == s5)
+ prog_modl = p;
+ }
+ if(prog_mul == P) {
+ diag("undefined: %s", s1->name);
+ prog_mul = curtext;
+ }
+ if(prog_div == P) {
+ diag("undefined: %s", s2->name);
+ prog_div = curtext;
+ }
+ if(prog_divl == P) {
+ diag("undefined: %s", s3->name);
+ prog_divl = curtext;
+ }
+ if(prog_mod == P) {
+ diag("undefined: %s", s4->name);
+ prog_mod = curtext;
+ }
+ if(prog_modl == P) {
+ diag("undefined: %s", s5->name);
+ prog_modl = curtext;
+ }
+}
diff --git a/utils/kl/obj.c b/utils/kl/obj.c
new file mode 100644
index 00000000..4233326e
--- /dev/null
+++ b/utils/kl/obj.c
@@ -0,0 +1,1277 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = 'k';
+char *thestring = "sparc";
+
+/*
+ * -H0 -T0x200000 -R0 is boot
+ * -H2 -T4128 -R4096 is plan9 format
+ * -H3 -T0xE0004000 -R4 is javastation boot format
+ */
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ outfile = 0;
+ nerrors = 0;
+ curtext = P;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ } ARGEND
+ USED(argc);
+ if(*argv == 0) {
+ diag("usage: vl [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 0;
+ if(debug['B'])
+ HEADTYPE = 1;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case 0: /* boot */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x200000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096L;
+ break;
+ case 1: /* garbage */
+ HEADR = 20L+60L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x80020000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* javastation boot */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 0xE0004020L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.to = zprg.from;
+ buildop();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ dtype = 4;
+ if(outfile == 0)
+ outfile = "k.out";
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("%s: cannot create", outfile);
+ errorexit();
+ }
+ nuxiinit();
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ goto out;
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ dodata();
+ follow();
+ if(firstp == P)
+ goto out;
+ noops();
+ span();
+ asmb();
+ undef();
+
+out:
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld memory used\n", tothunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ Bflush(&bso);
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int i, c;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ c = p[2];
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ p[0] = AEND+1;
+ return 0;
+ }
+ a->type = p[0];
+ a->reg = p[1];
+ a->sym = h[c];
+ a->name = p[3];
+ c = 4;
+
+ if(a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ p[0] = AEND+1;
+ return 0; /* force real diagnostic */
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ p[0] = AEND+1;
+ return 0; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_CREG:
+ case D_PREG:
+ break;
+
+ case D_BRANCH:
+ case D_OREG:
+ case D_ASI:
+ case D_CONST:
+ a->offset = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ c += 4;
+ break;
+
+ case D_SCONST:
+ memmove(a->sval, p+4, NSNAME);
+ c += NSNAME;
+ break;
+
+ case D_FCONST:
+ a->ieee.l = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ a->ieee.h = p[8] | (p[9]<<8) |
+ (p[10]<<16) | (p[11]<<24);
+ c += 8;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto out;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ goto out;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ goto out;
+ }
+
+ u = malloc(sizeof(Auto));
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+out:
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ Prog *p, *t;
+ Sym *h[NSYM], *s, *di;
+ int v, o, r, skip;
+ long ipc;
+ uchar *bloc, *bsize, *stop;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ histfrogp = 0;
+ version++;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0]; /* as */
+ if(o <= 0 || o >= ALAST) {
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .k file\n");
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[1]; /* type */
+ o = bloc[2]; /* sym */
+ bloc += 3;
+ c -= 3;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ if(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->reg = bloc[1] & 0x7f;
+ if(bloc[1] & 0x80)
+ p->mark = NOSCHED;
+ p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(p->reg < 0 || p->reg > NREG)
+ diag("register out of range %d", p->reg);
+
+ p->link = P;
+ p->cond = P;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ break;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->reg = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_CONST;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case ADATA:
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ curtext = p;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
+ s = p->from.sym;
+ if(s == S) {
+ diag("TEXT must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->reg & DUPOK) {
+ skip = 1;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P", s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ if(textp != P) {
+ for(t = textp; t->cond != P; t = t->cond)
+ ;
+ t->cond = p;
+ } else
+ textp = p;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+
+ case AFMOVF:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 4;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AFMOVD:
+ if(skip)
+ goto casedef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+ int n;
+
+ n = (sizeof(Prog) + 3) & ~3;
+ while(nhunk < n)
+ gethunk();
+
+ p = (Prog*)hunk;
+ nhunk -= n;
+ hunk += n;
+
+ *p = zprg;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(tothunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(tothunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char *)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+
+ hunk = h;
+ nhunk = nh;
+ tothunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ p->reg = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->reg = 1;
+ ps4 = p;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+
+ if(p->reg & NOPROF) { /* dont profile */
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AJMPL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARETURN) {
+
+ /*
+ * RETURN
+ */
+ q = prg();
+ q->as = ARETURN;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JMPL profout
+ */
+ p->as = AJMPL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x01020304L, i+1);
+ if(i >= 2)
+ inuxi2[i-2] = c;
+ if(i >= 3)
+ inuxi1[i-3] = c;
+ inuxi4[i] = c;
+
+ fnuxi8[i] = c+4;
+ fnuxi8[i+4] = c;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+long
+ieeedtof(Ieee *ieeep)
+{
+ int exp;
+ long v;
+
+ if(ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (ieeep->h & 0xfffffL) << 3;
+ v |= (ieeep->l >> 29) & 0x7L;
+ if((ieeep->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= ieeep->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
diff --git a/utils/kl/optab.c b/utils/kl/optab.c
new file mode 100644
index 00000000..31892430
--- /dev/null
+++ b/utils/kl/optab.c
@@ -0,0 +1,199 @@
+#include "l.h"
+
+#define X 99
+
+Optab optab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+ { ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+
+ { AMOVW, C_SCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMOVW, C_SACON,C_NONE, C_REG, 2, 4, REGSP },
+ { AMOVW, C_SECON,C_NONE, C_REG, 2, 4, REGSB },
+
+ { AMOVW, C_SOREG,C_NONE, C_REG, 3, 4, 0 },
+ { AMOVW, C_ZOREG,C_REG, C_REG, 3, 4, 0 },
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_SEXT, C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVB, C_SOREG,C_NONE, C_REG, 3, 4, 0 },
+ { AMOVB, C_ZOREG,C_REG, C_REG, 3, 4, 0 },
+ { AMOVB, C_SAUTO,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVB, C_SEXT, C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVD, C_SOREG,C_NONE, C_REG, 3, 4, 0 },
+ { AMOVD, C_ZOREG,C_REG, C_REG, 3, 4, 0 },
+ { AMOVD, C_SAUTO,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVD, C_SEXT, C_NONE, C_REG, 3, 4, REGSB },
+
+ { AMOVW, C_REG, C_NONE, C_SOREG, 4, 4, 0 },
+ { AMOVW, C_REG, C_REG, C_ZOREG, 4, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 4, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SEXT, 4, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 4, 4, 0 },
+ { AMOVB, C_REG, C_REG, C_ZOREG, 4, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 4, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SEXT, 4, 4, REGSB },
+ { AMOVD, C_REG, C_NONE, C_SOREG, 4, 4, 0 },
+ { AMOVD, C_REG, C_REG, C_ZOREG, 4, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_SAUTO, 4, 4, REGSP },
+ { AMOVD, C_REG, C_NONE, C_SEXT, 4, 4, REGSB },
+
+ { AMOVW, C_LCON, C_NONE, C_REG, 5, 8, 0 },
+
+ { AMOVW, C_ASI, C_NONE, C_REG, 6, 4, 0 },
+ { AMOVW, C_ASI, C_REG, C_REG, 6, 4, 0 },
+ { AMOVB, C_ASI, C_NONE, C_REG, 6, 4, 0 },
+ { AMOVB, C_ASI, C_REG, C_REG, 6, 4, 0 },
+ { AMOVD, C_ASI, C_NONE, C_REG, 6, 4, 0 },
+ { AMOVD, C_ASI, C_REG, C_REG, 6, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_ASI, 7, 4, 0 },
+ { AMOVW, C_REG, C_REG, C_ASI, 7, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_ASI, 7, 4, 0 },
+ { AMOVB, C_REG, C_REG, C_ASI, 7, 4, 0 },
+ { AMOVD, C_REG, C_NONE, C_ASI, 7, 4, 0 },
+ { AMOVD, C_REG, C_REG, C_ASI, 7, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_PREG, 8, 4, 0 },
+ { AMOVW, C_PREG, C_NONE, C_REG, 8, 4, 0 },
+
+ { AMOVB, C_REG, C_NONE, C_REG, 9, 8, 0 },
+
+ { AMOVW, C_LACON,C_NONE, C_REG, 10,12, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_REG, 10,12, REGSB },
+
+ { AMOVW, C_LOREG,C_NONE, C_REG, 11,12, 0 },
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 11,12, REGSP },
+ { AMOVW, C_LEXT, C_NONE, C_REG, 11,12, REGSB },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 11,12, 0 },
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 11,12, REGSP },
+ { AMOVB, C_LEXT, C_NONE, C_REG, 11,12, REGSB },
+ { AMOVD, C_LOREG,C_NONE, C_REG, 11,12, 0 },
+ { AMOVD, C_LAUTO,C_NONE, C_REG, 11,12, REGSP },
+ { AMOVD, C_LEXT, C_NONE, C_REG, 11,12, REGSB },
+
+ { AMOVW, C_REG, C_NONE, C_LOREG, 12,12, 0 },
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 12,12, REGSP },
+ { AMOVW, C_REG, C_NONE, C_LEXT, 12,12, REGSB },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 12,12, 0 },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 12,12, REGSP },
+ { AMOVB, C_REG, C_NONE, C_LEXT, 12,12, REGSB },
+ { AMOVD, C_REG, C_NONE, C_LOREG, 12,12, 0 },
+ { AMOVD, C_REG, C_NONE, C_LAUTO, 12,12, REGSP },
+ { AMOVD, C_REG, C_NONE, C_LEXT, 12,12, REGSB },
+
+ { AMOVW, C_UCON, C_NONE, C_REG, 13, 4, 0 },
+
+ { AADD, C_SCON, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_SCON, C_REG, C_REG, 20, 4, 0 },
+
+ { AADD, C_REG, C_NONE, C_REG, 21, 4, 0 },
+ { AADD, C_REG, C_REG, C_REG, 21, 4, 0 },
+
+ { AADD, C_LCON, C_NONE, C_REG, 22,12, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 22,12, 0 },
+
+ { ACMP, C_REG, C_NONE, C_REG, 23, 4, 0 },
+ { ACMP, C_REG, C_NONE, C_SCON, 24, 4, 0 },
+ { ACMP, C_SCON, C_NONE, C_REG, 25, 8, 0 },
+
+ { AADD, C_UCON, C_NONE, C_REG, 26, 8, 0 },
+ { AADD, C_UCON, C_REG, C_REG, 26, 8, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_SOREG, 30, 4, 0 },
+ { AJMPL, C_NONE, C_NONE, C_SOREG, 30, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_SBRA, 31, 4, 0 },
+ { ABA, C_NONE, C_NONE, C_SBRA, 31, 4, 0 },
+
+ { AJMPL, C_NONE, C_NONE, C_LBRA, 32, 4, 0 },
+
+ { ATA, C_REG, C_NONE, C_NONE, 33, 4, 0 },
+ { ARETT, C_REG, C_NONE, C_REG, 34, 8, 0 },
+
+ { AMOVW, C_SOREG,C_NONE, C_FSR, 40, 4, 0 },
+ { AMOVW, C_SAUTO,C_NONE, C_FSR, 40, 4, REGSP },
+ { AMOVW, C_SEXT, C_NONE, C_FSR, 40, 4, REGSB },
+ { AMOVW, C_FSR, C_NONE, C_SOREG, 40, 4, 0 },
+ { AMOVW, C_FSR, C_NONE, C_SAUTO, 40, 4, REGSP },
+ { AMOVW, C_FSR, C_NONE, C_SEXT, 40, 4, REGSB },
+ { AMOVD, C_FQ, C_NONE, C_SOREG, 40, 4, 0 },
+ { AMOVD, C_FQ, C_NONE, C_SAUTO, 40, 4, REGSP },
+ { AMOVD, C_FQ, C_NONE, C_SEXT, 40, 4, REGSB },
+
+ { AFMOVF, C_SOREG,C_NONE, C_FREG, 41, 4, 0 },
+ { AFMOVF, C_SAUTO,C_NONE, C_FREG, 41, 4, REGSP },
+ { AFMOVF, C_SEXT, C_NONE, C_FREG, 41, 4, REGSB },
+ { AMOVW, C_SOREG,C_NONE, C_FREG, 41, 4, 0 },
+ { AMOVW, C_SAUTO,C_NONE, C_FREG, 41, 4, REGSP },
+ { AMOVW, C_SEXT, C_NONE, C_FREG, 41, 4, REGSB },
+ { AMOVD, C_SOREG,C_NONE, C_FREG, 41, 4, 0 },
+ { AMOVD, C_SAUTO,C_NONE, C_FREG, 41, 4, REGSP },
+ { AFMOVD, C_ESAUTO,C_NONE,C_FREG, 41, 4, REGSP },
+ { AMOVD, C_SEXT, C_NONE, C_FREG, 41, 4, REGSB },
+ { AFMOVD, C_ESEXT,C_NONE, C_FREG, 41, 4, REGSB },
+
+ { AFMOVD, C_SOREG,C_NONE, C_FREG, 42, 8, 0 },
+ { AFMOVD, C_SAUTO,C_NONE, C_FREG, 42, 8, REGSP },
+ { AFMOVD, C_SEXT, C_NONE, C_FREG, 42, 8, REGSB },
+
+ { AFMOVF, C_FREG, C_NONE, C_SOREG, 43, 4, 0 },
+ { AFMOVF, C_FREG, C_NONE, C_SAUTO, 43, 4, REGSP },
+ { AFMOVF, C_FREG, C_NONE, C_SEXT, 43, 4, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_SOREG, 43, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_SAUTO, 43, 4, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_SEXT, 43, 4, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_SOREG, 43, 4, 0 },
+ { AMOVD, C_FREG, C_NONE, C_SAUTO, 43, 4, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_ESAUTO, 43, 4, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_SEXT, 43, 4, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_ESEXT, 43, 4, REGSB },
+
+ { AFMOVD, C_FREG, C_NONE, C_SOREG, 44, 8, 0 },
+ { AFMOVD, C_FREG, C_NONE, C_SAUTO, 44, 8, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_SEXT, 44, 8, REGSB },
+
+ { AFMOVF, C_LOREG,C_NONE, C_FREG, 45,12, 0 },
+ { AFMOVF, C_LAUTO,C_NONE, C_FREG, 45,12, REGSP },
+ { AFMOVF, C_LEXT, C_NONE, C_FREG, 45,12, REGSB },
+
+ { AFMOVD, C_LOREG,C_NONE, C_FREG, 46,16, 0 },
+ { AFMOVD, C_LAUTO,C_NONE, C_FREG, 46,16, REGSP },
+ { AFMOVD, C_LEXT, C_NONE, C_FREG, 46,16, REGSB },
+
+ { AFMOVF, C_FREG, C_NONE, C_LOREG, 47,12, 0 },
+ { AFMOVF, C_FREG, C_NONE, C_LAUTO, 47,12, REGSP },
+ { AFMOVF, C_FREG, C_NONE, C_LEXT, 47,12, REGSB },
+
+ { AFMOVD, C_FREG, C_NONE, C_LOREG, 48,16, 0 },
+ { AFMOVD, C_FREG, C_NONE, C_LAUTO, 48,16, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_LEXT, 48,16, REGSB },
+
+ { AFMOVD, C_FREG, C_NONE, C_FREG, 49, 8, 0 },
+ { AFCMPD, C_FREG, C_NONE, C_FREG, 50, 4, 0 },
+
+ { AFABSF, C_FREG, C_NONE, C_FREG, 57, 4, 0 },
+ { AFMOVF, C_FREG, C_NONE, C_FREG, 57, 4, 0 },
+ { AFADDD, C_FREG, C_NONE, C_FREG, 21, 4, 0 },
+ { AFADDD, C_FREG, C_REG, C_FREG, 21, 4, 0 },
+
+ { AWORD, C_LCON, C_NONE, C_NONE, 51, 4, 0 },
+
+ { ADIV, C_REG, C_NONE, C_REG, 52,12, 0 },
+ { ADIV, C_REG, C_REG, C_REG, 52,12, 0 },
+
+ { ADIVL, C_REG, C_NONE, C_REG, 53, 8, 0 },
+ { ADIVL, C_REG, C_REG, C_REG, 53, 8, 0 },
+
+ { AMOD, C_REG, C_NONE, C_REG, 54,20, 0 },
+ { AMOD, C_REG, C_REG, C_REG, 54,20, 0 },
+
+ { AMODL, C_REG, C_NONE, C_REG, 55,16, 0 },
+ { AMODL, C_REG, C_REG, C_REG, 55,16, 0 },
+
+ { ABE, C_NONE, C_NONE, C_SBRA, 56, 4, 0 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
diff --git a/utils/kl/pass.c b/utils/kl/pass.c
new file mode 100644
index 00000000..6c8fb526
--- /dev/null
+++ b/utils/kl/pass.c
@@ -0,0 +1,551 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i, t;
+ Sym *s;
+ Prog *p, *p1;
+ long orig, orig1, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ v = p->from.offset + p->reg;
+ if(v > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ /*
+ * pass 1
+ * assign 'small' variables to data segment
+ * (rational is that data segment is more easily
+ * addressed through offset on REGSB)
+ */
+ orig = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA && t != SBSS)
+ continue;
+ v = s->value;
+ if(v == 0) {
+ diag("%s: no size", s->name);
+ v = 1;
+ }
+ while(v & 3)
+ v++;
+ s->value = v;
+ if(v > MINSIZ)
+ continue;
+ if(v >= 8)
+ while(orig & 7)
+ orig++;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+ orig1 = orig;
+
+ /*
+ * pass 2
+ * assign 'data' variables to data segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA) {
+ if(t == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ v = s->value;
+ if(v >= 8)
+ while(orig & 7)
+ orig++;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+
+ while(orig & 7)
+ orig++;
+ datsize = orig;
+
+ /*
+ * pass 3
+ * everything else to bss segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ v = s->value;
+ if(v >= 8)
+ while(orig & 7)
+ orig++;
+ s->value = orig;
+ orig += v;
+ }
+ while(orig & 7)
+ orig++;
+ bsssize = orig-datsize;
+
+ /*
+ * pass 4
+ * add literals to all large values.
+ * at this time:
+ * small data is allocated DATA
+ * large data is allocated DATA1
+ * large bss is allocated BSS
+ * the new literals are loaded between
+ * small data and large data.
+ */
+ orig = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as != AMOVW)
+ continue;
+ if(p->from.type != D_CONST)
+ continue;
+ if(s = p->from.sym) {
+ t = s->type;
+ if(t != SDATA && t != SDATA1 && t != SBSS)
+ continue;
+ t = p->from.name;
+ if(t != D_EXTERN && t != D_STATIC)
+ continue;
+ v = s->value + p->from.offset;
+ if(v >= 0 && v <= 0xffff)
+ continue;
+ if(!strcmp(s->name, "setSB"))
+ continue;
+ /* size should be 19 max */
+ if(strlen(s->name) >= 10) /* has loader address */
+ sprint(literal, "$%p.%lux", s, p->from.offset);
+ else
+ sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset);
+ } else {
+ if(p->from.name != D_NONE)
+ continue;
+ if(p->from.reg != NREG)
+ continue;
+ v = p->from.offset;
+ if(v >= -0x7fff && v <= 0xffff)
+ continue;
+ if(!(v & 0xffff))
+ continue;
+ /* size should be 9 max */
+ sprint(literal, "$%lux", v);
+ }
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ s->value = orig1+orig;
+ orig += 4;
+ p1 = prg();
+ p1->as = ADATA;
+ p1->line = p->line;
+ p1->from.type = D_OREG;
+ p1->from.sym = s;
+ p1->from.name = D_EXTERN;
+ p1->reg = 4;
+ p1->to = p->from;
+ p1->link = datap;
+ datap = p1;
+ }
+ if(s->type != SDATA)
+ diag("literal not data: %s", s->name);
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ continue;
+ }
+ while(orig & 7)
+ orig++;
+ /*
+ * pass 5
+ * re-adjust offsets
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t == SBSS) {
+ s->value += orig;
+ continue;
+ }
+ if(t == SDATA1) {
+ s->type = SDATA;
+ s->value += orig;
+ continue;
+ }
+ }
+ datsize += orig;
+ xdefine("setSB", SDATA, 0L+BIG);
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+ xdefine("etext", STEXT, 0L);
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABA: return ABN;
+ case ABN: return ABA;
+
+ case ABE: return ABNE;
+ case ABNE: return ABE;
+
+ case ABLE: return ABG;
+ case ABG: return ABLE;
+
+ case ABL: return ABGE;
+ case ABGE: return ABL;
+
+ case ABLEU: return ABGU;
+ case ABGU: return ABLEU;
+
+ case ABCS: return ABCC;
+ case ABCC: return ABCS;
+
+ case ABNEG: return ABPOS;
+ case ABPOS: return ABNEG;
+
+ case ABVC: return ABVS;
+ case ABVS: return ABVC;
+
+ case AFBN: return AFBA;
+ case AFBA: return AFBN;
+
+ case AFBE: return AFBLG;
+ case AFBLG: return AFBE;
+
+ case AFBG: return AFBLE;
+ case AFBLE: return AFBG;
+
+ case AFBGE: return AFBL;
+ case AFBL: return AFBGE;
+
+ /* unordered fp compares have no inverse
+ that traps in the same way */
+ }
+ return 0;
+}
+
+void
+follow(void)
+{
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ firstp = prg();
+ lastp = firstp;
+
+ xfol(textp);
+
+ firstp = firstp->link;
+ lastp->link = P;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q, *r;
+ int a, b, i;
+
+loop:
+ if(p == P)
+ return;
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(a == AJMP) {
+ q = p->cond;
+ if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ p = p->link;
+ xfol(p);
+ p = q;
+ if(p && !(p->mark & FOLL))
+ goto loop;
+ return;
+ }
+ if(q != P) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == lastp || (q->mark&NOSCHED))
+ break;
+ b = 0; /* set */
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AJMP || a == ARETURN || a == ARETT)
+ goto copy;
+ if(!q->cond || (q->cond->mark&FOLL))
+ continue;
+ b = relinv(a);
+ if(!b)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ lastp->link = r;
+ lastp = r;
+ continue;
+ }
+ lastp->link = r;
+ lastp = r;
+ if(a == AJMP || a == ARETURN || a == ARETT)
+ return;
+ r->as = b;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+
+ a = AJMP;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ if(a == AJMP || a == ARETURN || a == ARETT){
+ if(p->mark & NOSCHED){
+ p = p->link;
+ goto loop;
+ }
+ return;
+ }
+ if(p->cond != P)
+ if(a != AJMPL && p->link != P) {
+ xfol(p->link);
+ p = p->cond;
+ if(p == P || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ long c, vexit;
+ Prog *p, *q;
+ Sym *s;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if((a == AJMPL || a == ARETURN) && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s\n%P", s->name, p);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range %ld\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->cond != P) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ long dwn[LOG], cnt[LOG], i;
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != AJMP || (p->mark&NOSCHED))
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/utils/kl/sched.c b/utils/kl/sched.c
new file mode 100644
index 00000000..4bbfb164
--- /dev/null
+++ b/utils/kl/sched.c
@@ -0,0 +1,672 @@
+#include "l.h"
+
+enum
+{
+ E_ICC = 1<<0,
+ E_FCC = 1<<1,
+ E_MEM = 1<<2,
+ E_MEMSP = 1<<3, /* uses offset and size */
+ E_MEMSB = 1<<4, /* uses offset and size */
+ ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
+ ALL = ~0
+};
+
+typedef struct Sch Sch;
+typedef struct Dep Dep;
+
+struct Dep
+{
+ ulong ireg;
+ ulong freg;
+ ulong cc;
+};
+struct Sch
+{
+ Prog p;
+ Dep set;
+ Dep used;
+ long soffset;
+ char size;
+ char nop;
+ char comp;
+};
+
+void regsused(Sch*, Prog*);
+int depend(Sch*, Sch*);
+int conflict(Sch*, Sch*);
+int offoverlap(Sch*, Sch*);
+void dumpbits(Sch*, Dep*);
+
+void
+sched(Prog *p0, Prog *pe)
+{
+ Prog *p, *q;
+ Sch sch[NSCHED], *s, *t, *u, *se, stmp;
+
+ /*
+ * build side structure
+ */
+ s = sch;
+ for(p=p0;; p=p->link) {
+ memset(s, 0, sizeof(*s));
+ s->p = *p;
+ regsused(s, p);
+ if(debug['X']) {
+ Bprint(&bso, "%P\tset", &s->p);
+ dumpbits(s, &s->set);
+ Bprint(&bso, "; used");
+ dumpbits(s, &s->used);
+ if(s->comp)
+ Bprint(&bso, "; compound");
+ if(s->p.mark & LOAD)
+ Bprint(&bso, "; load");
+ if(s->p.mark & BRANCH)
+ Bprint(&bso, "; branch");
+ if(s->p.mark & FCMP)
+ Bprint(&bso, "; fcmp");
+ Bprint(&bso, "\n");
+ }
+ s++;
+ if(p == pe)
+ break;
+ }
+ se = s;
+
+ for(s=se-1; s>=sch; s--) {
+ /*
+ * branch delay slot
+ */
+ if(s->p.mark & BRANCH) {
+ /* t is the trial instruction to use */
+ for(t=s-1; t>=sch; t--) {
+ if(t->comp || (t->p.mark & FCMP))
+ goto no1;
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no1;
+ goto out1;
+ no1:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?b%P\n", &s->p);
+ s->nop = 1;
+ continue;
+
+ out1:
+ if(debug['X']) {
+ Bprint(&bso, "!b%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+
+ /*
+ * load delay. interlocked.
+ */
+ if(s->p.mark & LOAD) {
+ if(s >= se-1)
+ continue;
+ if(!conflict(s, (s+1)))
+ continue;
+ /*
+ * s is load, s+1 is immediate use of result
+ * t is the trial instruction to insert between s and s+1
+ */
+ for(t=s-1; t>=sch; t--) {
+ if(t->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & FCMP)
+ if((s+1)->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & LOAD)
+ if(conflict(t, (s+1)))
+ goto no2;
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no2;
+ goto out2;
+ no2:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?l%P\n", &s->p);
+ continue;
+ out2:
+ if(debug['X']) {
+ Bprint(&bso, "!l%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+
+ /*
+ * fop2 delay.
+ */
+ if(s->p.mark & FCMP) {
+ if(s >= se-1) {
+ s->nop = 1;
+ continue;
+ }
+ if(!((s+1)->p.mark & BRANCH))
+ continue;
+ /* t is the trial instruction to use */
+ for(t=s-1; t>=sch; t--) {
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no3;
+ goto out3;
+ no3:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?f%P\n", &s->p);
+ s->nop = 1;
+ continue;
+ out3:
+ if(debug['X']) {
+ Bprint(&bso, "!f%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+ }
+
+ /*
+ * put it all back
+ */
+ for(s=sch, p=p0; s<se; s++, p=q) {
+ q = p->link;
+ if(q != s->p.link) {
+ *p = s->p;
+ p->link = q;
+ }
+ if(s->nop)
+ addnop(p);
+ }
+ if(debug['X'])
+ Bprint(&bso, "\n");
+}
+
+void
+regsused(Sch *s, Prog *realp)
+{
+ int c, ar, ad, ld, sz;
+ ulong m;
+ Prog *p;
+
+ p = &s->p;
+ s->comp = compound(p);
+ s->nop = 0;
+ if(s->comp) {
+ s->set.ireg |= 1<<REGTMP;
+ s->used.ireg |= 1<<REGTMP;
+ }
+ ar = 0; /* dest is really reference */
+ ad = 0; /* source/dest is really address */
+ ld = 0; /* opcode is load instruction */
+ sz = 20; /* size of load/store for overlap computation */
+
+/*
+ * flags based on opcode
+ */
+ switch(p->as) {
+ case ATEXT:
+ curtext = realp;
+ autosize = p->to.offset + 4;
+ ad = 1;
+ break;
+ case AJMPL:
+ c = p->reg;
+ if(c == NREG)
+ c = REGLINK;
+ s->set.ireg |= 1<<c;
+ ar = 1;
+ ad = 1;
+ break;
+ case AJMP:
+ ar = 1;
+ ad = 1;
+ break;
+ case ACMP:
+ s->set.cc |= E_ICC;
+ ar = 1;
+ break;
+ case AFCMPD:
+ case AFCMPED:
+ case AFCMPEF:
+ case AFCMPEX:
+ case AFCMPF:
+ case AFCMPX:
+ s->set.cc |= E_FCC;
+ ar = 1;
+ break;
+ case ABE:
+ case ABNE:
+ case ABLE:
+ case ABG:
+ case ABL:
+ case ABGE:
+ case ABLEU:
+ case ABGU:
+ case ABCS:
+ case ABCC:
+ case ABNEG:
+ case ABPOS:
+ case ABVC:
+ case ABVS:
+ s->used.cc |= E_ICC;
+ ar = 1;
+ break;
+ case AFBE:
+ case AFBLG:
+ case AFBG:
+ case AFBLE:
+ case AFBGE:
+ case AFBL:
+ s->used.cc |= E_FCC;
+ ar = 1;
+ break;
+ case AMOVB:
+ case AMOVBU:
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVH:
+ case AMOVHU:
+ sz = 2;
+ ld = 1;
+ break;
+ case AFMOVF:
+ case AMOVW:
+ sz = 4;
+ ld = 1;
+ break;
+ case AMOVD:
+ case AFMOVD:
+ sz = 8;
+ ld = 1;
+ break;
+ case AFMOVX: /* gok */
+ sz = 16;
+ ld = 1;
+ break;
+ case AADDCC:
+ case AADDXCC:
+ case AANDCC:
+ case AANDNCC:
+ case AORCC:
+ case AORNCC:
+ case ASUBCC:
+ case ASUBXCC:
+ case ATADDCC:
+ case ATADDCCTV:
+ case ATSUBCC:
+ case ATSUBCCTV:
+ case AXNORCC:
+ case AXORCC:
+ s->set.cc |= E_ICC;
+ break;
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+ case AMUL:
+ case AMULSCC:
+ case ATAS:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ break;
+ }
+
+/*
+ * flags based on 'to' field
+ */
+ c = p->to.class;
+ if(c == 0) {
+ c = aclass(&p->to) + 1;
+ p->to.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->to);
+
+ case C_ZCON:
+ case C_SCON:
+ case C_UCON:
+ case C_LCON:
+ case C_NONE:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+ case C_CREG:
+ case C_FSR:
+ case C_FQ:
+ case C_PREG:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ case C_ASI:
+ c = p->to.reg;
+ s->used.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ if(ar)
+ s->used.cc |= m;
+ else
+ s->set.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ if(ar)
+ s->used.ireg |= 1<<p->to.reg;
+ else
+ s->set.ireg |= 1<<p->to.reg;
+ break;
+ case C_FREG:
+ /* do better -- determine double prec */
+ if(ar) {
+ s->used.freg |= 1<<p->to.reg;
+ s->used.freg |= 1<<(p->to.reg|1);
+ } else {
+ s->set.freg |= 1<<p->to.reg;
+ s->set.freg |= 1<<(p->to.reg|1);
+ }
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ case C_ESAUTO:
+ case C_OSAUTO:
+ case C_ELAUTO:
+ case C_OLAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSP;
+ else
+ s->set.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ case C_ESEXT:
+ case C_OSEXT:
+ case C_ELEXT:
+ case C_OLEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSB;
+ else
+ s->set.cc |= E_MEMSB;
+ break;
+ }
+
+/*
+ * flags based on 'from' field
+ */
+ c = p->from.class;
+ if(c == 0) {
+ c = aclass(&p->from) + 1;
+ p->from.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->from);
+
+ case C_ZCON:
+ case C_SCON:
+ case C_UCON:
+ case C_LCON:
+ case C_NONE:
+ case C_SBRA:
+ case C_LBRA:
+ c = p->from.reg;
+ if(c != NREG)
+ s->used.ireg |= 1<<c;
+ break;
+ case C_CREG:
+ case C_FSR:
+ case C_FQ:
+ case C_PREG:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ case C_ASI:
+ c = p->from.reg;
+ s->used.ireg |= 1<<c;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ s->used.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ s->used.ireg |= 1<<p->from.reg;
+ break;
+ case C_FREG:
+ /* do better -- determine double prec */
+ s->used.freg |= 1<<p->from.reg;
+ s->used.freg |= 1<<(p->from.reg|1);
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ case C_ESAUTO:
+ case C_ELAUTO:
+ case C_OSAUTO:
+ case C_OLAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ case C_ESEXT:
+ case C_ELEXT:
+ case C_OSEXT:
+ case C_OLEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSB;
+ break;
+ }
+
+ c = p->reg;
+ if(c != NREG) {
+ if(p->from.type == D_FREG || p->to.type == D_FREG) {
+ s->used.freg |= 1<<c;
+ s->used.freg |= 1<<(c|1);
+ } else
+ s->used.ireg |= 1<<c;
+ }
+ s->set.ireg &= ~(1<<0); /* R0 cant be set */
+}
+
+/*
+ * test to see if 2 instrictions can be
+ * interchanged without changing semantics
+ */
+int
+depend(Sch *sa, Sch *sb)
+{
+ ulong x;
+
+ if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
+ return 1;
+ if(sb->set.ireg & sa->used.ireg)
+ return 1;
+
+ if(sa->set.freg & (sb->set.freg|sb->used.freg))
+ return 1;
+ if(sb->set.freg & sa->used.freg)
+ return 1;
+
+ x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
+ (sb->set.cc & sa->used.cc);
+ if(x) {
+ /*
+ * allow SB and SP to pass each other.
+ * allow SB to pass SB iff doffsets are ok
+ * anything else conflicts
+ */
+ if(x != E_MEMSP && x != E_MEMSB)
+ return 1;
+ x = sa->set.cc | sb->set.cc |
+ sa->used.cc | sb->used.cc;
+ if(x & E_MEM)
+ return 1;
+ if(offoverlap(sa, sb))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+offoverlap(Sch *sa, Sch *sb)
+{
+
+ if(sa->soffset < sb->soffset) {
+ if(sa->soffset+sa->size > sb->soffset)
+ return 1;
+ return 0;
+ }
+ if(sb->soffset+sb->size > sa->soffset)
+ return 1;
+ return 0;
+}
+
+/*
+ * test 2 adjacent instructions
+ * and find out if inserted instructions
+ * are desired to prevent stalls.
+ * first instruction is a load instruction.
+ */
+int
+conflict(Sch *sa, Sch *sb)
+{
+
+ if(sa->set.ireg & sb->used.ireg)
+ return 1;
+ if(sa->set.freg & sb->used.freg)
+ return 1;
+ return 0;
+}
+
+int
+compound(Prog *p)
+{
+ Optab *o;
+
+ o = oplook(p);
+ if(o->size != 4)
+ return 1;
+ if(p->to.type == D_REG && p->to.reg == REGSB)
+ return 1;
+ return 0;
+}
+
+void
+dumpbits(Sch *s, Dep *d)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(d->ireg & (1<<i))
+ Bprint(&bso, " R%d", i);
+ for(i=0; i<32; i++)
+ if(d->freg & (1<<i))
+ Bprint(&bso, " F%d", i);
+ for(i=0; i<32; i++)
+ switch(d->cc & (1<<i)) {
+ default:
+ break;
+ case E_ICC:
+ Bprint(&bso, " ICC");
+ break;
+ case E_FCC:
+ Bprint(&bso, " FCC");
+ break;
+ case E_MEM:
+ Bprint(&bso, " MEM%d", s->size);
+ break;
+ case E_MEMSB:
+ Bprint(&bso, " SB%d", s->size);
+ break;
+ case E_MEMSP:
+ Bprint(&bso, " SP%d", s->size);
+ break;
+ }
+}
diff --git a/utils/kl/span.c b/utils/kl/span.c
new file mode 100644
index 00000000..fdfb8034
--- /dev/null
+++ b/utils/kl/span.c
@@ -0,0 +1,522 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p;
+ Sym *setext;
+ Optab *o;
+ int m;
+ long c;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ if(p->as != ANOP)
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ c = rnd(c, 8);
+
+ setext = lookup("etext", 0);
+ if(setext != S) {
+ setext->value = c;
+ textsize = c - INITTEXT;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "tsize = %lux\n", textsize);
+ Bflush(&bso);
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+}
+
+long
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+int
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_CREG:
+ return C_CREG;
+
+ case D_PREG:
+ if(a->reg == D_FSR)
+ return C_FSR;
+ if(a->reg == D_FPQ)
+ return C_FQ;
+ return C_PREG;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == S)
+ break;
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ instoffset = a->sym->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG) {
+ if(instoffset & 7)
+ return C_OSEXT;
+ return C_ESEXT;
+ }
+ if(instoffset & 7)
+ return C_OLEXT;
+ return C_ELEXT;
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ goto dauto;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ dauto:
+ if(instoffset >= -BIG && instoffset < BIG) {
+ if(instoffset & 7)
+ return C_OSAUTO;
+ return C_ESAUTO;
+ }
+ if(instoffset & 7)
+ return C_OLAUTO;
+ return C_ELAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ if(instoffset == 0)
+ return C_ZOREG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_ASI:
+ if(a->name == D_NONE)
+ return C_ASI;
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+
+ case D_NONE:
+ instoffset = a->offset;
+ consize:
+ if(instoffset == 0)
+ return C_ZCON;
+ if(instoffset >= -0x1000 && instoffset <= 0xfff)
+ return C_SCON;
+ if((instoffset & 0x3ff) == 0)
+ return C_UCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ if(s->type == STEXT || s->type == SLEAF) {
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ if(s->type == SCONST) {
+ instoffset = s->value + a->offset;
+ goto consize;
+ }
+ instoffset = s->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG && instoffset != 0)
+ return C_SECON;
+ instoffset = s->value + a->offset + INITDAT;
+/* not sure why this barfs */
+return C_LCON;
+ if(instoffset == 0)
+ return C_ZCON;
+ if(instoffset >= -0x1000 && instoffset <= 0xfff)
+ return C_SCON;
+ if((instoffset & 0x3ff) == 0)
+ return C_UCON;
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(&p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0)
+ o = oprange[r].stop; /* just generate an error */
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ diag("illegal combination %A %d %d %d",
+ p->as, a1, a2, a3);
+ if(1||!debug['a'])
+ prasm(p);
+ if(o == 0)
+ errorexit();
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_ELEXT:
+ if(b == C_ESEXT)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT ||
+ b == C_ESEXT || b == C_OSEXT ||
+ b == C_ELEXT || b == C_OLEXT)
+ return 1;
+ break;
+ case C_SEXT:
+ if(b == C_ESEXT || b == C_OSEXT)
+ return 1;
+ break;
+ case C_ELAUTO:
+ if(b == C_ESAUTO)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO ||
+ b == C_ESAUTO || b == C_OSAUTO ||
+ b == C_ELAUTO || b == C_OLAUTO)
+ return 1;
+ break;
+ case C_SAUTO:
+ if(b == C_ESAUTO || b == C_OSAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+
+ case C_ANY:
+ return 1;
+ }
+ return 0;
+}
+
+int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ for(i=0; i<C_NCLASS; i++)
+ for(n=0; n<C_NCLASS; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A", r);
+ errorexit();
+ case AADD:
+ oprange[AADDX] = oprange[r];
+ oprange[ASUB] = oprange[r];
+ oprange[ASUBX] = oprange[r];
+ oprange[AMUL] = oprange[r];
+ oprange[AXOR] = oprange[r];
+ oprange[AXNOR] = oprange[r];
+ oprange[AAND] = oprange[r];
+ oprange[AANDN] = oprange[r];
+ oprange[AOR] = oprange[r];
+ oprange[AORN] = oprange[r];
+ oprange[ASLL] = oprange[r];
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ oprange[AADDCC] = oprange[r];
+ oprange[AADDXCC] = oprange[r];
+ oprange[ATADDCC] = oprange[r];
+ oprange[ATADDCCTV] = oprange[r];
+ oprange[ASUBCC] = oprange[r];
+ oprange[ASUBXCC] = oprange[r];
+ oprange[ATSUBCC] = oprange[r];
+ oprange[ATSUBCCTV] = oprange[r];
+ oprange[AXORCC] = oprange[r];
+ oprange[AXNORCC] = oprange[r];
+ oprange[AANDCC] = oprange[r];
+ oprange[AANDNCC] = oprange[r];
+ oprange[AORCC] = oprange[r];
+ oprange[AORNCC] = oprange[r];
+ oprange[AMULSCC] = oprange[r];
+ oprange[ASAVE] = oprange[r];
+ oprange[ARESTORE] = oprange[r];
+ break;
+ case AMOVB:
+ oprange[AMOVH] = oprange[r];
+ oprange[AMOVHU] = oprange[r];
+ oprange[AMOVBU] = oprange[r];
+ oprange[ASWAP] = oprange[r];
+ oprange[ATAS] = oprange[r];
+ break;
+ case ABA:
+ oprange[ABN] = oprange[r];
+ oprange[AFBA] = oprange[r];
+ oprange[AFBN] = oprange[r];
+ break;
+ case ABE:
+ oprange[ABCC] = oprange[r];
+ oprange[ABCS] = oprange[r];
+ oprange[ABGE] = oprange[r];
+ oprange[ABGU] = oprange[r];
+ oprange[ABG] = oprange[r];
+ oprange[ABLEU] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ oprange[ABL] = oprange[r];
+ oprange[ABNEG] = oprange[r];
+ oprange[ABNE] = oprange[r];
+ oprange[ABPOS] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABVS] = oprange[r];
+
+ oprange[AFBE] = oprange[r];
+ oprange[AFBG] = oprange[r];
+ oprange[AFBGE] = oprange[r];
+ oprange[AFBL] = oprange[r];
+ oprange[AFBLE] = oprange[r];
+ oprange[AFBLG] = oprange[r];
+ oprange[AFBNE] = oprange[r];
+ oprange[AFBO] = oprange[r];
+ oprange[AFBU] = oprange[r];
+ oprange[AFBUE] = oprange[r];
+ oprange[AFBUG] = oprange[r];
+ oprange[AFBUGE] = oprange[r];
+ oprange[AFBUL] = oprange[r];
+ oprange[AFBULE] = oprange[r];
+ break;
+ case ATA:
+ oprange[ATCC] = oprange[r];
+ oprange[ATCS] = oprange[r];
+ oprange[ATE] = oprange[r];
+ oprange[ATGE] = oprange[r];
+ oprange[ATGU] = oprange[r];
+ oprange[ATG] = oprange[r];
+ oprange[ATLEU] = oprange[r];
+ oprange[ATLE] = oprange[r];
+ oprange[ATL] = oprange[r];
+ oprange[ATNEG] = oprange[r];
+ oprange[ATNE] = oprange[r];
+ oprange[ATN] = oprange[r];
+ oprange[ATPOS] = oprange[r];
+ oprange[ATVC] = oprange[r];
+ oprange[ATVS] = oprange[r];
+ break;
+ case AFADDD:
+ oprange[AFADDF] = oprange[r];
+ oprange[AFADDX] = oprange[r];
+ oprange[AFDIVD] = oprange[r];
+ oprange[AFDIVF] = oprange[r];
+ oprange[AFDIVX] = oprange[r];
+ oprange[AFMULD] = oprange[r];
+ oprange[AFMULF] = oprange[r];
+ oprange[AFMULX] = oprange[r];
+ oprange[AFSUBD] = oprange[r];
+ oprange[AFSUBF] = oprange[r];
+ oprange[AFSUBX] = oprange[r];
+ break;
+ case AFCMPD:
+ oprange[AFCMPF] = oprange[r];
+ oprange[AFCMPX] = oprange[r];
+ oprange[AFCMPED] = oprange[r];
+ oprange[AFCMPEF] = oprange[r];
+ oprange[AFCMPEX] = oprange[r];
+ break;
+ case AFABSF:
+ oprange[AFMOVDF] = oprange[r];
+ oprange[AFMOVDW] = oprange[r];
+ oprange[AFMOVFD] = oprange[r];
+ oprange[AFMOVFW] = oprange[r];
+ oprange[AFMOVWD] = oprange[r];
+ oprange[AFMOVWF] = oprange[r];
+ oprange[AFNEGF] = oprange[r];
+ oprange[AFSQRTD] = oprange[r];
+ oprange[AFSQRTF] = oprange[r];
+ break;
+ case AFMOVF:
+ case AFMOVD:
+ case AMOVW:
+ case AMOVD:
+ case AWORD:
+ case ARETT:
+ case AJMPL:
+ case AJMP:
+ case ACMP:
+ case ANOP:
+ case ATEXT:
+ case ADIV:
+ case ADIVL:
+ case AMOD:
+ case AMODL:
+ break;
+ }
+ }
+}
diff --git a/utils/kprof/kprof.c b/utils/kprof/kprof.c
new file mode 100644
index 00000000..a524815e
--- /dev/null
+++ b/utils/kprof/kprof.c
@@ -0,0 +1,155 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+enum {
+ SpecialTotalTicks,
+ SpecialOutsideTicks,
+ SpecialMicroSecondsPerTick,
+ SpecialSamples,
+ SpecialSampleSize,
+ SpecialSampleLogBucketSize,
+ SpecialMax
+};
+
+int pcres = 8;
+ulong uspertick;
+
+struct COUNTER
+{
+ char *name; /* function name */
+ ulong time; /* ticks spent there */
+};
+
+void
+error(int perr, char *s)
+{
+ fprint(2, "kprof: %s", s);
+ if(perr)
+ fprint(2, ": %r\n");
+ else
+ fprint(2, "\n");
+ exits(s);
+}
+
+int
+compar(void *va, void *vb)
+{
+ struct COUNTER *a, *b;
+
+ a = (struct COUNTER *)va;
+ b = (struct COUNTER *)vb;
+ if(a->time < b->time)
+ return -1;
+ if(a->time == b->time)
+ return 0;
+ return 1;
+}
+
+ulong
+tickstoms(ulong ticks)
+{
+ return ((vlong)ticks * uspertick) / 1000;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int fd;
+ long i, j, k, n;
+ Dir *d;
+ char *name;
+ ulong *data;
+ ulong tbase, sum;
+ long delta;
+ Symbol s;
+ Biobuf outbuf;
+ Fhdr f;
+ struct COUNTER *cp;
+
+ if(argc != 3)
+ error(0, "usage: kprof text data");
+ /*
+ * Read symbol table
+ */
+ fd = open(argv[1], OREAD);
+ if(fd < 0)
+ error(1, argv[1]);
+ if (!crackhdr(fd, &f))
+ error(1, "read text header");
+ if (f.type == FNONE)
+ error(0, "text file not an a.out");
+ if (syminit(fd, &f) < 0)
+ error(1, "syminit");
+ close(fd);
+ /*
+ * Read timing data
+ */
+ fd = open(argv[2], OREAD);
+ if(fd < 0)
+ error(1, argv[2]);
+ if((d = dirfstat(fd)) == nil)
+ error(1, "stat");
+ n = d->length/sizeof(data[0]);
+ if(n < 2)
+ error(0, "data file too short");
+ data = malloc(d->length);
+ if(data == 0)
+ error(1, "malloc");
+ if(read(fd, data, d->length) < 0)
+ error(1, "text read");
+ close(fd);
+ free(d);
+ for(i=0; i<n; i++)
+ data[i] = beswal(data[i]);
+ pcres = 1 << data[SpecialSampleLogBucketSize];
+ uspertick = data[SpecialMicroSecondsPerTick];
+ if (data[SpecialSampleSize] != sizeof(data[0]))
+ error(0, "only sample size 4 supported\n");
+ delta = data[SpecialTotalTicks] - data[SpecialOutsideTicks];
+ print("total: %lud in kernel text: %lud outside kernel text: %lud\n",
+ data[0], delta, data[1]);
+ if(data[0] == 0)
+ exits(0);
+ if (!textsym(&s, 0))
+ error(0, "no text symbols");
+ tbase = s.value & ~(mach->pgsize-1); /* align down to page */
+ print("KTZERO %.8lux\n", tbase);
+ /*
+ * Accumulate counts for each function
+ */
+ cp = 0;
+ k = 0;
+ for (i = 0, j = (s.value-tbase)/pcres+SpecialMax; j < n; i++) {
+ name = s.name; /* save name */
+ if (!textsym(&s, i)) /* get next symbol */
+ break;
+ sum = 0;
+ while (j < n && j*pcres < s.value-tbase)
+ sum += data[j++];
+ if (sum) {
+ cp = realloc(cp, (k+1)*sizeof(struct COUNTER));
+ if (cp == 0)
+ error(1, "realloc");
+ cp[k].name = name;
+ cp[k].time = sum;
+ k++;
+ }
+ }
+ if (!k)
+ error(0, "no counts");
+ cp[k].time = 0; /* "etext" can take no time */
+ /*
+ * Sort by time and print
+ */
+ qsort(cp, k, sizeof(struct COUNTER), compar);
+ Binit(&outbuf, 1, OWRITE);
+ Bprint(&outbuf, "ms %% sym\n");
+ while(--k>=0)
+ Bprint(&outbuf, "%lud\t%3lud.%d\t%s\n",
+ tickstoms(cp[k].time),
+ 100*cp[k].time/delta,
+ (1000*cp[k].time/delta)%10,
+ cp[k].name);
+ exits(0);
+}
diff --git a/utils/kprof/mkfile b/utils/kprof/mkfile
new file mode 100644
index 00000000..b8f53cd3
--- /dev/null
+++ b/utils/kprof/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=kprof
+
+OFILES= kprof.$O\
+
+LIBS= mach bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/ksize/ksize.c b/utils/ksize/ksize.c
new file mode 100644
index 00000000..1bb84701
--- /dev/null
+++ b/utils/ksize/ksize.c
@@ -0,0 +1,49 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+size(char *file)
+{
+ int fd;
+ Fhdr f;
+
+ if((fd = open(file, OREAD)) < 0){
+ fprint(2, "size: ");
+ perror(file);
+ return 1;
+ }
+ if(crackhdr(fd, &f)) {
+ print("%ldt + %ldd + %ldb = %ld\t%s\n", f.txtsz, f.datsz,
+ f.bsssz, f.txtsz+f.datsz+f.bsssz, file);
+ close(fd);
+ return 0;
+ }
+
+ /* get error string from libmach and display */
+ fprint(2, "ksize: %s %r\n", file);
+ close(fd);
+ return 1;
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *err;
+ int i;
+
+ ARGBEGIN {
+ default:
+ fprint(2, "usage: ksize [a.out ...]\n");
+ exits("usage");
+ } ARGEND;
+
+ err = 0;
+ if(argc == 0)
+ if(size("8.out"))
+ err = "error";
+ for(i=0; i<argc; i++)
+ if(size(argv[i]))
+ err = "error";
+ exits(err);
+}
diff --git a/utils/ksize/mkfile b/utils/ksize/mkfile
new file mode 100644
index 00000000..e4d9a113
--- /dev/null
+++ b/utils/ksize/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=ksize
+
+OFILES= ksize.$O\
+
+LIBS= mach bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/kstrip/kstrip.c b/utils/kstrip/kstrip.c
new file mode 100644
index 00000000..2fab8bea
--- /dev/null
+++ b/utils/kstrip/kstrip.c
@@ -0,0 +1,166 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+static void
+error(char* fmt, ...)
+{
+ va_list arg;
+
+ fprint(2, "kstrip: ");
+ va_start(arg, fmt);
+ vfprint(2, fmt, arg);
+ va_end(arg);
+ fprint(2, "\n");
+}
+
+static void
+usage(void)
+{
+ error("usage: %s -o ofile file\n\t%s file ...\n", argv0, argv0);
+ exits("usage");
+}
+
+static int
+strip(char* file, char* out)
+{
+ Dir *dir;
+ int fd, i;
+ Fhdr fhdr;
+ Exec *exec;
+ ulong mode;
+ void *data;
+ vlong length;
+
+ if((fd = open(file, OREAD)) < 0){
+ error("%s: open: %r", file);
+ return 1;
+ }
+
+ if(!crackhdr(fd, &fhdr)){
+ error("%s: %r", file);
+ close(fd);
+ return 1;
+ }
+ for(i = MIN_MAGIC; i <= MAX_MAGIC; i++){
+ if(fhdr.magic == _MAGIC(0, i) || fhdr.magic == _MAGIC(HDR_MAGIC, i))
+ break;
+ }
+ if(i > MAX_MAGIC){
+ error("%s: not a recognizable binary", file);
+ close(fd);
+ return 1;
+ }
+
+ if((dir = dirfstat(fd)) == nil){
+ error("%s: stat: %r", file);
+ close(fd);
+ return 1;
+ }
+
+ length = fhdr.datoff+fhdr.datsz;
+ if(length == dir->length){
+ if(out == nil){ /* nothing to do */
+ error("%s: already stripped", file);
+ free(dir);
+ close(fd);
+ return 0;
+ }
+ }
+ if(length > dir->length){
+ error("%s: strange length", file);
+ close(fd);
+ free(dir);
+ return 1;
+ }
+
+ mode = dir->mode;
+ free(dir);
+
+ if((data = malloc(length)) == nil){
+ error("%s: out of memory", file);
+ close(fd);
+ return 1;
+ }
+ seek(fd, 0, 0);
+ if(read(fd, data, length) != length){
+ error("%s: read error: %r", file);
+ close(fd);
+ free(data);
+ return 1;
+ }
+ close(fd);
+
+ exec = data;
+ exec->syms = 0;
+ exec->spsz = 0;
+ exec->pcsz = 0;
+
+ if(out == nil){
+ if(remove(file) < 0) {
+ error("%s: can't remove: %r", file);
+ free(data);
+ return 1;
+ }
+ out = file;
+ }
+ if((fd = create(out, OWRITE, mode)) < 0){
+ error("%s: can't create: %r", out);
+ free(data);
+ return 1;
+ }
+ if(write(fd, data, length) != length){
+ error("%s: write error: %r", out);
+ close(fd);
+ free(data);
+ return 1;
+ }
+ close(fd);
+ free(data);
+
+ return 0;
+}
+
+void
+main(int argc, char* argv[])
+{
+ int r;
+ char *p;
+
+ p = nil;
+
+ ARGBEGIN{
+ default:
+ usage();
+ break;
+ case 'o':
+ p = ARGF();
+ if(p == nil)
+ usage();
+ break;
+ }ARGEND;
+
+ switch(argc){
+ case 0:
+ usage();
+ return;
+ case 1:
+ if(p != nil){
+ r = strip(*argv, p);
+ break;
+ }
+ /*FALLTHROUGH*/
+ default:
+ r = 0;
+ while(argc > 0){
+ r |= strip(*argv, nil);
+ argc--;
+ argv++;
+ }
+ break;
+ }
+
+ if(r)
+ exits("error");
+ exits(0);
+}
diff --git a/utils/kstrip/mkfile b/utils/kstrip/mkfile
new file mode 100644
index 00000000..c88945ac
--- /dev/null
+++ b/utils/kstrip/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=kstrip
+
+OFILES= kstrip.$O\
+
+LIBS= mach bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/lib/rcmain b/utils/lib/rcmain
new file mode 100644
index 00000000..f74190ca
--- /dev/null
+++ b/utils/lib/rcmain
@@ -0,0 +1,29 @@
+# rcmain: 9pm version
+if(~ $#home 0) home=/
+if(~ $#ifs 0) ifs='
+'
+switch($#prompt){
+case 0
+case 1
+ prompt=('% ' ' ')
+}
+if(~ $rcname v.out) prompt=('broken! ' ' ')
+if(! ~ $#cflag 0){
+ if(flag l && test -r $home/lib/profile) . $home/lib/profile
+ status=''
+ eval $cflag
+}
+if not if(flag i){
+ if(flag l && test -r $home/lib/profile) . $home/lib/profile
+ status=''
+ if(! ~ $#* 0) . $*
+ if not . -i 'stdin$'
+}
+if not {
+ if(~ $#* 0) . 'stdin$'
+ if not{
+ status=''
+ . $*
+ }
+}
+exit $status
diff --git a/utils/lib/yaccpar b/utils/lib/yaccpar
new file mode 100644
index 00000000..efc1da06
--- /dev/null
+++ b/utils/lib/yaccpar
@@ -0,0 +1,241 @@
+#define YYFLAG -1000
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+
+#ifdef yydebug
+#include "y.debug"
+#else
+#define yydebug 0
+char* yytoknames[1]; /* for debugging */
+char* yystates[1]; /* for debugging */
+#endif
+
+/* parser for yacc output */
+
+int yynerrs = 0; /* number of errors */
+int yyerrflag = 0; /* error recovery flag */
+
+extern int fprint(int, char*, ...);
+extern int sprint(char*, char*, ...);
+
+char*
+yytokname(int yyc)
+{
+ static char x[10];
+
+ if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
+ if(yytoknames[yyc-1])
+ return yytoknames[yyc-1];
+ sprint(x, "<%d>", yyc);
+ return x;
+}
+
+char*
+yystatname(int yys)
+{
+ static char x[10];
+
+ if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
+ if(yystates[yys])
+ return yystates[yys];
+ sprint(x, "<%d>\n", yys);
+ return x;
+}
+
+long
+yylex1(void)
+{
+ long yychar;
+ long *t3p;
+ int c;
+
+ yychar = yylex();
+ if(yychar <= 0) {
+ c = yytok1[0];
+ goto out;
+ }
+ if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
+ c = yytok1[yychar];
+ goto out;
+ }
+ if(yychar >= YYPRIVATE)
+ if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
+ c = yytok2[yychar-YYPRIVATE];
+ goto out;
+ }
+ for(t3p=yytok3;; t3p+=2) {
+ c = t3p[0];
+ if(c == yychar) {
+ c = t3p[1];
+ goto out;
+ }
+ if(c == 0)
+ break;
+ }
+ c = 0;
+
+out:
+ if(c == 0)
+ c = yytok2[1]; /* unknown char */
+ if(yydebug >= 3)
+ fprint(2, "lex %.4lux %s\n", yychar, yytokname(c));
+ return c;
+}
+
+int
+yyparse(void)
+{
+ struct
+ {
+ YYSTYPE yyv;
+ int yys;
+ } yys[YYMAXDEPTH], *yyp, *yypt;
+ short *yyxi;
+ int yyj, yym, yystate, yyn, yyg;
+ long yychar;
+ YYSTYPE save1, save2;
+ int save3, save4;
+
+ save1 = yylval;
+ save2 = yyval;
+ save3 = yynerrs;
+ save4 = yyerrflag;
+
+ yystate = 0;
+ yychar = -1;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yyp = &yys[-1];
+ goto yystack;
+
+ret0:
+ yyn = 0;
+ goto ret;
+
+ret1:
+ yyn = 1;
+ goto ret;
+
+ret:
+ yylval = save1;
+ yyval = save2;
+ yynerrs = save3;
+ yyerrflag = save4;
+ return yyn;
+
+yystack:
+ /* put a state and value onto the stack */
+ if(yydebug >= 4)
+ fprint(2, "char %s in %s", yytokname(yychar), yystatname(yystate));
+
+ yyp++;
+ if(yyp >= &yys[YYMAXDEPTH]) {
+ yyerror("yacc stack overflow");
+ goto ret1;
+ }
+ yyp->yys = yystate;
+ yyp->yyv = yyval;
+
+yynewstate:
+ yyn = yypact[yystate];
+ if(yyn <= YYFLAG)
+ goto yydefault; /* simple state */
+ if(yychar < 0)
+ yychar = yylex1();
+ yyn += yychar;
+ if(yyn < 0 || yyn >= YYLAST)
+ goto yydefault;
+ yyn = yyact[yyn];
+ if(yychk[yyn] == yychar) { /* valid shift */
+ yychar = -1;
+ yyval = yylval;
+ yystate = yyn;
+ if(yyerrflag > 0)
+ yyerrflag--;
+ goto yystack;
+ }
+
+yydefault:
+ /* default state action */
+ yyn = yydef[yystate];
+ if(yyn == -2) {
+ if(yychar < 0)
+ yychar = yylex1();
+
+ /* look through exception table */
+ for(yyxi=yyexca;; yyxi+=2)
+ if(yyxi[0] == -1 && yyxi[1] == yystate)
+ break;
+ for(yyxi += 2;; yyxi += 2) {
+ yyn = yyxi[0];
+ if(yyn < 0 || yyn == yychar)
+ break;
+ }
+ yyn = yyxi[1];
+ if(yyn < 0)
+ goto ret0;
+ }
+ if(yyn == 0) {
+ /* error ... attempt to resume parsing */
+ switch(yyerrflag) {
+ case 0: /* brand new error */
+ yyerror("syntax error");
+ yynerrs++;
+ if(yydebug >= 1) {
+ fprint(2, "%s", yystatname(yystate));
+ fprint(2, "saw %s\n", yytokname(yychar));
+ }
+
+ case 1:
+ case 2: /* incompletely recovered error ... try again */
+ yyerrflag = 3;
+
+ /* find a state where "error" is a legal shift action */
+ while(yyp >= yys) {
+ yyn = yypact[yyp->yys] + YYERRCODE;
+ if(yyn >= 0 && yyn < YYLAST) {
+ yystate = yyact[yyn]; /* simulate a shift of "error" */
+ if(yychk[yystate] == YYERRCODE)
+ goto yystack;
+ }
+
+ /* the current yyp has no shift onn "error", pop stack */
+ if(yydebug >= 2)
+ fprint(2, "error recovery pops state %d, uncovers %d\n",
+ yyp->yys, (yyp-1)->yys );
+ yyp--;
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1;
+
+ case 3: /* no shift yet; clobber input char */
+ if(yydebug >= 2)
+ fprint(2, "error recovery discards %s\n", yytokname(yychar));
+ if(yychar == YYEOFCODE)
+ goto ret1;
+ yychar = -1;
+ goto yynewstate; /* try again in the same state */
+ }
+ }
+
+ /* reduction by production yyn */
+ if(yydebug >= 2)
+ fprint(2, "reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+ yypt = yyp;
+ yyp -= yyr2[yyn];
+ yyval = (yyp+1)->yyv;
+ yym = yyn;
+
+ /* consult goto table to find next state */
+ yyn = yyr1[yyn];
+ yyg = yypgo[yyn];
+ yyj = yyg + yyp->yys + 1;
+
+ if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+ yystate = yyact[yyg];
+ switch(yym) {
+ $A
+ }
+ goto yystack; /* stack new state and value */
+}
diff --git a/utils/libmach/2.c b/utils/libmach/2.c
new file mode 100644
index 00000000..2b1010f4
--- /dev/null
+++ b/utils/libmach/2.c
@@ -0,0 +1,85 @@
+/*
+ * 68020 definition
+ */
+#include <lib9.h>
+#include "ureg2.h"
+#include <bio.h>
+#include "mach.h"
+
+#define MAXREG 0
+#define MINREG 0
+
+#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x)
+
+#define VO REGOFF(vo) /* vo, 2 bytes */
+#define SR REGOFF(sr) /* sr, 2 bytes */
+#define R0 REGOFF(r0)
+#define PC REGOFF(pc)
+#define DBMAGIC REGOFF(magic)
+#define SP REGOFF(usp)
+
+#define REGSIZE (R0+4)
+#define FCTL(x) (REGSIZE+(x)*4)
+#define FREG(x) (FCTL(3)+(x)*12)
+#define FPREGSIZE (11*12)
+
+/*
+ * 68020 register set
+ */
+Reglist m68020reglist[] = {
+ {"VO", VO, RINT, 'x'},
+ {"SR", SR, RINT, 'x'},
+ {"MAGIC", DBMAGIC, RINT, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"A7", SP, RINT, 'X'},
+ {"KSP", REGOFF(sp), RINT, 'X'},
+ {"A6", REGOFF(a6), RINT, 'X'},
+ {"A5", REGOFF(a5), RINT, 'X'},
+ {"A4", REGOFF(a4), RINT, 'X'},
+ {"A3", REGOFF(a3), RINT, 'X'},
+ {"A2", REGOFF(a2), RINT, 'X'},
+ {"A1", REGOFF(a1), RINT, 'X'},
+ {"A0", REGOFF(a0), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ {"R0", REGOFF(r0), RINT, 'X'},
+ {"FPCR", FCTL(0), RFLT, 'X'},
+ {"FPSR", FCTL(1), RFLT, 'X'},
+ {"FPIAR", FCTL(2), RFLT, 'X'},
+ {"F0", FREG(0), RFLT, '8'},
+ {"F1", FREG(1), RFLT, '8'},
+ {"F2", FREG(2), RFLT, '8'},
+ {"F3", FREG(3), RFLT, '8'},
+ {"F4", FREG(4), RFLT, '8'},
+ {"F5", FREG(5), RFLT, '8'},
+ {"F6", FREG(6), RFLT, '8'},
+ {"F7", FREG(7), RFLT, '8'},
+ {0}
+};
+
+Mach m68020 =
+{
+ "68020",
+ M68020, /* machine type */
+ m68020reglist, /* register list */
+ REGSIZE, /* number of bytes in reg set */
+ FPREGSIZE, /* number of bytes in fp reg set */
+ "PC",
+ "A7",
+ 0, /* link register */
+ "a6base", /* static base register name */
+ 0, /* value */
+ 0x2000, /* page size */
+ 0x80000000, /* kernel base */
+ 0, /* kernel text mask */
+ 2, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/2db.c b/utils/libmach/2db.c
new file mode 100644
index 00000000..5aa61fd3
--- /dev/null
+++ b/utils/libmach/2db.c
@@ -0,0 +1,2084 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+/*
+ * 68020-specific debugger interface
+ */
+
+static char *m68020excep(Map*, Rgetter);
+
+static int m68020foll(Map*, ulong, Rgetter, ulong*);
+static int m68020inst(Map*, ulong, char, char*, int);
+static int m68020das(Map*, ulong, char*, int);
+static int m68020instlen(Map*, ulong);
+
+Machdata m68020mach =
+{
+ {0x48,0x48,0,0}, /* break point #0 instr. */
+ 2, /* size of break point instr. */
+
+ beswab, /* convert short to local byte order */
+ beswal, /* convert long to local byte order */
+ beswav, /* convert vlong to local byte order */
+ cisctrace, /* C traceback */
+ ciscframe, /* frame finder */
+ m68020excep, /* print exception */
+ 0, /* breakpoint fixup */
+ beieeesftos,
+ beieeedftos,
+ m68020foll, /* follow-set calculation */
+ m68020inst, /* print instruction */
+ m68020das, /* dissembler */
+ m68020instlen, /* instruction size */
+};
+
+/*
+ * 68020 exception frames
+ */
+
+#define BPTTRAP 4 /* breakpoint gives illegal inst */
+
+static char * excep[] = {
+ 0, /* 0 */
+ 0, /* 1 */
+ "bus error", /* 2 */
+ "address error", /* 3 */
+ "illegal instruction", /* 4 */
+ "zero divide", /* 5 */
+ "CHK", /* 6 */
+ "TRAP", /* 7 */
+ "privilege violation", /* 8 */
+ "Trace", /* 9 */
+ "line 1010", /* 10 */
+ "line 1011", /* 11 */
+ 0, /* 12 */
+ "coprocessor protocol violation", /* 13 */
+ 0,0,0,0,0,0,0,0,0,0, /* 14-23 */
+ "spurious", /* 24 */
+ "incon", /* 25 */
+ "tac", /* 26 */
+ "auto 3", /* 27 */
+ "clock", /* 28 */
+ "auto 5", /* 29 */
+ "parity", /* 30 */
+ "mouse", /* 31 */
+ "system call", /* 32 */
+ "system call 1", /* 33 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 34-47 */
+ "FPCP branch", /* 48 */
+ "FPCP inexact", /* 49 */
+ "FPCP zero div", /* 50 */
+ "FPCP underflow", /* 51 */
+ "FPCP operand err", /* 52 */
+ "FPCP overflow", /* 53 */
+ "FPCP signal NAN", /* 54 */
+};
+
+static int m68020vec;
+static
+struct ftype{
+ short fmt;
+ short len;
+ char *name;
+} ftype[] = { /* section 6.5.7 page 6-24 */
+ { 0, 4*2, "Short Format" },
+ { 1, 4*2, "Throwaway" },
+ { 2, 6*2, "Instruction Exception" },
+ { 3, 6*2, "MC68040 Floating Point Exception" },
+ { 8, 29*2, "MC68010 Bus Fault" },
+ { 7, 30*2, "MC68040 Bus Fault" },
+ { 9, 10*2, "Coprocessor mid-Instruction" },
+ { 10, 16*2, "MC68020 Short Bus Fault" },
+ { 11, 46*2, "MC68020 Long Bus Fault" },
+ { 0, 0, 0 }
+};
+
+static int
+m68020ufix(Map *map)
+{
+ struct ftype *ft;
+ int i, size, vec;
+ ulong efl[2], stktop;
+ uchar *ef=(uchar*)efl;
+ long l;
+ short fvo;
+
+ /* The kernel proc pointer on a 68020 is always
+ * at #8xxxxxxx; on the 68040 NeXT, the address
+ * is always #04xxxxxx. the sun3 port at sydney
+ * uses 0xf8xxxxxx to 0xffxxxxxx.
+ */
+ m68020vec = 0;
+
+ if (get4(map, mach->kbase, (&l)) < 0)
+ return -1;
+ if ((l&0xfc000000) == 0x04000000) /* if NeXT */
+ size = 30*2;
+ else
+ size = 46*2; /* 68020 */
+ USED(size); /* kept because it might be re-used later */
+
+ stktop = mach->kbase+mach->pgsize;
+ for(i=3; i<100; i++){
+ if (get1(map, stktop-i*4, (uchar*)&l, 4)< 0)
+ return -1;
+
+ if(machdata->swal(l) == 0xBADC0C0A){
+ if (get1(map, stktop-(i-1)*4, (uchar *)&efl[0], 4) < 0)
+ return -1;
+ if (get1(map, stktop-(i-2)*4, (uchar *)&efl[1], 4) < 0)
+ return -1;
+ fvo = (ef[6]<<8)|ef[7];
+ vec = fvo & 0xfff;
+ vec >>= 2;
+ if(vec >= 256)
+ continue;
+
+ for(ft=ftype; ft->name; ft++) {
+ if(ft->fmt == ((fvo>>12) & 0xF)){
+ m68020vec = vec;
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+ return -1;
+}
+
+static char *
+m68020excep(Map *map, Rgetter rget)
+{
+ ulong pc;
+ uchar buf[4];
+
+ if (m68020ufix(map) < 0)
+ return "bad exception frame";
+
+ if(excep[m68020vec] == 0)
+ return "bad exeception type";
+
+ if(m68020vec == BPTTRAP) {
+ pc = (*rget)(map, "PC");
+ if (get1(map, pc, buf, machdata->bpsize) > 0)
+ if(memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
+ return "breakpoint";
+ }
+ return excep[m68020vec];
+}
+ /* 68020 Disassembler and related functions */
+/*
+not supported: cpBcc, cpDBcc, cpGEN, cpScc, cpTRAPcc, cpRESTORE, cpSAVE
+
+opcode: 1 1 1 1 1 1
+ 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+%y - register number x x x
+%f - trap vector x x x
+%e - destination eff addr x x x x x x
+%p - conditional predicate x x x x x x
+%s - size code x x
+%C - cache code x x
+%E - source eff addr. x x x x x x
+%d - direction bit x
+%c - condition code x x x x
+%x - register number x x x
+%b - shift count x x x
+%q - daffy 3-bit quick operand or shift count x x x
+%i - immediate operand <varies>
+%t - offset(PC) <varies>
+
+word 1: 1 1 1 1 1 1
+ 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+%a - register number x x x
+%w - bit field width x x x x x
+%L - MMU function code (SFC/DFC/D%a/#[0-3]) x x x x x
+%P - conditional predicate x x x x x x
+%k - k factor x x x x x x x
+%m - register mask x x x x x x x x
+%N - control register id x x x x x x x x x x x x
+%j - (Dq != Dr) ? Dq:Dr : Dr x x x x x x
+%K - dynamic k register x x x
+%h - register number x x x
+%I - MMU function code mask x x x x
+%o - bit field offset x x x x x
+%u - register number x x x
+%D - float dest reg x x x
+%F - (fdr==fsr) ? "F%D" :"F%B,F%D" x x x x x x
+%S - float source type x x x
+%B - float source register x x x
+%Z - ATC level number x x x
+%H - MMU register x x x x
+%r - register type/number x x x x
+
+word 2: 1 1 1 1 1 1
+ 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+%A - register number x x x
+%U - register number x x x
+%R - register type,number x x x x
+
+-----------------------------------------------------------------------------
+
+%a - register [word 1: 0-2]
+%c - condition code [opcode: 8-11]
+%d - direction [opcode: 8]
+%e - destination effective address [opcode: 0-5]
+%f - trap vector [opcode: 0-3]
+%h - register [word 1: 5-7]
+%i - immediate operand (1, 2, or 4 bytes)
+%j - Dq:Dr if Dq != Dr; else Dr => Dr [word 1: 0-2] Dq [word 1: 12-14]
+%k - k factor [word 1: 0-6]
+%m - register mask [word 1: 0-7]
+%o - bit field offset [word 1: 6-10]
+%p - conditional predicate [opcode: 0-5]
+%q - daffy 3-bit quick operand [opcode: 9-11]
+%r - register type, [word 1: 15], register [word 1: 12-14]
+%s - size [opcode: 6-7]
+%t - offset beyond pc (text address) (2 or 4 bytes)
+%u - register [word 1: 6-8]
+%w - bit field width [word 1: 0-4]
+%x - register [opcode: 9-11]
+%y - register [opcode: 0-2]
+%A - register [word 2: 0-2]
+%B - float source register [word 1: 10-12]
+%C - cache identifier [opcode: 6-7] (IC, DC, or BC)
+%D - float dest reg [word 1: 7-9]
+%E - dest effective address [opcode: 6-11]
+%F - float dest reg == float src reg => "F%D"; else "F%B,F%D"
+%H - MMU reg [word 1: 10-13] (see above & p 4-53/54)
+%I - MMU function code mask [word 1: 5-8]
+%K - dynamic k factor register [word 1: 4-6]
+%L - MMU function code [word 1: 0-4] (SFC, DFC, D%a, or #[0-3])
+%N - control register [word 1: 0-11]
+%P - conditional predicate [word 1: 0-5]
+%R - register type, [word 2: 15], register [word 2: 12-14]
+%S - float source type code [word 1: 10-12]
+%U - register [word 2: 6-8]
+%Z - ATC level number [word 1: 10-12]
+%1 - Special case: EA as second operand
+*/
+ /* Operand classes */
+enum {
+ EAPI = 1, /* extended address: pre decrement only */
+ EACA, /* extended address: control alterable */
+ EACAD, /* extended address: control alterable or Dreg */
+ EACAPI, /* extended address: control alterable or post-incr */
+ EACAPD, /* extended address: control alterable or pre-decr */
+ EAMA, /* extended address: memory alterable */
+ EADA, /* extended address: data alterable */
+ EAA, /* extended address: alterable */
+ EAC, /* extended address: control addressing */
+ EACPI, /* extended address: control addressing or post-incr */
+ EACD, /* extended address: control addressing or Dreg */
+ EAD, /* extended address: data addressing */
+ EAM, /* extended address: memory addressing */
+ EAM_B, /* EAM with byte immediate data */
+ EADI, /* extended address: data addressing or immediate */
+ EADI_L, /* EADI with long immediate data */
+ EADI_W, /* EADI with word immediate data */
+ EAALL, /* extended address: all modes */
+ EAALL_L, /* EAALL with long immediate data */
+ EAALL_W, /* EAALL with word immediate data */
+ EAALL_B, /* EAALL with byte immediate date */
+ /* special codes not directly used for validation */
+ EAFLT, /* extended address: EADI for B, W, L, or S; else EAM */
+ EADDA, /* destination extended address: EADA */
+ BREAC, /* EAC operand for JMP or CALL */
+ OP8, /* low 8 bits of op word */
+ I8, /* low 8-bits of first extension word */
+ I16, /* 16 bits in first extension word */
+ I32, /* 32 bits in first and second extension words */
+ IV, /* 8, 16 or 32 bit data in first & 2nd extension words */
+ C16, /* CAS2 16 bit immediate with bits 9-11 & 3-5 zero */
+ BR8, /* 8 bits in op word or 16 or 32 bits in extension words
+ branch instruction format (p. 2-25) */
+ BR16, /* 16-bit branch displacement */
+ BR32, /* 32-bit branch displacement */
+ STACK, /* return PC on stack - follow set only */
+};
+ /* validation bit masks for various EA classes */
+enum {
+ Dn = 0x0001, /* Data register */
+ An = 0x0002, /* Address register */
+ Ind = 0x0004, /* Address register indirect */
+ Pinc = 0x0008, /* Address register indirect post-increment */
+ Pdec = 0x0010, /* Address register indirect pre-decrement */
+ Bdisp = 0x0020, /* Base/Displacement in all its forms */
+ PCrel = 0x0040, /* PC relative addressing in all its forms */
+ Imm = 0x0080, /* Immediate data */
+ Abs = 0x0100, /* Absolute */
+};
+ /* EA validation table indexed by operand class number */
+
+static short validea[] =
+{
+ 0, /* none */
+ Pdec, /* EAPI */
+ Abs|Bdisp|Ind, /* EACA */
+ Abs|Bdisp|Ind|Dn, /* EACAD */
+ Abs|Bdisp|Pinc|Ind, /* EACAPI */
+ Abs|Bdisp|Pdec|Ind, /* EACAPD */
+ Abs|Bdisp|Pdec|Pinc|Ind, /* EAMA */
+ Abs|Bdisp|Pdec|Pinc|Ind|Dn, /* EADA */
+ Abs|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAA */
+ Abs|PCrel|Bdisp|Ind, /* EAC */
+ Abs|PCrel|Bdisp|Pinc|Ind, /* EACPI */
+ Abs|PCrel|Bdisp|Ind|Dn, /* EACD */
+ Abs|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EAD */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind, /* EAM */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind, /* EAM_B */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI_L */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI_W */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_L */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_W */
+ Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_B */
+};
+ /* EA types */
+enum
+{
+ Dreg, /* Dn */
+ Areg, /* An */
+ AInd, /* (An) */
+ APdec, /* -(An) */
+ APinc, /* (An)+ */
+ ADisp, /* Displacement beyond (An) */
+ BXD, /* Base, Index, Displacement */
+ PDisp, /* Displacement beyond PC */
+ PXD, /* PC, Index, Displacement */
+ ABS, /* absolute */
+ IMM, /* immediate */
+ IREAL, /* single precision real immediate */
+ IEXT, /* extended precision real immediate */
+ IPACK, /* packed real immediate */
+ IDBL, /* double precision real immediate */
+};
+
+typedef struct optable Optable;
+typedef struct operand Operand;
+typedef struct inst Inst;
+
+struct optable
+{
+ ushort opcode;
+ ushort mask0;
+ ushort op2;
+ ushort mask1;
+ char opdata[2];
+ char *format;
+};
+
+struct operand
+{
+ int eatype;
+ short ext;
+ union {
+ long immediate; /* sign-extended integer byte/word/long */
+ struct { /* index mode displacements */
+ long disp;
+ long outer;
+ } s0;
+ char floater[24]; /* floating point immediates */
+ } u0;
+};
+
+struct inst
+{
+ int n; /* # bytes in instruction */
+ ulong addr; /* addr of start of instruction */
+ ushort raw[4+12]; /* longest instruction: 24 byte packed immediate */
+ Operand and[2];
+ char *end; /* end of print buffer */
+ char *curr; /* current fill point in buffer */
+ char *errmsg;
+};
+ /* class 0: bit field, MOVEP & immediate instructions */
+static Optable t0[] = {
+{ 0x003c, 0xffff, 0x0000, 0xff00, {I8}, "ORB %i,CCR" },
+{ 0x007c, 0xffff, 0x0000, 0x0000, {I16}, "ORW %i,SR" },
+{ 0x023c, 0xffff, 0x0000, 0xff00, {I8}, "ANDB %i,CCR" },
+{ 0x027c, 0xffff, 0x0000, 0x0000, {I16}, "ANDW %i,SR" },
+{ 0x0a3c, 0xffff, 0x0000, 0xff00, {I8}, "EORB %i,CCR" },
+{ 0x0a7c, 0xffff, 0x0000, 0x0000, {I16}, "EORW %i,SR" },
+{ 0x0cfc, 0xffff, 0x0000, 0x0000, {C16,C16}, "CAS2W R%a:R%A,R%u:R%U,(%r):(%R)"} ,
+{ 0x0efc, 0xffff, 0x0000, 0x0000, {C16,C16}, "CAS2L R%a:R%A,R%u:R%U,(%r):(%R)"} ,
+
+{ 0x06c0, 0xfff8, 0x0000, 0x0000, {0}, "RTM R%y" },
+{ 0x06c8, 0xfff8, 0x0000, 0x0000, {0}, "RTM A%y" },
+{ 0x0800, 0xfff8, 0x0000, 0x0000, {I16}, "BTSTL %i,R%y" },
+{ 0x0840, 0xfff8, 0x0000, 0x0000, {I16}, "BCHGL %i,R%y" },
+{ 0x0880, 0xfff8, 0x0000, 0x0000, {I16}, "BCLRL %i,R%y" },
+
+{ 0x00c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2B %e,%r" },
+{ 0x00c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2B %e,%r" },
+{ 0x02c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2W %e,%r" },
+{ 0x02c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2W %e,%r" },
+{ 0x04c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2L %e,%r" },
+{ 0x04c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2L %e,%r" },
+{ 0x06c0, 0xffc0, 0x0000, 0x0000, {I16, BREAC}, "CALLM %i,%e" },
+{ 0x0800, 0xffc0, 0x0000, 0x0000, {I16, EAD}, "BTSTB %i,%e" },
+{ 0x0840, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BCHG %i,%e" },
+{ 0x0880, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BCLR %i,%e" },
+{ 0x08c0, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BSET %i,%e" },
+{ 0x0ac0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASB R%a,R%u,%e" },
+{ 0x0cc0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASW R%a,R%u,%e" },
+{ 0x0ec0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASL R%a,R%u,%e" },
+
+{ 0x0000, 0xff00, 0x0000, 0x0000, {IV, EADA}, "OR%s %i,%e" },
+{ 0x0200, 0xff00, 0x0000, 0x0000, {IV, EADA}, "AND%s %i,%e" },
+{ 0x0400, 0xff00, 0x0000, 0x0000, {IV, EADA}, "SUB%s %i,%e" },
+{ 0x0600, 0xff00, 0x0000, 0x0000, {IV, EADA}, "ADD%s %i,%e" },
+{ 0x0a00, 0xff00, 0x0000, 0x0000, {IV, EADA}, "EOR%s %i,%e" },
+{ 0x0c00, 0xff00, 0x0000, 0x0000, {IV, EAD}, "CMP%s %i,%e" },
+{ 0x0e00, 0xff00, 0x0000, 0x0800, {EAMA}, "MOVES%s %e,%r" },
+{ 0x0e00, 0xff00, 0x0800, 0x0800, {EAMA}, "MOVES%s %r,%e" },
+
+{ 0x0108, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPW (%i,A%y),R%x" },
+{ 0x0148, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPL (%i,A%y),R%x" },
+{ 0x0188, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPW R%x,(%i,A%y)" },
+{ 0x01c8, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPL R%x,(%i,A%y)" },
+{ 0x0100, 0xf1f8, 0x0000, 0x0000, {0}, "BTSTL R%x,R%y" },
+{ 0x0140, 0xf1f8, 0x0000, 0x0000, {0}, "BCHGL R%x,R%y" },
+{ 0x0180, 0xf1f8, 0x0000, 0x0000, {0}, "BCLRL R%x,R%y" },
+{ 0x01c0, 0xf1f8, 0x0000, 0x0000, {0}, "BSET R%x,R%y" },
+
+{ 0x0100, 0xf1c0, 0x0000, 0x0000, {EAM_B}, "BTSTB R%x,%e" },
+{ 0x0140, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BCHG R%x,%e" },
+{ 0x0180, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BCLR R%x,%e" },
+{ 0x01c0, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BSET R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 1: move byte */
+static Optable t1[] = {
+{ 0x1000, 0xf000, 0x0000, 0x0000, {EAALL_B,EADDA},"MOVB %e,%E" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 2: move long */
+static Optable t2[] = {
+{ 0x2040, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "MOVL %e,A%x" },
+
+{ 0x2000, 0xf000, 0x0000, 0x0000, {EAALL_L,EADDA},"MOVL %e,%E" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 3: move word */
+static Optable t3[] = {
+{ 0x3040, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "MOVW %e,A%x" },
+
+{ 0x3000, 0xf000, 0x0000, 0x0000, {EAALL_W,EADDA},"MOVW %e,%E" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 4: miscellaneous */
+static Optable t4[] = {
+{ 0x4e75, 0xffff, 0x0000, 0x0000, {STACK}, "RTS" },
+{ 0x4e77, 0xffff, 0x0000, 0x0000, {STACK}, "RTR" },
+{ 0x4afc, 0xffff, 0x0000, 0x0000, {0}, "ILLEGAL" },
+{ 0x4e71, 0xffff, 0x0000, 0x0000, {0}, "NOP" },
+{ 0x4e74, 0xffff, 0x0000, 0x0000, {I16, STACK}, "RTD %i" },
+{ 0x4e76, 0xffff, 0x0000, 0x0000, {0}, "TRAPV" },
+{ 0x4e70, 0xffff, 0x0000, 0x0000, {0}, "RESET" },
+{ 0x4e72, 0xffff, 0x0000, 0x0000, {I16}, "STOP %i" },
+{ 0x4e73, 0xffff, 0x0000, 0x0000, {0}, "RTE" },
+{ 0x4e7a, 0xffff, 0x0000, 0x0000, {I16}, "MOVEL %N,%r" },
+{ 0x4e7b, 0xffff, 0x0000, 0x0000, {I16}, "MOVEL %r,%N" },
+
+{ 0x4808, 0xfff8, 0x0000, 0x0000, {I32}, "LINKL A%y,%i" },
+{ 0x4840, 0xfff8, 0x0000, 0x0000, {0}, "SWAPW R%y" },
+{ 0x4848, 0xfff8, 0x0000, 0x0000, {0}, "BKPT #%y" },
+{ 0x4880, 0xfff8, 0x0000, 0x0000, {0}, "EXTW R%y" },
+{ 0x48C0, 0xfff8, 0x0000, 0x0000, {0}, "EXTL R%y" },
+{ 0x49C0, 0xfff8, 0x0000, 0x0000, {0}, "EXTBL R%y" },
+{ 0x4e50, 0xfff8, 0x0000, 0x0000, {I16}, "LINKW A%y,%i" },
+{ 0x4e58, 0xfff8, 0x0000, 0x0000, {0}, "UNLK A%y" },
+{ 0x4e60, 0xfff8, 0x0000, 0x0000, {0}, "MOVEL (A%y),USP" },
+{ 0x4e68, 0xfff8, 0x0000, 0x0000, {0}, "MOVEL USP,(A%y)" },
+
+{ 0x4e40, 0xfff0, 0x0000, 0x0000, {0}, "SYS %f" },
+
+{ 0x40c0, 0xffc0, 0x0000, 0x0000, {EADA}, "MOVW SR,%e" },
+{ 0x42c0, 0xffc0, 0x0000, 0x0000, {EADA}, "MOVW CCR,%e" },
+{ 0x44c0, 0xffc0, 0x0000, 0x0000, {EADI_W}, "MOVW %e,CCR" },
+{ 0x46c0, 0xffc0, 0x0000, 0x0000, {EADI_W}, "MOVW %e,SR" },
+{ 0x4800, 0xffc0, 0x0000, 0x0000, {EADA}, "NBCDB %e" },
+{ 0x4840, 0xffc0, 0x0000, 0x0000, {EAC}, "PEA %e" },
+{ 0x4880, 0xffc0, 0x0000, 0x0000, {I16, EACAPD},"MOVEMW %i,%e" },
+{ 0x48c0, 0xffc0, 0x0000, 0x0000, {I16, EACAPD},"MOVEML %i,%e" },
+{ 0x4ac0, 0xffc0, 0x0000, 0x0000, {EADA}, "TAS %e" },
+{ 0x4a00, 0xffc0, 0x0000, 0x0000, {EAD}, "TSTB %e" },
+{ 0x4c00, 0xffc0, 0x0000, 0x8ff8, {EADI_L}, "MULUL %e,%r" },
+{ 0x4c00, 0xffc0, 0x0400, 0x8ff8, {EADI_L}, "MULUL %e,R%a:%r" },
+{ 0x4c00, 0xffc0, 0x0800, 0x8ff8, {EADI_L}, "MULSL %e,%r" },
+{ 0x4c00, 0xffc0, 0x0c00, 0x8ff8, {EADI_L}, "MULSL %e,R%a:%r" },
+{ 0x4c40, 0xffc0, 0x0000, 0x8ff8, {EADI_L}, "DIVUL %e,%j" },
+{ 0x4c40, 0xffc0, 0x0400, 0x8ff8, {EADI_L}, "DIVUD %e,%r:R%a" },
+{ 0x4c40, 0xffc0, 0x0800, 0x8ff8, {EADI_L}, "DIVSL %e,%j" },
+{ 0x4c40, 0xffc0, 0x0c00, 0x8ff8, {EADI_L}, "DIVSD %e,%r:R%a" },
+{ 0x4c80, 0xffc0, 0x0000, 0x0000, {I16, EACPI}, "MOVEMW %1,%i" },
+{ 0x4cc0, 0xffc0, 0x0000, 0x0000, {I16, EACPI}, "MOVEML %1,%i" },
+{ 0x4e80, 0xffc0, 0x0000, 0x0000, {BREAC}, "JSR %e" },
+{ 0x4ec0, 0xffc0, 0x0000, 0x0000, {BREAC}, "JMP %e" },
+
+{ 0x4000, 0xff00, 0x0000, 0x0000, {EADA}, "NEGX%s %e" },
+{ 0x4200, 0xff00, 0x0000, 0x0000, {EADA}, "CLR%s %e" },
+{ 0x4400, 0xff00, 0x0000, 0x0000, {EADA}, "NEG%s %e" },
+{ 0x4600, 0xff00, 0x0000, 0x0000, {EADA}, "NOT%s %e" },
+{ 0x4a00, 0xff00, 0x0000, 0x0000, {EAALL}, "TST%s %e" },
+
+{ 0x4180, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "CHKW %e,R%x" },
+{ 0x41c0, 0xf1c0, 0x0000, 0x0000, {EAC}, "LEA %e,A%x" },
+{ 0x4100, 0xf1c0, 0x0000, 0x0000, {EADI_L}, "CHKL %e,R%x" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 5: miscellaneous quick, branch & trap instructions */
+static Optable t5[] = {
+{ 0x5000, 0xf1c0, 0x0000, 0x0000, {EADA}, "ADDB $Q#%q,%e" },
+{ 0x5100, 0xf1c0, 0x0000, 0x0000, {EADA}, "SUBB $Q#%q,%e" },
+
+{ 0x50c8, 0xf1f8, 0x0000, 0x0000, {BR16}, "DB%c R%y,%t" },
+{ 0x51c8, 0xf1f8, 0x0000, 0x0000, {BR16}, "DB%c R%y,%t" },
+
+{ 0x5000, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDB $Q#%q,%e" },
+{ 0x5040, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDW $Q#%q,%e" },
+{ 0x5080, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDL $Q#%q,%e" },
+{ 0x5100, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBB $Q#%q,%e" },
+{ 0x5140, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBW $Q#%q,%e" },
+{ 0x5180, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBL $Q#%q,%e" },
+
+{ 0x50fa, 0xf0ff, 0x0000, 0x0000, {I16}, "TRAP%cW %i" },
+{ 0x50fb, 0xf0ff, 0x0000, 0x0000, {I32}, "TRAP%cL %i" },
+{ 0x50fc, 0xf0ff, 0x0000, 0x0000, {0}, "TRAP%c" },
+
+{ 0x50c0, 0xf0c0, 0x0000, 0x0000, {EADA}, "S%c %e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 6: branch instructions */
+static Optable t6[] = {
+{ 0x6000, 0xff00, 0x0000, 0x0000, {BR8}, "BRA %t" },
+{ 0x6100, 0xff00, 0x0000, 0x0000, {BR8}, "BSR %t" },
+{ 0x6000, 0xf000, 0x0000, 0x0000, {BR8}, "B%c %t" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 7: move quick */
+static Optable t7[] = {
+{ 0x7000, 0xf100, 0x0000, 0x0000, {OP8}, "MOVL $Q%i,R%x" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 8: BCD operations, DIV, and OR instructions */
+static Optable t8[] = {
+{ 0x8100, 0xf1f8, 0x0000, 0x0000, {0}, "SBCDB R%y,R%x" },
+{ 0x8108, 0xf1f8, 0x0000, 0x0000, {0}, "SBCDB -(A%y),-(A%x)" },
+{ 0x8140, 0xf1f8, 0x0000, 0x0000, {I16}, "PACK R%y,R%x,%i" },
+{ 0x8148, 0xf1f8, 0x0000, 0x0000, {I16}, "PACK -(A%y),-(A%x),%i" },
+{ 0x8180, 0xf1f8, 0x0000, 0x0000, {I16}, "UNPK R%y,R%x,%i" },
+{ 0x8188, 0xf1f8, 0x0000, 0x0000, {I16}, "UNPK -(A%y),-(A%x),%i" },
+
+{ 0x80c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "DIVUW %e,R%x" },
+{ 0x81c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "DIVSW %e,R%x" },
+
+{ 0x8000, 0xf100, 0x0000, 0x0000, {EADI}, "OR%s %e,R%x" },
+{ 0x8100, 0xf100, 0x0000, 0x0000, {EAMA}, "OR%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class 9: subtract instruction */
+static Optable t9[] = {
+{ 0x90c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "SUBW %e,A%x" },
+{ 0x91c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "SUBL %e,A%x" },
+
+{ 0x9100, 0xf138, 0x0000, 0x0000, {0}, "SUBX%s R%y,R%x" },
+{ 0x9108, 0xf138, 0x0000, 0x0000, {0}, "SUBX%s -(A%y),-(A%x)" },
+
+{ 0x9000, 0xf100, 0x0000, 0x0000, {EAALL}, "SUB%s %e,R%x" },
+{ 0x9100, 0xf100, 0x0000, 0x0000, {EAMA}, "SUB%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class b: CMP & EOR */
+static Optable tb[] = {
+{ 0xb000, 0xf1c0, 0x0000, 0x0000, {EADI}, "CMPB R%x,%e" },
+{ 0xb040, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "CMPW R%x,%e" },
+{ 0xb080, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "CMPL R%x,%e" },
+{ 0xb0c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "CMPW A%x,%e" },
+{ 0xb1c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "CMPL A%x,%e" },
+
+{ 0xb108, 0xf138, 0x0000, 0x0000, {0}, "CMP%s (A%y)+,(A%x)+" },
+
+{ 0xb100, 0xf100, 0x0000, 0x0000, {EADA}, "EOR%s %e,R%x" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class c: AND, MUL, BCD & Exchange */
+static Optable tc[] = {
+{ 0xc100, 0xf1f8, 0x0000, 0x0000, {0}, "ABCDB R%y,R%x" },
+{ 0xc108, 0xf1f8, 0x0000, 0x0000, {0}, "ABCDB -(A%y),-(A%x)" },
+{ 0xc140, 0xf1f8, 0x0000, 0x0000, {0}, "EXG R%x,R%y" },
+{ 0xc148, 0xf1f8, 0x0000, 0x0000, {0}, "EXG A%x,A%y" },
+{ 0xc188, 0xf1f8, 0x0000, 0x0000, {0}, "EXG R%x,A%y" },
+
+{ 0xc0c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "MULUW %e,R%x" },
+{ 0xc1c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "MULSW %e,R%x" },
+
+{ 0xc000, 0xf100, 0x0000, 0x0000, {EADI}, "AND%s %e,R%x" },
+{ 0xc100, 0xf100, 0x0000, 0x0000, {EAMA}, "AND%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class d: addition */
+static Optable td[] = {
+{ 0xd000, 0xf1c0, 0x0000, 0x0000, {EADI}, "ADDB %e,R%x" },
+{ 0xd0c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "ADDW %e,A%x" },
+{ 0xd1c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "ADDL %e,A%x" },
+
+{ 0xd100, 0xf138, 0x0000, 0x0000, {0}, "ADDX%s R%y,R%x" },
+{ 0xd108, 0xf138, 0x0000, 0x0000, {0}, "ADDX%s -(A%y),-(A%x)" },
+
+{ 0xd000, 0xf100, 0x0000, 0x0000, {EAALL}, "ADD%s %e,R%x" },
+{ 0xd100, 0xf100, 0x0000, 0x0000, {EAMA}, "ADD%s R%x,%e" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class e: shift, rotate, bit field operations */
+static Optable te[] = {
+{ 0xe8c0, 0xffc0, 0x0820, 0xfe38, {EACD}, "BFTST %e{R%u:R%a}" },
+{ 0xe8c0, 0xffc0, 0x0800, 0xfe20, {EACD}, "BFTST %e{R%u:%w}" },
+{ 0xe8c0, 0xffc0, 0x0020, 0xf838, {EACD}, "BFTST %e{%o:R%a}" },
+{ 0xe8c0, 0xffc0, 0x0000, 0xf820, {EACD}, "BFTST %e{%o:%w}" },
+
+{ 0xe9c0, 0xffc0, 0x0820, 0x8e38, {EACD}, "BFEXTU %e{R%u:R%a},%r" },
+{ 0xe9c0, 0xffc0, 0x0800, 0x8e20, {EACD}, "BFEXTU %e{R%u:%w},%r" },
+{ 0xe9c0, 0xffc0, 0x0020, 0x8838, {EACD}, "BFEXTU %e{%o:R%a},%r" },
+{ 0xe9c0, 0xffc0, 0x0000, 0x8820, {EACD}, "BFEXTU %e{%o:%w},%r" },
+
+{ 0xeac0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFCHG %e{R%u:R%a}" },
+{ 0xeac0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFCHG %e{R%u:%w}" },
+{ 0xeac0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFCHG %e{%o:R%a}" },
+{ 0xeac0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFCHG %e{%o:%w}" },
+
+{ 0xebc0, 0xffc0, 0x0820, 0x8e38, {EACD}, "BFEXTS %e{R%u:R%a},%r" },
+{ 0xebc0, 0xffc0, 0x0800, 0x8e20, {EACD}, "BFEXTS %e{R%u:%w},%r" },
+{ 0xebc0, 0xffc0, 0x0020, 0x8838, {EACD}, "BFEXTS %e{%o:R%a},%r" },
+{ 0xebc0, 0xffc0, 0x0000, 0x8820, {EACD}, "BFEXTS %e{%o:%w},%r" },
+
+{ 0xecc0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFCLR %e{R%u:R%a}" },
+{ 0xecc0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFCLR %e{R%u:%w}" },
+{ 0xecc0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFCLR %e{%o:R%a}" },
+{ 0xecc0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFCLR %e{%o:%w}" },
+
+{ 0xedc0, 0xffc0, 0x0820, 0x8e38, {EACAD}, "BFFFO %e{R%u:R%a},%r" },
+{ 0xedc0, 0xffc0, 0x0800, 0x8e20, {EACAD}, "BFFFO %e{R%u:%w},%r" },
+{ 0xedc0, 0xffc0, 0x0020, 0x8838, {EACAD}, "BFFFO %e{%o:R%a},%r" },
+{ 0xedc0, 0xffc0, 0x0000, 0x8820, {EACAD}, "BFFFO %e{%o:%w},%r" },
+
+{ 0xeec0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFSET %e{R%u:R%a}" },
+{ 0xeec0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFSET %e{R%u:%w}" },
+{ 0xeec0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFSET %e{%o:R%a}" },
+{ 0xeec0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFSET %e{%o:%w}" },
+
+{ 0xefc0, 0xffc0, 0x0820, 0x8e38, {EACAD}, "BFINS %r,%e{R%u:R%a}" },
+{ 0xefc0, 0xffc0, 0x0800, 0x8e20, {EACAD}, "BFINS %r,%e{R%u:%w}" },
+{ 0xefc0, 0xffc0, 0x0020, 0x8838, {EACAD}, "BFINS %r,%e{%o:R%a}" },
+{ 0xefc0, 0xffc0, 0x0000, 0x8820, {EACAD}, "BFINS %r,%e{%o:%w}" },
+
+{ 0xe0c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "AS%dW %e" },
+{ 0xe2c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "LS%dW %e" },
+{ 0xe4c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "ROX%dW %e" },
+{ 0xe6c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "RO%dW %e" },
+
+{ 0xe000, 0xf038, 0x0000, 0x0000, {0}, "AS%d%s #%q,R%y" },
+{ 0xe008, 0xf038, 0x0000, 0x0000, {0}, "LS%d%s #%q,R%y" },
+{ 0xe010, 0xf038, 0x0000, 0x0000, {0}, "ROX%d%s #%q,R%y" },
+{ 0xe018, 0xf038, 0x0000, 0x0000, {0}, "RO%d%s #%q,R%y" },
+{ 0xe020, 0xf038, 0x0000, 0x0000, {0}, "AS%d%s R%x,R%y" },
+{ 0xe028, 0xf038, 0x0000, 0x0000, {0}, "LS%d%s R%x,R%y" },
+{ 0xe030, 0xf038, 0x0000, 0x0000, {0}, "ROX%d%s R%x,R%y" },
+{ 0xe038, 0xf038, 0x0000, 0x0000, {0}, "RO%d%s R%x,R%y" },
+{ 0,0,0,0,{0},0 },
+};
+ /* class f: coprocessor and mmu instructions */
+static Optable tf[] = {
+{ 0xf280, 0xffff, 0x0000, 0xffff, {0}, "FNOP" },
+{ 0xf200, 0xffff, 0x5c00, 0xfc00, {0}, "FMOVECRX %k,F%D" },
+{ 0xf27a, 0xffff, 0x0000, 0xffc0, {I16}, "FTRAP%P %i" },
+{ 0xf27b, 0xffff, 0x0000, 0xffc0, {I32}, "FTRAP%P %i" },
+{ 0xf27c, 0xffff, 0x0000, 0xffc0, {0}, "FTRAP%P" },
+
+{ 0xf248, 0xfff8, 0x0000, 0xffc0, {BR16}, "FDB%P R%y,%t" },
+{ 0xf620, 0xfff8, 0x8000, 0x8fff, {0}, "MOVE16 (A%y)+,(%r)+" },
+{ 0xf500, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHN (A%y)" },
+{ 0xf508, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSH (A%y)" },
+{ 0xf510, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHAN" },
+{ 0xf518, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHA" },
+{ 0xf548, 0xfff8, 0x0000, 0x0000, {0}, "PTESTW (A%y)" },
+{ 0xf568, 0xfff8, 0x0000, 0x0000, {0}, "PTESTR (A%y)" },
+{ 0xf600, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 (A%y)+,$%i" },
+{ 0xf608, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 $%i,(A%y)-" },
+{ 0xf610, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 (A%y),$%i" },
+{ 0xf618, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 $%i,(A%y)" },
+
+{ 0xf000, 0xffc0, 0x0800, 0xffff, {EACA}, "PMOVE %e,TT0" },
+{ 0xf000, 0xffc0, 0x0900, 0xffff, {EACA}, "PMOVEFD %e,TT0" },
+{ 0xf000, 0xffc0, 0x0a00, 0xffff, {EACA}, "PMOVE TT0,%e" },
+{ 0xf000, 0xffc0, 0x0b00, 0xffff, {EACA}, "PMOVEFD TT0,%e" },
+{ 0xf000, 0xffc0, 0x0c00, 0xffff, {EACA}, "PMOVE %e,TT1" },
+{ 0xf000, 0xffc0, 0x0d00, 0xffff, {EACA}, "PMOVEFD %e,TT1" },
+{ 0xf000, 0xffc0, 0x0e00, 0xffff, {EACA}, "PMOVE TT1,%e" },
+{ 0xf000, 0xffc0, 0x0f00, 0xffff, {EACA}, "PMOVEFD TT1,%e" },
+{ 0xf000, 0xffc0, 0x2400, 0xffff, {0}, "PFLUSHA" },
+{ 0xf000, 0xffc0, 0x2800, 0xffff, {EACA}, "PVALID VAL,%e" },
+{ 0xf000, 0xffc0, 0x6000, 0xffff, {EACA}, "PMOVE %e,MMUSR" },
+{ 0xf000, 0xffc0, 0x6200, 0xffff, {EACA}, "PMOVE MMUSR,%e" },
+{ 0xf000, 0xffc0, 0x2800, 0xfff8, {EACA}, "PVALID A%a,%e" },
+{ 0xf000, 0xffc0, 0x2000, 0xffe0, {EACA}, "PLOADW %L,%e" },
+{ 0xf000, 0xffc0, 0x2200, 0xffe0, {EACA}, "PLOADR %L,%e" },
+{ 0xf000, 0xffc0, 0x8000, 0xffe0, {EACA}, "PTESTW %L,%e,#0" },
+{ 0xf000, 0xffc0, 0x8200, 0xffe0, {EACA}, "PTESTR %L,%e,#0" },
+{ 0xf000, 0xffc0, 0x3000, 0xfe00, {0}, "PFLUSH %L,#%I" },
+{ 0xf000, 0xffc0, 0x3800, 0xfe00, {EACA}, "PFLUSH %L,#%I,%e" },
+{ 0xf000, 0xffc0, 0x8000, 0xe300, {EACA}, "PTESTW %L,%e,#%Z" },
+{ 0xf000, 0xffc0, 0x8100, 0xe300, {EACA}, "PTESTW %L,%e,#%Z,A%h" },
+{ 0xf000, 0xffc0, 0x8200, 0xe300, {EACA}, "PTESTR %L,%e,#%Z" },
+{ 0xf000, 0xffc0, 0x8300, 0xe300, {EACA}, "PTESTR %L,%e,#%Z,A%h" },
+{ 0xf000, 0xffc0, 0x4000, 0xc3ff, {EACA}, "PMOVE %e,%H" },
+{ 0xf000, 0xffc0, 0x4100, 0xc3ff, {EACA}, "PMOVEFD %e,%H" },
+{ 0xf000, 0xffc0, 0x4200, 0xc3ff, {EACA}, "PMOVE %H,%e" },
+
+ /* floating point (coprocessor 1)*/
+
+{ 0xf200, 0xffc0, 0x8400, 0xffff, {EAALL_L}, "FMOVEL %e,FPIAR" },
+{ 0xf200, 0xffc0, 0x8800, 0xffff, {EADI_L}, "FMOVEL %e,FPSR" },
+{ 0xf200, 0xffc0, 0x9000, 0xffff, {EADI_L}, "FMOVEL %e,FPCR" },
+{ 0xf200, 0xffc0, 0xa400, 0xffff, {EAA}, "FMOVEL FPIAR,%e" },
+{ 0xf200, 0xffc0, 0xa800, 0xffff, {EADA}, "FMOVEL FPSR,%e" },
+{ 0xf200, 0xffc0, 0xb000, 0xffff, {EADA}, "FMOVEL FPCR,%e" },
+
+{ 0xf240, 0xffc0, 0x0000, 0xffc0, {EADA}, "FS%P %e" },
+
+{ 0xf200, 0xffc0, 0xd000, 0xff00, {EACPI}, "FMOVEMX %e,%m" },
+{ 0xf200, 0xffc0, 0xd800, 0xff00, {EACPI}, "FMOVEMX %e,R%K" },
+{ 0xf200, 0xffc0, 0xe000, 0xff00, {EAPI}, "FMOVEMX %m,-(A%y)" },
+{ 0xf200, 0xffc0, 0xe800, 0xff00, {EAPI}, "FMOVEMX R%K,-(A%y)" },
+{ 0xf200, 0xffc0, 0xf000, 0xff00, {EACAPD}, "FMOVEMX %m,%e" },
+{ 0xf200, 0xffc0, 0xf800, 0xff00, {EACAPD}, "FMOVEMX R%K,%e" },
+
+{ 0xf200, 0xffc0, 0x6800, 0xfc00, {EAMA}, "FMOVEX F%D,%e" },
+{ 0xf200, 0xffc0, 0x6c00, 0xfc00, {EAMA}, "FMOVEP F%D,%e,{%k}" },
+{ 0xf200, 0xffc0, 0x7400, 0xfc00, {EAMA}, "FMOVED F%D,%e" },
+{ 0xf200, 0xffc0, 0x7c00, 0xfc00, {EAMA}, "FMOVEP F%D,%e,{R%K}" },
+
+{ 0xf200, 0xffc0, 0x8000, 0xe3ff, {EAM}, "FMOVEML #%B,%e" },
+{ 0xf200, 0xffc0, 0xa000, 0xe3ff, {EAMA}, "FMOVEML %e,#%B" },
+
+{ 0xf200, 0xffc0, 0x0000, 0xe07f, {0}, "FMOVE F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0001, 0xe07f, {0}, "FINTX %F" },
+{ 0xf200, 0xffc0, 0x0002, 0xe07f, {0}, "FSINHX %F" },
+{ 0xf200, 0xffc0, 0x0003, 0xe07f, {0}, "FINTRZ %F" },
+{ 0xf200, 0xffc0, 0x0004, 0xe07f, {0}, "FSQRTX %F" },
+{ 0xf200, 0xffc0, 0x0006, 0xe07f, {0}, "FLOGNP1X %F" },
+{ 0xf200, 0xffc0, 0x0009, 0xe07f, {0}, "FTANHX %F" },
+{ 0xf200, 0xffc0, 0x000a, 0xe07f, {0}, "FATANX %F" },
+{ 0xf200, 0xffc0, 0x000c, 0xe07f, {0}, "FASINX %F" },
+{ 0xf200, 0xffc0, 0x000d, 0xe07f, {0}, "FATANHX %F" },
+{ 0xf200, 0xffc0, 0x000e, 0xe07f, {0}, "FSINX %F" },
+{ 0xf200, 0xffc0, 0x000f, 0xe07f, {0}, "FTANX %F" },
+{ 0xf200, 0xffc0, 0x0010, 0xe07f, {0}, "FETOXX %F" },
+{ 0xf200, 0xffc0, 0x0011, 0xe07f, {0}, "FTWOTOXX %F" },
+{ 0xf200, 0xffc0, 0x0012, 0xe07f, {0}, "FTENTOXX %F" },
+{ 0xf200, 0xffc0, 0x0014, 0xe07f, {0}, "FLOGNX %F" },
+{ 0xf200, 0xffc0, 0x0015, 0xe07f, {0}, "FLOG10X %F" },
+{ 0xf200, 0xffc0, 0x0016, 0xe07f, {0}, "FLOG2X %F" },
+{ 0xf200, 0xffc0, 0x0018, 0xe07f, {0}, "FABSX %F" },
+{ 0xf200, 0xffc0, 0x0019, 0xe07f, {0}, "FCOSHX %F" },
+{ 0xf200, 0xffc0, 0x001a, 0xe07f, {0}, "FNEGX %F" },
+{ 0xf200, 0xffc0, 0x001c, 0xe07f, {0}, "FACOSX %F" },
+{ 0xf200, 0xffc0, 0x001d, 0xe07f, {0}, "FCOSX %F" },
+{ 0xf200, 0xffc0, 0x001e, 0xe07f, {0}, "FGETEXPX %F" },
+{ 0xf200, 0xffc0, 0x001f, 0xe07f, {0}, "FGETMANX %F" },
+{ 0xf200, 0xffc0, 0x0020, 0xe07f, {0}, "FDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0021, 0xe07f, {0}, "FMODX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0022, 0xe07f, {0}, "FADDX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0023, 0xe07f, {0}, "FMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0024, 0xe07f, {0}, "FSGLDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0025, 0xe07f, {0}, "FREMX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0026, 0xe07f, {0}, "FSCALEX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0027, 0xe07f, {0}, "FSGLMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0028, 0xe07f, {0}, "FSUBX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0038, 0xe07f, {0}, "FCMPX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x003a, 0xe07f, {0}, "FTSTX F%B" },
+{ 0xf200, 0xffc0, 0x0040, 0xe07f, {0}, "FSMOVE F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0041, 0xe07f, {0}, "FSSQRTX %F"},
+{ 0xf200, 0xffc0, 0x0044, 0xe07f, {0}, "FDMOVE F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0045, 0xe07f, {0}, "FDSQRTX %F" },
+{ 0xf200, 0xffc0, 0x0058, 0xe07f, {0}, "FSABSX %F" },
+{ 0xf200, 0xffc0, 0x005a, 0xe07f, {0}, "FSNEGX %F" },
+{ 0xf200, 0xffc0, 0x005c, 0xe07f, {0}, "FDABSX %F" },
+{ 0xf200, 0xffc0, 0x005e, 0xe07f, {0}, "FDNEGX %F" },
+{ 0xf200, 0xffc0, 0x0060, 0xe07f, {0}, "FSDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0062, 0xe07f, {0}, "FSADDX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0063, 0xe07f, {0}, "FSMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0064, 0xe07f, {0}, "FDDIVX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0066, 0xe07f, {0}, "FDADDX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0067, 0xe07f, {0}, "FDMULX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x0068, 0xe07f, {0}, "FSSUBX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x006c, 0xe07f, {0}, "FDSUBX F%B,F%D" },
+{ 0xf200, 0xffc0, 0x4000, 0xe07f, {EAFLT}, "FMOVE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4001, 0xe07f, {EAFLT}, "FINT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4002, 0xe07f, {EAFLT}, "FSINH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4003, 0xe07f, {EAFLT}, "FINTRZ%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4004, 0xe07f, {EAFLT}, "FSQRT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4006, 0xe07f, {EAFLT}, "FLOGNP1%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4009, 0xe07f, {EAFLT}, "FTANH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400a, 0xe07f, {EAFLT}, "FATAN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400c, 0xe07f, {EAFLT}, "FASIN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400d, 0xe07f, {EAFLT}, "FATANH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400e, 0xe07f, {EAFLT}, "FSIN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x400f, 0xe07f, {EAFLT}, "FTAN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4010, 0xe07f, {EAFLT}, "FETOX%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4011, 0xe07f, {EAFLT}, "FTWOTOX%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4012, 0xe07f, {EAFLT}, "FTENTOX%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4014, 0xe07f, {EAFLT}, "FLOGN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4015, 0xe07f, {EAFLT}, "FLOG10%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4016, 0xe07f, {EAFLT}, "FLOG2%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4018, 0xe07f, {EAFLT}, "FABS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4019, 0xe07f, {EAFLT}, "FCOSH%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401a, 0xe07f, {EAFLT}, "FNEG%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401c, 0xe07f, {EAFLT}, "FACOS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401d, 0xe07f, {EAFLT}, "FCOS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401e, 0xe07f, {EAFLT}, "FGETEXP%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x401f, 0xe07f, {EAFLT}, "FGETMAN%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4020, 0xe07f, {EAFLT}, "FDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4021, 0xe07f, {EAFLT}, "FMOD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4022, 0xe07f, {EAFLT}, "FADD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4023, 0xe07f, {EAFLT}, "FMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4024, 0xe07f, {EAFLT}, "FSGLDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4025, 0xe07f, {EAFLT}, "FREM%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4026, 0xe07f, {EAFLT}, "FSCALE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4027, 0xe07f, {EAFLT}, "FSGLMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4028, 0xe07f, {EAFLT}, "FSUB%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4038, 0xe07f, {EAFLT}, "FCMP%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x403a, 0xe07f, {EAFLT}, "FTST%S %e" },
+{ 0xf200, 0xffc0, 0x4040, 0xe07f, {EAFLT}, "FSMOVE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4041, 0xe07f, {EAFLT}, "FSSQRT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4044, 0xe07f, {EAFLT}, "FDMOVE%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4045, 0xe07f, {EAFLT}, "FDSQRT%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4058, 0xe07f, {EAFLT}, "FSABS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x405a, 0xe07f, {EAFLT}, "FSNEG%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x405c, 0xe07f, {EAFLT}, "FDABS%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x405e, 0xe07f, {EAFLT}, "FDNEG%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4060, 0xe07f, {EAFLT}, "FSDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4062, 0xe07f, {EAFLT}, "FSADD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4063, 0xe07f, {EAFLT}, "FSMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4064, 0xe07f, {EAFLT}, "FDDIV%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4066, 0xe07f, {EAFLT}, "FDADD%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4067, 0xe07f, {EAFLT}, "FDMUL%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x4068, 0xe07f, {EAFLT}, "FSSUB%S %e,F%D" },
+{ 0xf200, 0xffc0, 0x406c, 0xe07f, {EAFLT}, "FDSUB%S %e,F%D" },
+
+{ 0xf200, 0xffc0, 0x0030, 0xe078, {0}, "FSINCOSX F%B,F%a:F%D" },
+{ 0xf200, 0xffc0, 0x4030, 0xe078, {EAFLT}, "FSINCOS%S %e,F%a:F%D" },
+
+{ 0xf200, 0xffc0, 0x6000, 0xe000, {EADA}, "FMOVE%S F%D,%e" },
+
+{ 0xf300, 0xffc0, 0x0000, 0x0000, {EACAPD}, "FSAVE %e" },
+{ 0xf340, 0xffc0, 0x0000, 0x0000, {EACAPI}, "FRESTORE %e" },
+
+{ 0xf280, 0xffc0, 0x0000, 0x0000, {BR16}, "FB%p %t" },
+{ 0xf2c0, 0xffc0, 0x0000, 0x0000, {BR32}, "FB%p %t" },
+
+{ 0xf408, 0xff38, 0x0000, 0x0000, {0}, "CINVL %C,(A%y)" },
+{ 0xf410, 0xff38, 0x0000, 0x0000, {0}, "CINVP %C,(A%y)" },
+{ 0xf418, 0xff38, 0x0000, 0x0000, {0}, "CINVA %C" },
+{ 0xf428, 0xff38, 0x0000, 0x0000, {0}, "CPUSHL %C,(A%y)" },
+{ 0xf430, 0xff38, 0x0000, 0x0000, {0}, "CPUSHP %C,(A%y)" },
+{ 0xf438, 0xff38, 0x0000, 0x0000, {0}, "CPUSHA %C" },
+{ 0,0,0,0,{0},0 },
+};
+
+static Optable *optables[] =
+{
+ t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, 0, tb, tc, td, te, tf,
+};
+
+static Map *mymap;
+
+static int
+dumpinst(Inst *ip, char *buf, int n)
+{
+ int i;
+
+ if (n <= 0)
+ return 0;
+
+ *buf++ = '#';
+ for (i = 0; i < ip->n && i*4+1 < n-4; i++, buf += 4)
+ _hexify(buf, ip->raw[i], 3);
+ *buf = 0;
+ return i*4+1;
+}
+
+static int
+getword(Inst *ip, long offset)
+{
+ if (ip->n < nelem(ip->raw)) {
+ if (get2(mymap, offset, &ip->raw[ip->n++]) > 0)
+ return 1;
+ werrstr("can't read instruction: %r");
+ } else
+ werrstr("instruction too big: %r");
+ return -1;
+}
+
+static int
+getshorts(Inst *ip, void *where, int n)
+{
+ if (ip->n+n < nelem(ip->raw)) {
+ if (get1(mymap, ip->addr+ip->n*2, (uchar*)&ip->raw[ip->n], n*2) < 0) {
+ werrstr("can't read instruction: %r");
+ return 0;
+ }
+ memmove(where, &ip->raw[ip->n], n*2);
+ ip->n += n;
+ return 1;
+ }
+ werrstr("instruction too big: %r");
+ return 0;
+}
+
+static int
+i8(Inst *ip, long *l)
+{
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ *l = ip->raw[ip->n-1]&0xff;
+ if (*l&0x80)
+ *l |= ~0xff;
+ return 1;
+}
+
+static int
+i16(Inst *ip, long *l)
+{
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ *l = ip->raw[ip->n-1];
+ if (*l&0x8000)
+ *l |= ~0xffff;
+ return 1;
+}
+static int
+i32(Inst *ip, long *l)
+{
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ *l = (ip->raw[ip->n-2]<<16)|ip->raw[ip->n-1];
+ return 1;
+}
+
+static int
+getimm(Inst *ip, Operand *ap, int mode)
+{
+ ap->eatype = IMM;
+ switch(mode)
+ {
+ case EAM_B: /* byte */
+ case EAALL_B:
+ return i8(ip, &ap->u0.immediate);
+ case EADI_W: /* word */
+ case EAALL_W:
+ return i16(ip, &ap->u0.immediate);
+ case EADI_L: /* long */
+ case EAALL_L:
+ return i32(ip, &ap->u0.immediate);
+ case EAFLT: /* floating point - size in bits 10-12 or word 1 */
+ switch((ip->raw[1]>>10)&0x07)
+ {
+ case 0: /* long integer */
+ return i32(ip, &ap->u0.immediate);
+ case 1: /* single precision real */
+ ap->eatype = IREAL;
+ return getshorts(ip, ap->u0.floater, 2);
+ case 2: /* extended precision real - not supported */
+ ap->eatype = IEXT;
+ return getshorts(ip, ap->u0.floater, 6);
+ case 3: /* packed decimal real - not supported */
+ ap->eatype = IPACK;
+ return getshorts(ip, ap->u0.floater, 12);
+ case 4: /* integer word */
+ return i16(ip, &ap->u0.immediate);
+ case 5: /* double precision real */
+ ap->eatype = IDBL;
+ return getshorts(ip, ap->u0.floater, 4);
+ case 6: /* integer byte */
+ return i8(ip, &ap->u0.immediate);
+ default:
+ ip->errmsg = "bad immediate float data";
+ return -1;
+ }
+ break;
+ case IV: /* size encoded in bits 6&7 of opcode word */
+ default:
+ switch((ip->raw[0]>>6)&0x03)
+ {
+ case 0x00: /* integer byte */
+ return i8(ip, &ap->u0.immediate);
+ case 0x01: /* integer word */
+ return i16(ip, &ap->u0.immediate);
+ case 0x02: /* integer long */
+ return i32(ip, &ap->u0.immediate);
+ default:
+ ip->errmsg = "bad immediate size";
+ return -1;
+ }
+ break;
+ }
+ return 1;
+}
+
+static int
+getdisp(Inst *ip, Operand *ap)
+{
+ short ext;
+
+ if (getword(ip, ip->addr+ip->n*2) < 0)
+ return -1;
+ ext = ip->raw[ip->n-1];
+ ap->ext = ext;
+ if ((ext&0x100) == 0) { /* indexed with 7-bit displacement */
+ ap->u0.s0.disp = ext&0x7f;
+ if (ap->u0.s0.disp&0x40)
+ ap->u0.s0.disp |= ~0x7f;
+ return 1;
+ }
+ switch(ext&0x30) /* first (inner) displacement */
+ {
+ case 0x10:
+ break;
+ case 0x20:
+ if (i16(ip, &ap->u0.s0.disp) < 0)
+ return -1;
+ break;
+ case 0x30:
+ if (i32(ip, &ap->u0.s0.disp) < 0)
+ return -1;
+ break;
+ default:
+ ip->errmsg = "bad EA displacement";
+ return -1;
+ }
+ switch (ext&0x03) /* outer displacement */
+ {
+ case 0x02: /* 16 bit displacement */
+ return i16(ip, &ap->u0.s0.outer);
+ case 0x03: /* 32 bit displacement */
+ return i32(ip, &ap->u0.s0.outer);
+ default:
+ break;
+ }
+ return 1;
+}
+
+static int
+ea(Inst *ip, int ea, Operand *ap, int mode)
+{
+ int type, size;
+
+ type = 0;
+ ap->ext = 0;
+ switch((ea>>3)&0x07)
+ {
+ case 0x00:
+ ap->eatype = Dreg;
+ type = Dn;
+ break;
+ case 0x01:
+ ap->eatype = Areg;
+ type = An;
+ break;
+ case 0x02:
+ ap->eatype = AInd;
+ type = Ind;
+ break;
+ case 0x03:
+ ap->eatype = APinc;
+ type = Pinc;
+ break;
+ case 0x04:
+ ap->eatype = APdec;
+ type = Pdec;
+ break;
+ case 0x05:
+ ap->eatype = ADisp;
+ type = Bdisp;
+ if (i16(ip, &ap->u0.s0.disp) < 0)
+ return -1;
+ break;
+ case 0x06:
+ ap->eatype = BXD;
+ type = Bdisp;
+ if (getdisp(ip, ap) < 0)
+ return -1;
+ break;
+ case 0x07:
+ switch(ea&0x07)
+ {
+ case 0x00:
+ type = Abs;
+ ap->eatype = ABS;
+ if (i16(ip, &ap->u0.immediate) < 0)
+ return -1;
+ break;
+ case 0x01:
+ type = Abs;
+ ap->eatype = ABS;
+ if (i32(ip, &ap->u0.immediate) < 0)
+ return -1;
+ break;
+ case 0x02:
+ type = PCrel;
+ ap->eatype = PDisp;
+ if (i16(ip, &ap->u0.s0.disp) < 0)
+ return -1;
+ break;
+ case 0x03:
+ type = PCrel;
+ ap->eatype = PXD;
+ if (getdisp(ip, ap) < 0)
+ return -1;
+ break;
+ case 0x04:
+ type = Imm;
+ if (getimm(ip, ap, mode) < 0)
+ return -1;
+ break;
+ default:
+ ip->errmsg = "bad EA mode";
+ return -1;
+ }
+ }
+ /* Allowable floating point EAs are restricted for packed,
+ * extended, and double precision operands
+ */
+ if (mode == EAFLT) {
+ size = (ip->raw[1]>>10)&0x07;
+ if (size == 2 || size == 3 || size == 5)
+ mode = EAM;
+ else
+ mode = EADI;
+ }
+ if (!(validea[mode]&type)) {
+ ip->errmsg = "invalid EA";
+ return -1;
+ }
+ return 1;
+}
+
+static int
+decode(Inst *ip, Optable *op)
+{
+ int i, t, mode;
+ Operand *ap;
+ short opcode;
+
+ opcode = ip->raw[0];
+ for (i = 0; i < nelem(op->opdata) && op->opdata[i]; i++) {
+ ap = &ip->and[i];
+ mode = op->opdata[i];
+ switch(mode)
+ {
+ case EAPI: /* normal EA modes */
+ case EACA:
+ case EACAD:
+ case EACAPI:
+ case EACAPD:
+ case EAMA:
+ case EADA:
+ case EAA:
+ case EAC:
+ case EACPI:
+ case EACD:
+ case EAD:
+ case EAM:
+ case EAM_B:
+ case EADI:
+ case EADI_L:
+ case EADI_W:
+ case EAALL:
+ case EAALL_L:
+ case EAALL_W:
+ case EAALL_B:
+ case EAFLT:
+ if (ea(ip, opcode&0x3f, ap, mode) < 0)
+ return -1;
+ break;
+ case EADDA: /* stupid bit flop required */
+ t = ((opcode>>9)&0x07)|((opcode>>3)&0x38);
+ if (ea(ip, t, ap, EADA)< 0)
+ return -1;
+ break;
+ case BREAC: /* EAC JMP or CALL operand */
+ if (ea(ip, opcode&0x3f, ap, EAC) < 0)
+ return -1;
+ break;
+ case OP8: /* weird movq instruction */
+ ap->eatype = IMM;
+ ap->u0.immediate = opcode&0xff;
+ if (opcode&0x80)
+ ap->u0.immediate |= ~0xff;
+ break;
+ case I8: /* must be two-word opcode */
+ ap->eatype = IMM;
+ ap->u0.immediate = ip->raw[1]&0xff;
+ if (ap->u0.immediate&0x80)
+ ap->u0.immediate |= ~0xff;
+ break;
+ case I16: /* 16 bit immediate */
+ case BR16:
+ ap->eatype = IMM;
+ if (i16(ip, &ap->u0.immediate) < 0)
+ return -1;
+ break;
+ case C16: /* CAS2 16 bit immediate */
+ ap->eatype = IMM;
+ if (i16(ip, &ap->u0.immediate) < 0)
+ return -1;
+ if (ap->u0.immediate & 0x0e38) {
+ ip->errmsg = "bad CAS2W operand";
+ return 0;
+ }
+ break;
+ case I32: /* 32 bit immediate */
+ case BR32:
+ ap->eatype = IMM;
+ if (i32(ip, &ap->u0.immediate) < 0)
+ return -1;
+ break;
+ case IV: /* immediate data depends on size field */
+ if (getimm(ip, ap, IV) < 0)
+ return -1;
+ break;
+ case BR8: /* branch displacement format */
+ ap->eatype = IMM;
+ ap->u0.immediate = opcode&0xff;
+ if (ap->u0.immediate == 0) {
+ if (i16(ip, &ap->u0.immediate) < 0)
+ return -1;
+ } else if (ap->u0.immediate == 0xff) {
+ if (i32(ip, &ap->u0.immediate) < 0)
+ return -1;
+ } else if (ap->u0.immediate & 0x80)
+ ap->u0.immediate |= ~0xff;
+ break;
+ case STACK: /* Dummy operand type for Return instructions */
+ default:
+ break;
+ }
+ }
+ return 1;
+}
+
+static Optable *
+instruction(Inst *ip)
+{
+ ushort opcode, op2;
+ Optable *op;
+ int class;
+
+ ip->n = 0;
+ if (getword(ip, ip->addr) < 0)
+ return 0;
+ opcode = ip->raw[0];
+ if (get2(mymap, ip->addr+2, &op2) < 0)
+ op2 = 0;
+ class = (opcode>>12)&0x0f;
+ for (op = optables[class]; op && op->format; op++) {
+ if (op->opcode != (opcode&op->mask0))
+ continue;
+ if (op->op2 != (op2&op->mask1))
+ continue;
+ if (op->mask1)
+ ip->raw[ip->n++] = op2;
+ return op;
+ }
+ ip->errmsg = "Invalid opcode";
+ return 0;
+}
+
+static void
+bprint(Inst *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static char *regname[] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "A0",
+ "A1", "A2", "A3", "A4", "A5", "A6", "A7", "PC", "SB"
+};
+
+static void
+plocal(Inst *ip, Operand *ap)
+{
+ int ret, offset;
+ long moved;
+ Symbol s;
+
+ offset = ap->u0.s0.disp;
+ if (!findsym(ip->addr, CTEXT, &s))
+ goto none;
+
+ moved = pc2sp(ip->addr);
+ if (moved == -1)
+ goto none;
+
+ if (offset > moved) { /* above frame - must be argument */
+ offset -= moved;
+ ret = getauto(&s, offset-mach->szaddr, CPARAM, &s);
+ } else /* below frame - must be automatic */
+ ret = getauto(&s, moved-offset, CPARAM, &s);
+ if (ret)
+ bprint(ip, "%s+%lux", s.name, offset);
+ else
+none: bprint(ip, "%lux", ap->u0.s0.disp);
+}
+
+/*
+ * this guy does all the work of printing the base and index component
+ * of an EA.
+ */
+static int
+pidx(Inst *ip, int ext, int reg, char *bfmt, char *ifmt, char *nobase)
+{
+ char *s;
+ int printed;
+ char buf[512];
+
+ printed = 1;
+ if (ext&0x80) { /* Base suppressed */
+ if (reg == 16)
+ bprint(ip, bfmt, "(ZPC)");
+ else if (nobase)
+ bprint(ip, nobase);
+ else
+ printed = 0;
+ } else /* format base reg */
+ bprint(ip, bfmt, regname[reg]);
+ if (ext & 0x40) /* index suppressed */
+ return printed;
+ switch ((ext>>9)&0x03)
+ {
+ case 0x01:
+ s = "*2";
+ break;
+ case 0x02:
+ s = "*4";
+ break;
+ case 0x03:
+ s = "*8";
+ break;
+ default:
+ if (ext&0x80)
+ s = "*1";
+ else
+ s = "";
+ break;
+ }
+ sprint(buf, "%s.%c%s", regname[(ext>>12)&0x0f], (ext&0x800) ? 'L' : 'W', s);
+ if (!printed)
+ bprint(ip, ifmt, buf);
+ else
+ bprint(ip, "(%s)", buf);
+ return 1;
+}
+
+static void
+prindex(Inst *ip, int reg, Operand *ap)
+{
+ short ext;
+ int left;
+ int disp;
+
+ left = ip->end-ip->curr;
+ if (left <= 0)
+ return;
+ ext = ap->ext;
+ disp = ap->u0.s0.disp;
+ /* look for static base register references */
+ if ((ext&0xa0) == 0x20 && reg == 14 && mach->sb && disp) {
+ reg = 17; /* "A6" -> "SB" */
+ disp += mach->sb;
+ }
+ if ((ext&0x100) == 0) { /* brief form */
+ if (reg == 15)
+ plocal(ip, ap);
+ else if (disp)
+ ip->curr += symoff(ip->curr, left, disp, CANY);
+ pidx(ip, ext&0xff00, reg, "(%s)", "(%s)", 0);
+ return;
+ }
+ switch(ext&0x3f) /* bd size, && i/is */
+ {
+ case 0x10:
+ if (!pidx(ip, ext, reg, "(%s)", "(%s)", 0))
+ bprint(ip, "#0");
+ break;
+ case 0x11:
+ if (pidx(ip, ext, reg, "((%s)", "((%s)", 0))
+ bprint(ip, ")");
+ else
+ bprint(ip, "#0");
+ break;
+ case 0x12:
+ case 0x13:
+ ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY);
+ if (pidx(ip, ext, reg, "((%s)", "((%s)", 0))
+ bprint(ip, ")");
+ break;
+ case 0x15:
+ if (!pidx(ip, ext, reg, "((%s))", "(%s)", 0))
+ bprint(ip, "#0");
+ break;
+ case 0x16:
+ case 0x17:
+ ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY);
+ pidx(ip, ext, reg, "((%s))", "(%s)", 0);
+ break;
+ case 0x20:
+ case 0x30:
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left, disp, CANY);
+ pidx(ip, ext, reg, "(%s)", "(%s)", 0);
+ break;
+ case 0x21:
+ case 0x31:
+ *ip->curr++ = '(';
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left-1, disp, CANY);
+ pidx(ip, ext, reg, "(%s)", "(%s)", 0);
+ bprint(ip, ")");
+ break;
+ case 0x22:
+ case 0x23:
+ case 0x32:
+ case 0x33:
+ ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY);
+ bprint(ip, "(");
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, ip->end-ip->curr, disp, CANY);
+ pidx(ip, ext, reg, "(%s)", "(%s)", 0);
+ bprint(ip, ")");
+ break;
+ case 0x25:
+ case 0x35:
+ *ip->curr++ = '(';
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left-1, disp, CANY);
+ if (!pidx(ip, ext, reg, "(%s))", "(%s)", "())"))
+ bprint(ip, ")");
+ break;
+ case 0x26:
+ case 0x27:
+ case 0x36:
+ case 0x37:
+ ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY);
+ bprint(ip, "(");
+ if (reg == 15)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, ip->end-ip->curr, disp, CANY);
+ pidx(ip, ext, reg, "(%s))", "(%s)", "())");
+ break;
+ default:
+ bprint(ip, "??%x??", ext);
+ ip->errmsg = "bad EA";
+ break;
+ }
+}
+
+static void
+pea(int reg, Inst *ip, Operand *ap)
+{
+ int i, left;
+
+ left = ip->end-ip->curr;
+ if (left < 0)
+ return;
+ switch(ap->eatype)
+ {
+ case Dreg:
+ bprint(ip, "R%d", reg);
+ break;
+ case Areg:
+ bprint(ip, "A%d", reg);
+ break;
+ case AInd:
+ bprint(ip, "(A%d)", reg);
+ break;
+ case APinc:
+ bprint(ip, "(A%d)+", reg);
+ break;
+ case APdec:
+ bprint(ip, "-(A%d)", reg);
+ break;
+ case PDisp:
+ ip->curr += symoff(ip->curr, left, ip->addr+2+ap->u0.s0.disp, CANY);
+ break;
+ case PXD:
+ prindex(ip, 16, ap);
+ break;
+ case ADisp: /* references off the static base */
+ if (reg == 6 && mach->sb && ap->u0.s0.disp) {
+ ip->curr += symoff(ip->curr, left, ap->u0.s0.disp+mach->sb, CANY);
+ bprint(ip, "(SB)", reg);
+ break;
+ }
+ /* reference autos and parameters off the stack */
+ if (reg == 7)
+ plocal(ip, ap);
+ else
+ ip->curr += symoff(ip->curr, left, ap->u0.s0.disp, CANY);
+ bprint(ip, "(A%d)", reg);
+ break;
+ case BXD:
+ prindex(ip, reg+8, ap);
+ break;
+ case ABS:
+ ip->curr += symoff(ip->curr, left, ap->u0.immediate, CANY);
+ bprint(ip, "($0)");
+ break;
+ case IMM:
+ *ip->curr++ = '$';
+ ip->curr += symoff(ip->curr, left-1, ap->u0.immediate, CANY);
+ break;
+ case IREAL:
+ *ip->curr++ = '$';
+ ip->curr += beieeesftos(ip->curr, left-1, (void*) ap->u0.floater);
+ break;
+ case IDBL:
+ *ip->curr++ = '$';
+ ip->curr += beieeedftos(ip->curr, left-1, (void*) ap->u0.floater);
+ break;
+ case IPACK:
+ bprint(ip, "$#");
+ for (i = 0; i < 24 && ip->curr < ip->end-1; i++) {
+ _hexify(ip->curr, ap->u0.floater[i], 1);
+ ip->curr += 2;
+ }
+ break;
+ case IEXT:
+ bprint(ip, "$#");
+ ip->curr += beieee80ftos(ip->curr, left-2, (void*)ap->u0.floater);
+ break;
+ default:
+ bprint(ip, "??%x??", ap->eatype);
+ ip->errmsg = "bad EA type";
+ break;
+ }
+}
+
+static char *cctab[] = { "F", "T", "HI", "LS", "CC", "CS", "NE", "EQ",
+ "VC", "VS", "PL", "MI", "GE", "LT", "GT", "LE" };
+static char *fcond[] =
+{
+ "F", "EQ", "OGT", "OGE", "OLT", "OLE", "OGL", "OR",
+ "UN", "UEQ", "UGT", "UGE", "ULT", "ULE", "NE", "T",
+ "SF", "SEQ", "GT", "GE", "LT", "LE", "GL", "GLE",
+ "NGLE", "NGL", "NLE", "NLT", "NGE", "NGT", "SNE", "ST"
+};
+static char *cachetab[] = { "NC", "DC", "IC", "BC" };
+static char *mmutab[] = { "TC", "??", "SRP", "CRP" };
+static char *crtab0[] =
+{
+ "SFC", "DFC", "CACR", "TC", "ITT0", "ITT1", "DTT0", "DTT1",
+};
+static char *crtab1[] =
+{
+ "USP", "VBR", "CAAR", "MSP", "ISP", "MMUSR", "URP", "SRP",
+};
+static char typetab[] = { 'L', 'S', 'X', 'P', 'W', 'D', 'B', '?', };
+static char sztab[] = {'?', 'B', 'W', 'L', '?' };
+
+static void
+formatins(char *fmt, Inst *ip)
+{
+ short op, w1;
+ int r1, r2;
+ int currand;
+
+ op = ip->raw[0];
+ w1 = ip->raw[1];
+ currand = 0;
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%')
+ *ip->curr++ = *fmt;
+ else switch(*++fmt)
+ {
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'a': /* register number; word 1:[0-2] */
+ *ip->curr++ = (w1&0x07)+'0';
+ break;
+ case 'c': /* condition code; opcode: [8-11] */
+ bprint(ip, cctab[(op>>8)&0x0f]);
+ break;
+ case 'd': /* shift direction; opcode: [8] */
+ if (op&0x100)
+ *ip->curr++ = 'L';
+ else
+ *ip->curr++ = 'R';
+ break;
+ case 'e': /* source effective address */
+ pea(op&0x07, ip, &ip->and[currand++]);
+ break;
+ case 'f': /* trap vector; op code: [0-3] */
+ bprint(ip, "%x", op&0x0f);
+ break;
+ case 'h': /* register number; word 1: [5-7] */
+ *ip->curr++ = (w1>>5)&0x07+'0';
+ break;
+ case 'i': /* immediate operand */
+ ip->curr += symoff(ip->curr, ip->end-ip->curr,
+ ip->and[currand++].u0.immediate, CANY);
+ break;
+ case 'j': /* data registers; word 1: [0-2] & [12-14] */
+ r1 = w1&0x07;
+ r2 = (w1>>12)&0x07;
+ if (r1 == r2)
+ bprint(ip, "R%d", r1);
+ else
+ bprint(ip, "R%d:R%d", r2, r1);
+ break;
+ case 'k': /* k factor; word 1 [0-6] */
+ bprint(ip, "%x", w1&0x7f);
+ break;
+ case 'm': /* register mask; word 1 [0-7] */
+ bprint(ip, "%x", w1&0xff);
+ break;
+ case 'o': /* bit field offset; word1: [6-10] */
+ bprint(ip, "%d", (w1>>6)&0x3f);
+ break;
+ case 'p': /* conditional predicate; opcode: [0-5]
+ only bits 0-4 are defined */
+ bprint(ip, fcond[op&0x1f]);
+ break;
+ case 'q': /* 3-bit immediate value; opcode[9-11] */
+ r1 = (op>>9)&0x07;
+ if (r1 == 0)
+ *ip->curr++ = '8';
+ else
+ *ip->curr++ = r1+'0';
+ break;
+ case 'r': /* register type & number; word 1: [12-15] */
+ bprint(ip, regname[(w1>>12)&0x0f]);
+ break;
+ case 's': /* size; opcode [6-7] */
+ *ip->curr = sztab[((op>>6)&0x03)+1];
+ if (*ip->curr++ == '?')
+ ip->errmsg = "bad size code";
+ break;
+ case 't': /* text offset */
+ ip->curr += symoff(ip->curr, ip->end-ip->curr,
+ ip->and[currand++].u0.immediate+ip->addr+2, CTEXT);
+ break;
+ case 'u': /* register number; word 1: [6-8] */
+ *ip->curr++ = ((w1>>6)&0x07)+'0';
+ break;
+ case 'w': /* bit field width; word 1: [0-4] */
+ bprint(ip, "%d", w1&0x0f);
+ break;
+ case 'x': /* register number; opcode: [9-11] */
+ *ip->curr++ = ((op>>9)&0x07)+'0';
+ break;
+ case 'y': /* register number; opcode: [0-2] */
+ *ip->curr++ = (op&0x07)+'0';
+ break;
+ case 'z': /* shift count; opcode: [9-11] */
+ *ip->curr++ = ((op>>9)&0x07)+'0';
+ break;
+ case 'A': /* register number; word 2: [0-2] */
+ *ip->curr++ = (ip->raw[2]&0x07)+'0';
+ break;
+ case 'B': /* float source reg; word 1: [10-12] */
+ *ip->curr++ = ((w1>>10)&0x07)+'0';
+ break;
+ case 'C': /* cache identifier; opcode: [6-7] */
+ bprint(ip, cachetab[(op>>6)&0x03]);
+ break;
+ case 'D': /* float dest reg; word 1: [7-9] */
+ *ip->curr++ = ((w1>>7)&0x07)+'0';
+ break;
+ case 'E': /* destination EA; opcode: [6-11] */
+ pea((op>>9)&0x07, ip, &ip->and[currand++]);
+ break;
+ case 'F': /* float dest register(s); word 1: [7-9] & [10-12] */
+ r1 = (w1>>7)&0x07;
+ r2 = (w1>>10)&0x07;
+ if (r1 == r2)
+ bprint(ip, "F%d", r1);
+ else
+ bprint(ip, "F%d,F%d", r2, r1);
+ break;
+ case 'H': /* MMU register; word 1 [10-13] */
+ bprint(ip, mmutab[(w1>>10)&0x03]);
+ if (ip->curr[-1] == '?')
+ ip->errmsg = "bad mmu register";
+ break;
+ case 'I': /* MMU function code mask; word 1: [5-8] */
+ bprint(ip, "%x", (w1>>4)&0x0f);
+ break;
+ case 'K': /* dynamic k-factor register; word 1: [5-8] */
+ bprint(ip, "%d", (w1>>4)&0x0f);
+ break;
+ case 'L': /* MMU function code; word 1: [0-6] */
+ if (w1&0x10)
+ bprint(ip, "%x", w1&0x0f);
+ else if (w1&0x08)
+ bprint(ip, "R%d",w1&0x07);
+ else if (w1&0x01)
+ bprint(ip, "DFC");
+ else
+ bprint(ip, "SFC");
+ break;
+ case 'N': /* control register; word 1: [0-11] */
+ r1 = w1&0xfff;
+ if (r1&0x800)
+ bprint(ip, crtab1[r1&0x07]);
+ else
+ bprint(ip, crtab0[r1&0x07]);
+ break;
+ case 'P': /* conditional predicate; word 1: [0-5] */
+ bprint(ip, fcond[w1&0x1f]);
+ break;
+ case 'R': /* register type & number; word 2 [12-15] */
+ bprint(ip, regname[(ip->raw[2]>>12)&0x0f]);
+ break;
+ case 'S': /* float source type code; word 1: [10-12] */
+ *ip->curr = typetab[(w1>>10)&0x07];
+ if (*ip->curr++ == '?')
+ ip->errmsg = "bad float type";
+ break;
+ case 'U': /* register number; word 2: [6-8] */
+ *ip->curr++ = ((ip->raw[2]>>6)&0x07)+'0';
+ break;
+ case 'Z': /* ATC level number; word 1: [10-12] */
+ bprint(ip, "%x", (w1>>10)&0x07);
+ break;
+ case '1': /* effective address in second operand*/
+ pea(op&0x07, ip, &ip->and[1]);
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+static int
+dispsize(Inst *ip)
+{
+ ushort ext;
+ static int dsize[] = {0, 0, 1, 2}; /* in words */
+
+ if (get2(mymap, ip->addr+ip->n*2, &ext) < 0)
+ return -1;
+ if ((ext&0x100) == 0)
+ return 1;
+ return dsize[(ext>>4)&0x03]+dsize[ext&0x03]+1;
+}
+
+static int
+immsize(Inst *ip, int mode)
+{
+ static int fsize[] = { 2, 2, 6, 12, 1, 4, 1, -1 };
+ static int isize[] = { 1, 1, 2, -1 };
+
+ switch(mode)
+ {
+ case EAM_B: /* byte */
+ case EAALL_B:
+ case EADI_W: /* word */
+ case EAALL_W:
+ return 1;
+ case EADI_L: /* long */
+ case EAALL_L:
+ return 2;
+ case EAFLT: /* floating point - size in bits 10-12 or word 1 */
+ return fsize[(ip->raw[1]>>10)&0x07];
+ case IV: /* size encoded in bits 6&7 of opcode word */
+ default:
+ return isize[(ip->raw[0]>>6)&0x03];
+ }
+ return -1;
+}
+
+static int
+easize(Inst *ip, int ea, int mode)
+{
+ switch((ea>>3)&0x07)
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ return 0;
+ case 0x05:
+ return 1;
+ case 0x06:
+ return dispsize(ip);
+ case 0x07:
+ switch(ea&0x07)
+ {
+ case 0x00:
+ case 0x02:
+ return 1;
+ case 0x01:
+ return 2;
+ case 0x03:
+ return dispsize(ip);
+ case 0x04:
+ return immsize(ip, mode);
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+static int
+instrsize(Inst *ip, Optable *op)
+{
+ int i, t, mode;
+ short opcode;
+
+ opcode = ip->raw[0];
+ for (i = 0; i < nelem(op->opdata) && op->opdata[i]; i++) {
+ mode = op->opdata[i];
+ switch(mode)
+ {
+ case EAPI: /* normal EA modes */
+ case EACA:
+ case EACAD:
+ case EACAPI:
+ case EACAPD:
+ case EAMA:
+ case EADA:
+ case EAA:
+ case EAC:
+ case EACPI:
+ case EACD:
+ case EAD:
+ case EAM:
+ case EAM_B:
+ case EADI:
+ case EADI_L:
+ case EADI_W:
+ case EAALL:
+ case EAALL_L:
+ case EAALL_W:
+ case EAALL_B:
+ case EAFLT:
+ t = easize(ip, opcode&0x3f, mode);
+ if (t < 0)
+ return -1;
+ ip->n += t;
+ break;
+ case EADDA: /* stupid bit flop required */
+ t = ((opcode>>9)&0x07)|((opcode>>3)&0x38);
+ t = easize(ip, t, mode);
+ if (t < 0)
+ return -1;
+ ip->n += t;
+ break;
+ case BREAC: /* EAC JMP or CALL operand */
+ /* easy displacements for follow set */
+ if ((opcode&0x038) == 0x28 || (opcode&0x3f) == 0x3a) {
+ if (i16(ip, &ip->and[i].u0.immediate) < 0)
+ return -1;
+ } else {
+ t = easize(ip, opcode&0x3f, mode);
+ if (t < 0)
+ return -1;
+ ip->n += t;
+ }
+ break;
+ case I16: /* 16 bit immediate */
+ case C16: /* CAS2 16 bit immediate */
+ ip->n++;
+ break;
+ case BR16: /* 16 bit branch displacement */
+ if (i16(ip, &ip->and[i].u0.immediate) < 0)
+ return -1;
+ break;
+ case BR32: /* 32 bit branch displacement */
+ if (i32(ip, &ip->and[i].u0.immediate) < 0)
+ return -1;
+ break;
+ case I32: /* 32 bit immediate */
+ ip->n += 2;
+ break;
+ case IV: /* immediate data depends on size field */
+ t = (ip->raw[0]>>6)&0x03;
+ if (t < 2)
+ ip->n++;
+ else if (t == 2)
+ ip->n += 2;
+ else
+ return -1;
+ break;
+ case BR8: /* loony branch displacement format */
+ t = opcode&0xff;
+ if (t == 0) {
+ if (i16(ip, &ip->and[i].u0.immediate) < 0)
+ return -1;
+ } else if (t == 0xff) {
+ if (i32(ip, &ip->and[i].u0.immediate) < 0)
+ return -1;
+ } else {
+ ip->and[i].u0.immediate = t;
+ if (t & 0x80)
+ ip->and[i].u0.immediate |= ~0xff;
+ }
+ break;
+ case STACK: /* Dummy operand for Return instructions */
+ case OP8: /* weird movq instruction */
+ case I8: /* must be two-word opcode */
+ default:
+ break;
+ }
+ }
+ return 1;
+}
+
+static int
+eaval(Inst *ip, Operand *ap, Rgetter rget)
+{
+ int reg;
+ char buf[8];
+
+ reg = ip->raw[0]&0x07;
+ switch(ap->eatype)
+ {
+ case AInd:
+ sprint(buf, "A%d", reg);
+ return (*rget)(mymap, buf);
+ case PDisp:
+ return ip->addr+2+ap->u0.s0.disp;
+ case ADisp:
+ sprint(buf, "A%d", reg);
+ return ap->u0.s0.disp+(*rget)(mymap, buf);
+ case ABS:
+ return ap->u0.immediate;
+ default:
+ return 0;
+ }
+}
+
+static int
+m68020instlen(Map *map, ulong pc)
+{
+ Inst i;
+ Optable *op;
+
+ mymap = map;
+ i.addr = pc;
+ i.errmsg = 0;
+ op = instruction(&i);
+ if (op && instrsize(&i, op) > 0)
+ return i.n*2;
+ return -1;
+}
+
+static int
+m68020foll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ int j;
+ Inst i;
+ Optable *op;
+
+ mymap = map;
+ i.addr = pc;
+ i.errmsg = 0;
+ op = instruction(&i);
+ if (op == 0 || instrsize(&i, op) < 0)
+ return -1;
+ for (j = 0; j < nelem(op->opdata) && op->opdata[j]; j++) {
+ switch(op->opdata[j])
+ {
+ case BREAC: /* CALL, JMP, JSR */
+ foll[0] = pc+2+eaval(&i, &i.and[j], rget);
+ return 1;
+ case BR8: /* Bcc, BSR, & BRA */
+ case BR16: /* FBcc, FDBcc, DBcc */
+ case BR32: /* FBcc */
+ foll[0] = pc+i.n*2;
+ foll[1] = pc+2+i.and[j].u0.immediate;
+ return 2;
+ case STACK: /* RTR, RTS, RTD */
+ if (get4(map, (*rget)(map, mach->sp), (long*) foll) < 0)
+ return -1;
+ return 1;
+ default:
+ break;
+ }
+ }
+ foll[0] = pc+i.n*2;
+ return 1;
+}
+
+static int
+m68020inst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ Inst i;
+ Optable *op;
+
+ USED(modifier);
+ mymap = map;
+ i.addr = pc;
+ i.curr = buf;
+ i.end = buf+n-1;
+ i.errmsg = 0;
+ op = instruction(&i);
+ if (!op)
+ return -1;
+ if (decode(&i, op) > 0)
+ formatins(op->format, &i);
+ if (i.errmsg) {
+ if (i.curr != buf)
+ bprint(&i, "\t\t;");
+ bprint(&i, "%s: ", i.errmsg);
+ dumpinst(&i, i.curr, i.end-i.curr);
+ }
+ return i.n*2;
+}
+
+static int
+m68020das(Map *map, ulong pc, char *buf, int n)
+{
+ Inst i;
+ Optable *op;
+
+ mymap = map;
+ i.addr = pc;
+ i.curr = buf;
+ i.end = buf+n-1;
+ i.errmsg = 0;
+
+ op = instruction(&i);
+ if (!op)
+ return -1;
+ decode(&i, op);
+ if (i.errmsg)
+ bprint(&i, "%s: ", i.errmsg);
+ dumpinst(&i, i.curr, i.end-i.curr);
+ return i.n*2;
+}
diff --git a/utils/libmach/2obj.c b/utils/libmach/2obj.c
new file mode 100644
index 00000000..368e1ec7
--- /dev/null
+++ b/utils/libmach/2obj.c
@@ -0,0 +1,137 @@
+/*
+ * 2obj.c - identify and parse a 68020 object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "2c/2.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char sym;
+ char flags;
+};
+static Addr addr(Biobuf *);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is2(char *t)
+{
+ uchar *s = (uchar *)t;
+
+ return s[0] == (ANAME&0xff) /* aslo = ANAME */
+ && s[1] == ((ANAME>>8)&0xff) /* ashi = ANAME */
+ && s[2] == D_FILE /* type */
+ && s[3] == 1 /* sym */
+ && s[4] == '<'; /* name of file */
+}
+
+int
+_read2(Biobuf *bp, Prog *p)
+{
+ int as, n, c;
+ Addr a;
+
+ as = Bgetc(bp); /* as(low) */
+ if(as < 0)
+ return 0;
+ c = Bgetc(bp); /* as(high) */
+ if(c < 0)
+ return 0;
+ as |= ((c & 0xff) << 8);
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 4); /*lineno: low, high, lowhigh, highigh*/
+ a = addr(bp);
+ addr(bp);
+ if(!(a.flags & T_SYM))
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ int t;
+ long off;
+
+ a.flags = Bgetc(bp); /* flags */
+ a.sym = -1;
+ off = 0;
+ if(a.flags & T_FIELD)
+ skip(bp, 2);
+ if(a.flags & T_INDEX)
+ skip(bp, 7);
+ if(a.flags & T_OFFSET){
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ }
+ if(a.flags & T_SYM)
+ a.sym = Bgetc(bp);
+ if(a.flags & T_FCONST)
+ skip(bp, 8);
+ else if(a.flags & T_SCONST)
+ skip(bp, NSNAME);
+ else{
+ t = Bgetc(bp);
+ if(a.flags & T_TYPE)
+ t |= Bgetc(bp) << 8;
+ t &= D_MASK;
+ if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
+ _offset(a.sym, off);
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/4.c b/utils/libmach/4.c
new file mode 100644
index 00000000..3b1f38dd
--- /dev/null
+++ b/utils/libmach/4.c
@@ -0,0 +1,139 @@
+/*
+ * mips definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "ureg4.h"
+#include "mach.h"
+
+#define FPREGBYTES 4
+#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x)
+
+#define SP REGOFF(u0.sp)
+#define PC REGOFF(pc)
+#define R1 REGOFF(hr1)
+#define R31 REGOFF(hr31)
+#define FP_REG(x) (R1+8+FPREGBYTES*(x))
+
+#define REGSIZE sizeof(struct Ureg)
+#define FPREGSIZE (FPREGBYTES*33)
+
+Reglist mips2reglist[] = {
+ {"STATUS", REGOFF(status), RINT|RRDONLY, 'X'},
+ {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'},
+ {"BADVADDR", REGOFF(badvaddr), RINT|RRDONLY, 'X'},
+ {"TLBVIRT", REGOFF(tlbvirt), RINT|RRDONLY, 'X'},
+ {"HI", REGOFF(hhi), RINT|RRDONLY, 'Y'},
+ {"LO", REGOFF(hlo), RINT|RRDONLY, 'Y'},
+ {"PC", PC, RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"R31", R31, RINT, 'Y'},
+ {"R30", REGOFF(hr30), RINT, 'Y'},
+ {"R28", REGOFF(hr28), RINT, 'Y'},
+ {"R27", REGOFF(hr27), RINT, 'Y'},
+ {"R26", REGOFF(hr26), RINT, 'Y'},
+ {"R25", REGOFF(hr25), RINT, 'Y'},
+ {"R24", REGOFF(hr24), RINT, 'Y'},
+ {"R23", REGOFF(hr23), RINT, 'Y'},
+ {"R22", REGOFF(hr22), RINT, 'Y'},
+ {"R21", REGOFF(hr21), RINT, 'Y'},
+ {"R20", REGOFF(hr20), RINT, 'Y'},
+ {"R19", REGOFF(hr19), RINT, 'Y'},
+ {"R18", REGOFF(hr18), RINT, 'Y'},
+ {"R17", REGOFF(hr17), RINT, 'Y'},
+ {"R16", REGOFF(hr16), RINT, 'Y'},
+ {"R15", REGOFF(hr15), RINT, 'Y'},
+ {"R14", REGOFF(hr14), RINT, 'Y'},
+ {"R13", REGOFF(hr13), RINT, 'Y'},
+ {"R12", REGOFF(hr12), RINT, 'Y'},
+ {"R11", REGOFF(hr11), RINT, 'Y'},
+ {"R10", REGOFF(hr10), RINT, 'Y'},
+ {"R9", REGOFF(hr9), RINT, 'Y'},
+ {"R8", REGOFF(hr8), RINT, 'Y'},
+ {"R7", REGOFF(hr7), RINT, 'Y'},
+ {"R6", REGOFF(hr6), RINT, 'Y'},
+ {"R5", REGOFF(hr5), RINT, 'Y'},
+ {"R4", REGOFF(hr4), RINT, 'Y'},
+ {"R3", REGOFF(hr3), RINT, 'Y'},
+ {"R2", REGOFF(hr2), RINT, 'Y'},
+ {"R1", REGOFF(hr1), RINT, 'Y'},
+ {"F0", FP_REG(0), RFLT, 'F'},
+ {"F1", FP_REG(1), RFLT, 'f'},
+ {"F2", FP_REG(2), RFLT, 'F'},
+ {"F3", FP_REG(3), RFLT, 'f'},
+ {"F4", FP_REG(4), RFLT, 'F'},
+ {"F5", FP_REG(5), RFLT, 'f'},
+ {"F6", FP_REG(6), RFLT, 'F'},
+ {"F7", FP_REG(7), RFLT, 'f'},
+ {"F8", FP_REG(8), RFLT, 'F'},
+ {"F9", FP_REG(9), RFLT, 'f'},
+ {"F10", FP_REG(10), RFLT, 'F'},
+ {"F11", FP_REG(11), RFLT, 'f'},
+ {"F12", FP_REG(12), RFLT, 'F'},
+ {"F13", FP_REG(13), RFLT, 'f'},
+ {"F14", FP_REG(14), RFLT, 'F'},
+ {"F15", FP_REG(15), RFLT, 'f'},
+ {"F16", FP_REG(16), RFLT, 'F'},
+ {"F17", FP_REG(17), RFLT, 'f'},
+ {"F18", FP_REG(18), RFLT, 'F'},
+ {"F19", FP_REG(19), RFLT, 'f'},
+ {"F20", FP_REG(20), RFLT, 'F'},
+ {"F21", FP_REG(21), RFLT, 'f'},
+ {"F22", FP_REG(22), RFLT, 'F'},
+ {"F23", FP_REG(23), RFLT, 'f'},
+ {"F24", FP_REG(24), RFLT, 'F'},
+ {"F25", FP_REG(25), RFLT, 'f'},
+ {"F26", FP_REG(26), RFLT, 'F'},
+ {"F27", FP_REG(27), RFLT, 'f'},
+ {"F28", FP_REG(28), RFLT, 'F'},
+ {"F29", FP_REG(29), RFLT, 'f'},
+ {"F30", FP_REG(30), RFLT, 'F'},
+ {"F31", FP_REG(31), RFLT, 'f'},
+ {"FPCR", FP_REG(32), RFLT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mmips2be =
+{
+ "mips2",
+ MMIPS2, /* machine type */
+ mips2reglist, /* register set */
+ REGSIZE, /* number of bytes in reg set */
+ FPREGSIZE, /* number of bytes in fp reg set */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R31", /* name of link register */
+ "setR30", /* static base register name */
+ 0, /* SB value */
+ 0x1000, /* page size */
+ 0xC0000000, /* kernel base */
+ 0x40000000, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 8, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
+
+Mach mmips2le =
+{
+ "mips2",
+ NMIPS2, /* machine type */
+ mips2reglist, /* register set */
+ REGSIZE, /* number of bytes in reg set */
+ FPREGSIZE, /* number of bytes in fp reg set */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R31", /* name of link register */
+ "setR30", /* static base register name */
+ 0, /* SB value */
+ 0x1000, /* page size */
+ 0xC0000000, /* kernel base */
+ 0x40000000, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 8, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/4db.c b/utils/libmach/4db.c
new file mode 100644
index 00000000..d3fa97a4
--- /dev/null
+++ b/utils/libmach/4db.c
@@ -0,0 +1,57 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+/*
+ * Mips-specific debugger interface
+ */
+
+char *mipsexcep(Map*, Rgetter);
+int mipsfoll(Map*, ulong, Rgetter, ulong*);
+int mipsinst(Map*, ulong, char, char*, int);
+int mipsdas(Map*, ulong, char*, int);
+int mipsinstlen(Map*, ulong);
+/*
+ * Debugger interface
+ */
+Machdata mipsmach2be =
+{
+ {0, 0, 0, 0xD}, /* break point */
+ 4, /* break point size */
+
+ beswab, /* short to local byte order */
+ beswal, /* long to local byte order */
+ beswav, /* vlong to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ mipsexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ beieeesftos, /* single precision float printer */
+ beieeedftos, /* double precisioin float printer */
+ mipsfoll, /* following addresses */
+ mipsinst, /* print instruction */
+ mipsdas, /* dissembler */
+ mipsinstlen, /* instruction size */
+};
+
+/*
+ * Debugger interface
+ */
+Machdata mipsmach2le =
+{
+ {0, 0, 0, 0xD}, /* break point */
+ 4, /* break point size */
+
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* vlong to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ mipsexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ leieeesftos, /* single precision float printer */
+ leieeedftos, /* double precisioin float printer */
+ mipsfoll, /* following addresses */
+ mipsinst, /* print instruction */
+ mipsdas, /* dissembler */
+ mipsinstlen, /* instruction size */
+};
diff --git a/utils/libmach/5.c b/utils/libmach/5.c
new file mode 100644
index 00000000..1210d7f2
--- /dev/null
+++ b/utils/libmach/5.c
@@ -0,0 +1,64 @@
+/*
+ * arm definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "ureg5.h"
+#include "mach.h"
+
+
+#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x)
+
+#define SP REGOFF(r13)
+#define PC REGOFF(pc)
+
+#define REGSIZE sizeof(struct Ureg)
+
+Reglist armreglist[] =
+{
+ {"LINK", REGOFF(link), RINT|RRDONLY, 'X'},
+ {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'},
+ {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"R15", PC, RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ {"R0", REGOFF(r0), RINT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach marm =
+{
+ "arm",
+ MARM, /* machine type */
+ armreglist, /* register set */
+ REGSIZE, /* register set size */
+ 0, /* fp register set size */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R15", /* name of link register */
+ "setR12", /* static base register name */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0xC0000000, /* kernel base */
+ 0, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/5db.c b/utils/libmach/5db.c
new file mode 100644
index 00000000..1a125042
--- /dev/null
+++ b/utils/libmach/5db.c
@@ -0,0 +1,1063 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+static int debug = 0;
+
+#define BITS(a, b) ((1<<(b+1))-(1<<a))
+
+#define LSR(v, s) ((ulong)(v) >> (s))
+#define ASR(v, s) ((long)(v) >> (s))
+#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
+
+
+
+typedef struct Instr Instr;
+struct Instr
+{
+ Map *map;
+ ulong w;
+ ulong addr;
+ uchar op; /* super opcode */
+
+ uchar cond; /* bits 28-31 */
+ uchar store; /* bit 20 */
+
+ uchar rd; /* bits 12-15 */
+ uchar rn; /* bits 16-19 */
+ uchar rs; /* bits 0-11 (shifter operand) */
+
+ long imm; /* rotated imm */
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+ char* err; /* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+ char* o;
+ void (*fmt)(Opcode*, Instr*);
+ ulong (*foll)(Map*, Rgetter, Instr*, ulong);
+ char* a;
+};
+
+static void format(char*, Instr*, char*);
+static char FRAMENAME[] = ".frame";
+
+/*
+ * Arm-specific debugger interface
+ */
+
+extern char *armexcep(Map*, Rgetter);
+static int armfoll(Map*, ulong, Rgetter, ulong*);
+static int arminst(Map*, ulong, char, char*, int);
+static int armdas(Map*, ulong, char*, int);
+static int arminstlen(Map*, ulong);
+
+/*
+ * Debugger interface
+ */
+Machdata armmach =
+{
+ {0, 0, 0, 0xD}, /* break point */
+ 4, /* break point size */
+
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* long to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ armexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ 0, /* single precision float printer */
+ 0, /* double precision float printer */
+ armfoll, /* following addresses */
+ arminst, /* print instruction */
+ armdas, /* dissembler */
+ arminstlen, /* instruction size */
+};
+
+char*
+armexcep(Map *map, Rgetter rget)
+{
+ long c;
+
+ c = (*rget)(map, "TYPE");
+ switch (c&0x1f) {
+ case 0x11:
+ return "Fiq interrupt";
+ case 0x12:
+ return "Mirq interrupt";
+ case 0x13:
+ return "SVC/SWI Exception";
+ case 0x17:
+ return "Prefetch Abort/Data Abort";
+ case 0x18:
+ return "Data Abort";
+ case 0x1b:
+ return "Undefined instruction/Breakpoint";
+ case 0x1f:
+ return "Sys trap";
+ default:
+ return "Undefined trap";
+ }
+}
+
+static
+char* cond[16] =
+{
+ "EQ", "NE", "CS", "CC",
+ "MI", "PL", "VS", "VC",
+ "HI", "LS", "GE", "LT",
+ "GT", "LE", 0, "NV"
+};
+
+static
+char* shtype[4] =
+{
+ "<<", ">>", "->", "@>"
+};
+
+static
+char *hb[4] =
+{
+ "???", "HU", "B", "H"
+};
+
+static
+char* addsub[2] =
+{
+ "-", "+",
+};
+
+int
+armclass(long w)
+{
+ int op;
+
+ op = (w >> 25) & 0x7;
+ switch(op) {
+ case 0: /* data processing r,r,r */
+ op = ((w >> 4) & 0xf);
+ if(op == 0x9) {
+ op = 48+16; /* mul */
+ if(w & (1<<24)) {
+ op += 2;
+ if(w & (1<<22))
+ op++; /* swap */
+ break;
+ }
+ if(w & (1<<21))
+ op++; /* mla */
+ break;
+ }
+ if ((op & 0x9) == 0x9) /* ld/st byte/half s/u */
+ {
+ op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ }
+ op = (w >> 21) & 0xf;
+ if(w & (1<<4))
+ op += 32;
+ else
+ if(w & (31<<7))
+ op += 16;
+ break;
+ case 1: /* data processing i,r,r */
+ op = (48) + ((w >> 21) & 0xf);
+ break;
+ case 2: /* load/store byte/word i(r) */
+ op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 3: /* load/store byte/word (r)(r) */
+ op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 4: /* block data transfer (r)(r) */
+ op = (48+24+4+4) + ((w >> 20) & 0x1);
+ break;
+ case 5: /* branch / branch link */
+ op = (48+24+4+4+2) + ((w >> 24) & 0x1);
+ break;
+ case 7: /* coprocessor crap */
+ op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
+ break;
+ default:
+ op = (48+24+4+4+2+2+4);
+ break;
+ }
+ return op;
+}
+
+static int
+decode(Map *map, ulong pc, Instr *i)
+{
+ long w;
+
+ if(get4(map, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->w = w;
+ i->addr = pc;
+ i->cond = (w >> 28) & 0xF;
+ i->op = armclass(w);
+ i->map = map;
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+plocal(Instr *i)
+{
+ char *reg;
+ Symbol s;
+ char *fn;
+ int class;
+ int offset;
+
+ if(!findsym(i->addr, CTEXT, &s)) {
+ if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
+ return 0;
+ }
+ fn = s.name;
+ if (!findlocal(&s, FRAMENAME, &s)) {
+ if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
+ return 0;
+ }
+ if(s.value > i->imm) {
+ class = CAUTO;
+ offset = s.value-i->imm;
+ reg = "(SP)";
+ } else {
+ class = CPARAM;
+ offset = i->imm-s.value-4;
+ reg = "(FP)";
+ }
+ if(!getauto(&s, offset, class, &s)) {
+ if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
+ class == CAUTO ? " auto" : "param", offset);
+ return 0;
+ }
+ bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
+ return 1;
+}
+
+/*
+ * Print value v as name[+offset]
+ */
+int
+gsymoff(char *buf, int n, long v, int space)
+{
+ Symbol s;
+ int r;
+ long delta;
+
+ r = delta = 0; /* to shut compiler up */
+ if (v) {
+ r = findsym(v, space, &s);
+ if (r)
+ delta = v-s.value;
+ if (delta < 0)
+ delta = -delta;
+ }
+ if (v == 0 || r == 0 || delta >= 4096)
+ return snprint(buf, n, "#%lux", v);
+ if (strcmp(s.name, ".string") == 0)
+ return snprint(buf, n, "#%lux", v);
+ if (!delta)
+ return snprint(buf, n, "%s", s.name);
+ if (s.type != 't' && s.type != 'T')
+ return snprint(buf, n, "%s+%lux", s.name, v-s.value);
+ else
+ return snprint(buf, n, "#%lux", v);
+}
+
+static void
+armdps(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = (i->w >> 0) & 0xf;
+ if(i->rn == 15 && i->rs == 0) {
+ if(i->op == 8) {
+ format("MOVW", i,"CPSR, R%d");
+ return;
+ } else
+ if(i->op == 10) {
+ format("MOVW", i,"SPSR, R%d");
+ return;
+ }
+ } else
+ if(i->rn == 9 && i->rd == 15) {
+ if(i->op == 9) {
+ format("MOVW", i, "R%s, CPSR");
+ return;
+ } else
+ if(i->op == 11) {
+ format("MOVW", i, "R%s, SPSR");
+ return;
+ }
+ }
+ format(o->o, i, o->a);
+}
+
+static void
+armdpi(Opcode *o, Instr *i)
+{
+ ulong v;
+ int c;
+
+ v = (i->w >> 0) & 0xff;
+ c = (i->w >> 8) & 0xf;
+ while(c) {
+ v = (v<<30) | (v>>2);
+ c--;
+ }
+ i->imm = v;
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0x0f;
+
+ /* RET is encoded as ADD #0,R14,R15 */
+ if((i->w & 0x0fffffff) == 0x028ef000){
+ format("RET%C", i, "");
+ return;
+ }
+ if((i->w & 0x0ff0ffff) == 0x0280f000){
+ format("B%C", i, "0(R%n)");
+ return;
+ }
+ format(o->o, i, o->a);
+}
+
+static void
+armsdti(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = i->w & 0xfff;
+ if(!(i->w & (1<<23)))
+ v = -v;
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->imm = v;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ /* RET is encoded as LW.P x,R13,R15 */
+ if ((i->w & 0x0ffff000) == 0x049df000)
+ {
+ format("RET%C%p", i, "%I");
+ return;
+ }
+ format(o->o, i, o->a);
+}
+
+/* arm V4 ld/st halfword, signed byte */
+static void
+armhwby(Opcode *o, Instr *i)
+{
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
+ if (!(i->w & (1 << 23)))
+ i->imm = - i->imm;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = (i->w >> 0) & 0xf;
+ format(o->o, i, o->a);
+}
+
+static void
+armsdts(Opcode *o, Instr *i)
+{
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->rs = (i->w >> 0) & 0xf;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ format(o->o, i, o->a);
+}
+
+static void
+armbdt(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 21) & 0x3; /* S & W bits */
+ i->rn = (i->w >> 16) & 0xf;
+ i->imm = i->w & 0xffff;
+ if(i->w == 0xe8fd8000)
+ format("RFE", i, "");
+ else
+ format(o->o, i, o->a);
+}
+
+static void
+armund(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armcdt(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armunk(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armb(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = i->w & 0xffffff;
+ if(v & 0x800000)
+ v |= ~0xffffff;
+ i->imm = (v<<2) + i->addr + 8;
+ format(o->o, i, o->a);
+}
+
+static void
+armco(Opcode *o, Instr *i) /* coprocessor instructions */
+{
+ int op, p, cp;
+
+ char buf[1024];
+
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0xf;
+ cp = (i->w >> 8) & 0xf;
+ p = (i->w >> 5) & 0x7;
+ if(i->w&(1<<4)) {
+ op = (i->w >> 21) & 0x07;
+ snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ } else {
+ op = (i->w >> 20) & 0x0f;
+ snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ }
+ format(o->o, i, buf);
+}
+
+static int
+armcondpass(Map *map, Rgetter rget, uchar cond)
+{
+ ulong psr;
+ uchar n;
+ uchar z;
+ uchar c;
+ uchar v;
+
+ psr = rget(map, "PSR");
+ n = (psr >> 31) & 1;
+ z = (psr >> 30) & 1;
+ c = (psr >> 29) & 1;
+ v = (psr >> 28) & 1;
+
+ switch(cond) {
+ case 0: return z;
+ case 1: return !z;
+ case 2: return c;
+ case 3: return !c;
+ case 4: return n;
+ case 5: return !n;
+ case 6: return v;
+ case 7: return !v;
+ case 8: return c && !z;
+ case 9: return !c || z;
+ case 10: return n == v;
+ case 11: return n != v;
+ case 12: return !z && (n == v);
+ case 13: return z && (n != v);
+ case 14: return 1;
+ case 15: return 0;
+ }
+ return 0;
+}
+
+static ulong
+armshiftval(Map *map, Rgetter rget, Instr *i)
+{
+ if(i->w & (1 << 25)) { /* immediate */
+ ulong imm = i->w & BITS(0, 7);
+ ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
+ return ROR(imm, s);
+ } else {
+ char buf[8];
+ ulong v;
+ ulong s = (i->w & BITS(7,11)) >> 7;
+
+ sprint(buf, "R%ld", i->w & 0xf);
+ v = rget(map, buf);
+
+ switch((i->w & BITS(4, 6)) >> 4) {
+ case 0: /* LSLIMM */
+ return v << s;
+ case 1: /* LSLREG */
+ sprint(buf, "R%lud", s >> 1);
+ s = rget(map, buf) & 0xFF;
+ if(s >= 32) return 0;
+ return v << s;
+ case 2: /* LSRIMM */
+ return LSR(v, s);
+ case 3: /* LSRREG */
+ sprint(buf, "R%ld", s >> 1);
+ s = rget(map, buf) & 0xFF;
+ if(s >= 32) return 0;
+ return LSR(v, s);
+ case 4: /* ASRIMM */
+ if(s == 0) {
+ if((v & (1U<<31)) == 0)
+ return 0;
+ return 0xFFFFFFFF;
+ }
+ return ASR(v, s);
+ case 5: /* ASRREG */
+ sprint(buf, "R%ld", s >> 1);
+ s = rget(map, buf) & 0xFF;
+ if(s >= 32) {
+ if((v & (1U<<31)) == 0)
+ return 0;
+ return 0xFFFFFFFF;
+ }
+ return ASR(v, s);
+ case 6: /* RORIMM */
+ if(s == 0) {
+ ulong c = (rget(map, "PSR") >> 29) & 1;
+
+ return (c << 31) | LSR(v, 1);
+ }
+ return ROR(v, s);
+ case 7: /* RORREG */
+ sprint(buf, "R%ld", (s>>1)&0xF);
+ s = rget(map, buf);
+ if(s == 0 || (s & 0xF) == 0)
+ return v;
+ return ROR(v, s & 0xF);
+ }
+ }
+ return 0;
+}
+
+static int
+nbits(ulong v)
+{
+ int n = 0;
+ int i;
+
+ for(i=0; i < 32 ; i++) {
+ if(v & 1) ++n;
+ v >>= 1;
+ }
+
+ return n;
+}
+
+static ulong
+armmaddr(Map *map, Rgetter rget, Instr *i)
+{
+ ulong v;
+ ulong nb;
+ char buf[8];
+ ulong rn;
+
+ rn = (i->w >> 16) & 0xf;
+ sprint(buf,"R%ld", rn);
+
+ v = rget(map, buf);
+ nb = nbits(i->w & ((1 << 15) - 1));
+
+ switch((i->w >> 23) & 3) {
+ case 0: return (v - (nb*4)) + 4;
+ case 1: return v;
+ case 2: return v - (nb*4);
+ case 3: return v + 4;
+ }
+ return 0;
+}
+
+static ulong
+armaddr(Map *map, Rgetter rget, Instr *i)
+{
+ char buf[8];
+ ulong rn;
+
+ sprint(buf, "R%ld", (i->w >> 16) & 0xf);
+ rn = rget(map, buf);
+
+ if((i->w & (1<<24)) == 0) { /* POSTIDX */
+ sprint(buf, "R%ld", rn);
+ return rget(map, buf);
+ }
+
+ if((i->w & (1<<25)) == 0) { /* OFFSET */
+ sprint(buf, "R%ld", rn);
+ if(i->w & (1U<<23))
+ return rget(map, buf) + (i->w & BITS(0,11));
+ return rget(map, buf) - (i->w & BITS(0,11));
+ } else { /* REGOFF */
+ ulong index = 0;
+ uchar c;
+ uchar rm;
+
+ sprint(buf, "R%ld", i->w & 0xf);
+ rm = rget(map, buf);
+
+ switch((i->w & BITS(5,6)) >> 5) {
+ case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break;
+ case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break;
+ case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break;
+ case 3:
+ if((i->w & BITS(7,11)) == 0) {
+ c = (rget(map, "PSR") >> 29) & 1;
+ index = c << 31 | LSR(rm, 1);
+ } else {
+ index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
+ }
+ break;
+ }
+ if(i->w & (1<<23))
+ return rn + index;
+ return rn - index;
+ }
+}
+
+static ulong
+armfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ char buf[8];
+ int r;
+
+ r = (i->w >> 12) & 0xf;
+ if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
+ return pc+4;
+
+ r = (i->w >> 16) & 0xf;
+ sprint(buf, "R%d", r);
+
+ return rget(map, buf) + armshiftval(map, rget, i);
+}
+
+static ulong
+armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ ulong v;
+ ulong addr;
+
+ v = i->w & 1<<15;
+ if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
+ return pc+4;
+
+ addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
+ if(get4(map, addr, (long*)&v) < 0) {
+ werrstr("can't read addr: %r");
+ return -1;
+ }
+ return v;
+}
+
+static ulong
+armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
+ return pc+4;
+
+ return pc + (((signed long)i->w << 8) >> 6) + 8;
+}
+
+static ulong
+armfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ ulong rd;
+ ulong v;
+
+ rd = (i->w >> 12) & 0xf;
+ if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
+ return pc+4;
+
+ /* LDR */
+ /* BUG: Needs LDH/B, too */
+ if((i->w>>26)&0x3 == 1) {
+ if(get4(map, armaddr(map, rget, i), (long*)&v) < 0) {
+ werrstr("can't read instruction: %r");
+ return pc+4;
+ }
+ return v;
+ }
+
+ /* MOV */
+ v = armshiftval(map, rget, i);
+
+ return v;
+}
+
+static Opcode opcodes[] =
+{
+ "AND%C%S", armdps, 0, "R%s,R%n,R%d",
+ "EOR%C%S", armdps, 0, "R%s,R%n,R%d",
+ "SUB%C%S", armdps, 0, "R%s,R%n,R%d",
+ "RSB%C%S", armdps, 0, "R%s,R%n,R%d",
+ "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d",
+ "ADC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "SBC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "RSC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "TST%C%S", armdps, 0, "R%s,R%n",
+ "TEQ%C%S", armdps, 0, "R%s,R%n",
+ "CMP%C%S", armdps, 0, "R%s,R%n",
+ "CMN%C%S", armdps, 0, "R%s,R%n",
+ "ORR%C%S", armdps, 0, "R%s,R%n,R%d",
+ "MOVW%C%S", armdps, armfmov, "R%s,R%d",
+ "BIC%C%S", armdps, 0, "R%s,R%n,R%d",
+ "MVN%C%S", armdps, 0, "R%s,R%d",
+
+/* 16 */
+ "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d",
+ "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "TST%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "CMP%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "CMN%C%S", armdps, 0, "(R%s%h%m),R%n",
+ "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d",
+ "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
+ "MVN%C%S", armdps, 0, "(R%s%h%m),R%d",
+
+/* 32 */
+ "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d",
+ "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "TST%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n",
+ "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d",
+ "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
+ "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d",
+
+/* 48 */
+ "AND%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d",
+ "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "TST%C%S", armdpi, 0, "$#%i,R%n",
+ "TEQ%C%S", armdpi, 0, "$#%i,R%n",
+ "CMP%C%S", armdpi, 0, "$#%i,R%n",
+ "CMN%C%S", armdpi, 0, "$#%i,R%n",
+ "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "MOVW%C%S", armdpi, armfmov, "$#%i,R%d",
+ "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d",
+ "MVN%C%S", armdpi, 0, "$#%i,R%d",
+
+/* 48+16 */
+ "MUL%C%S", armdpi, 0, "R%s,R%M,R%n",
+ "MULA%C%S", armdpi, 0, "R%s,R%M,R%n,R%d",
+ "SWPW", armdpi, 0, "R%s,(R%n),R%d",
+ "SWPB", armdpi, 0, "R%s,(R%n),R%d",
+
+/* 48+16+4 */
+ "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)",
+ "MOV%u%C%p", armhwby, 0, "R%d,%I",
+ "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d",
+ "MOV%u%C%p", armhwby, armfmov, "%I,R%d",
+
+/* 48+24 */
+ "MOVW%C%p", armsdti, 0, "R%d,%I",
+ "MOVB%C%p", armsdti, 0, "R%d,%I",
+ "MOVW%C%p", armsdti, armfmov, "%I,R%d",
+ "MOVBU%C%p", armsdti, armfmov, "%I,R%d",
+
+ "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
+ "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
+ "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
+ "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
+
+ "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)",
+ "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]",
+
+ "B%C", armb, armfbranch, "%b",
+ "BL%C", armb, armfbranch, "%b",
+
+ "CDP%C", armco, 0, "",
+ "CDP%C", armco, 0, "",
+ "MCR%C", armco, 0, "",
+ "MRC%C", armco, 0, "",
+
+ "UNK", armunk, 0, "",
+};
+
+static void
+gaddr(Instr *i)
+{
+ *i->curr++ = '$';
+ i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
+}
+
+static char *mode[] = { 0, "IA", "DB", "IB" };
+static char *pw[] = { "P", "PW", 0, "W" };
+static char *sw[] = { 0, "W", "S", "SW" };
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int j, k, m, n;
+ int g;
+ char *fmt;
+
+ if(mnemonic)
+ format(0, i, mnemonic);
+ if(f == 0)
+ return;
+ if(mnemonic)
+ if(i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if(*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 'C': /* .CONDITION */
+ if(cond[i->cond])
+ bprint(i, ".%s", cond[i->cond]);
+ break;
+
+ case 'S': /* .STORE */
+ if(i->store)
+ bprint(i, ".S");
+ break;
+
+ case 'P': /* P & U bits for block move */
+ n = (i->w >>23) & 0x3;
+ if (mode[n])
+ bprint(i, ".%s", mode[n]);
+ break;
+
+ case 'p': /* P & W bits for single data xfer*/
+ if (pw[i->store])
+ bprint(i, ".%s", pw[i->store]);
+ break;
+
+ case 'a': /* S & W bits for single data xfer*/
+ if (sw[i->store])
+ bprint(i, ".%s", sw[i->store]);
+ break;
+
+ case 's':
+ bprint(i, "%d", i->rs & 0xf);
+ break;
+
+ case 'M':
+ bprint(i, "%d", (i->w>>8) & 0xf);
+ break;
+
+ case 'm':
+ bprint(i, "%d", (i->w>>7) & 0x1f);
+ break;
+
+ case 'h':
+ bprint(i, shtype[(i->w>>5) & 0x3]);
+ break;
+
+ case 'u': /* Signed/unsigned Byte/Halfword */
+ bprint(i, hb[(i->w>>5) & 0x3]);
+ break;
+
+ case 'I':
+ if (i->rn == 13) {
+ if (plocal(i))
+ break;
+ }
+ g = 0;
+ fmt = "#%lx(R%d)";
+ if (i->rn == 15) {
+ /* convert load of offset(PC) to a load immediate */
+ if (get4(i->map, i->addr+i->imm+8, &i->imm) > 0)
+ {
+ g = 1;
+ fmt = "";
+ }
+ }
+ if (mach->sb)
+ {
+ if (i->rd == 11) {
+ ulong nxti;
+
+ if (get4(i->map, i->addr+4, (long*)&nxti) > 0) {
+ if ((nxti & 0x0e0f0fff) == 0x060c000b) {
+ i->imm += mach->sb;
+ g = 1;
+ fmt = "-SB";
+ }
+ }
+ }
+ if (i->rn == 12)
+ {
+ i->imm += mach->sb;
+ g = 1;
+ fmt = "-SB(SB)";
+ }
+ }
+ if (g)
+ {
+ gaddr(i);
+ bprint(i, fmt, i->rn);
+ }
+ else
+ bprint(i, fmt, i->imm, i->rn);
+ break;
+ case 'U': /* Add/subtract from base */
+ bprint(i, addsub[(i->w >> 23) & 1]);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->rn);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'i':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'b':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ i->imm, CTEXT);
+ break;
+
+ case 'g':
+ i->curr += gsymoff(i->curr, i->end-i->curr,
+ i->imm, CANY);
+ break;
+
+ case 'r':
+ n = i->imm&0xffff;
+ j = 0;
+ k = 0;
+ while(n) {
+ m = j;
+ while(n&0x1) {
+ j++;
+ n >>= 1;
+ }
+ if(j != m) {
+ if(k)
+ bprint(i, ",");
+ if(j == m+1)
+ bprint(i, "R%d", m);
+ else
+ bprint(i, "R%d-R%d", m, j-1);
+ k = 1;
+ }
+ j++;
+ n >>= 1;
+ }
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n-1;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+
+ (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
+ return 4;
+}
+
+static int
+arminst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ USED(modifier);
+ return printins(map, pc, buf, n);
+}
+
+static int
+armdas(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ if(i.end-i.curr > 8)
+ i.curr = _hexify(buf, i.w, 7);
+ *i.curr = 0;
+ return 4;
+}
+
+static int
+arminstlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ return 4;
+}
+
+static int
+armfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ ulong d;
+ Instr i;
+
+ if(decode(map, pc, &i) < 0)
+ return -1;
+
+ if(opcodes[i.op].foll) {
+ d = (*opcodes[i.op].foll)(map, rget, &i, pc);
+ if(d == -1)
+ return -1;
+ } else
+ d = pc+4;
+
+ foll[0] = d;
+ return 1;
+}
diff --git a/utils/libmach/5obj.c b/utils/libmach/5obj.c
new file mode 100644
index 00000000..e7e3437c
--- /dev/null
+++ b/utils/libmach/5obj.c
@@ -0,0 +1,133 @@
+/*
+ * 5obj.c - identify and parse a arm object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "5c/5.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is5(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_read5(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 6); /* scond(1), reg(1), lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/6.c b/utils/libmach/6.c
new file mode 100644
index 00000000..28c74a43
--- /dev/null
+++ b/utils/libmach/6.c
@@ -0,0 +1,117 @@
+/*
+ * x86-amd64 definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "ureg6.h"
+#include "mach.h"
+
+#define REGOFF(x) (uvlong)(&((struct Ureg *) 0)->x)
+
+#define PC REGOFF(pc)
+#define SP REGOFF(sp)
+#define AX REGOFF(ax)
+
+#define REGSIZE sizeof(struct Ureg)
+#define FP_CTLS(x) (REGSIZE+2*(x))
+#define FP_CTL(x) (REGSIZE+4*(x))
+#define FP_REG(x) (FP_CTL(8)+16*(x))
+#define XM_REG(x) (FP_CTL(8)+8*16+16*(x))
+
+#define FPREGSIZE 512 /* TO DO? currently only 0x1A0 used */
+
+Reglist amd64reglist[] = {
+ {"R15", REGOFF(r15), RINT, 'Y'},
+ {"R14", REGOFF(r14), RINT, 'Y'},
+ {"R13", REGOFF(r13), RINT, 'Y'},
+ {"R12", REGOFF(r12), RINT, 'Y'},
+ {"R11", REGOFF(r11), RINT, 'Y'},
+ {"R10", REGOFF(r10), RINT, 'Y'},
+ {"R9", REGOFF(r9), RINT, 'Y'},
+ {"R8", REGOFF(r8), RINT, 'Y'},
+ {"DI", REGOFF(di), RINT, 'X'},
+ {"SI", REGOFF(si), RINT, 'Y'},
+ {"BP", REGOFF(bp), RINT, 'Y'},
+ {"BX", REGOFF(bx), RINT, 'Y'},
+ {"DX", REGOFF(dx), RINT, 'Y'},
+ {"CX", REGOFF(cx), RINT, 'Y'},
+ {"AX", REGOFF(ax), RINT, 'Y'},
+ {"GS", REGOFF(gs), RINT, 'Y'},
+ {"FS", REGOFF(fs), RINT, 'Y'},
+ {"ES", REGOFF(es), RINT, 'Y'},
+ {"DS", REGOFF(ds), RINT, 'Y'},
+ {"TRAP", REGOFF(trap), RINT, 'Y'},
+ {"ECODE", REGOFF(ecode), RINT, 'Y'},
+ {"PC", PC, RINT, 'Y'},
+ {"CS", REGOFF(cs), RINT, 'Y'},
+ {"EFLAGS", REGOFF(flags), RINT, 'Y'},
+ {"SP", SP, RINT, 'Y'},
+ {"SS", REGOFF(ss), RINT, 'Y'},
+
+ {"FCW", FP_CTLS(0), RFLT, 'x'},
+ {"FSW", FP_CTLS(1), RFLT, 'x'},
+ {"FTW", FP_CTLS(2), RFLT, 'x'},
+ {"FOP", FP_CTLS(3), RFLT, 'x'},
+ {"FPC", FP_CTL(2), RFLT, 'Y'},
+ {"RDP", FP_CTL(4), RFLT, 'Y'},
+ {"MXCSR", FP_CTL(6), RFLT, 'X'},
+ {"MXCSRMSK", FP_CTL(7), RFLT, 'X'},
+ {"M0", FP_REG(0), RFLT, 'F'}, /* assumes double */
+ {"M1", FP_REG(1), RFLT, 'F'},
+ {"M2", FP_REG(2), RFLT, 'F'},
+ {"M3", FP_REG(3), RFLT, 'F'},
+ {"M4", FP_REG(4), RFLT, 'F'},
+ {"M5", FP_REG(5), RFLT, 'F'},
+ {"M6", FP_REG(6), RFLT, 'F'},
+ {"M7", FP_REG(7), RFLT, 'F'},
+ {"X0", XM_REG(0), RFLT, 'F'}, /* assumes double */
+ {"X1", XM_REG(1), RFLT, 'F'},
+ {"X2", XM_REG(2), RFLT, 'F'},
+ {"X3", XM_REG(3), RFLT, 'F'},
+ {"X4", XM_REG(4), RFLT, 'F'},
+ {"X5", XM_REG(5), RFLT, 'F'},
+ {"X6", XM_REG(6), RFLT, 'F'},
+ {"X7", XM_REG(7), RFLT, 'F'},
+ {"X8", XM_REG(8), RFLT, 'F'},
+ {"X9", XM_REG(9), RFLT, 'F'},
+ {"X10", XM_REG(10), RFLT, 'F'},
+ {"X11", XM_REG(11), RFLT, 'F'},
+ {"X12", XM_REG(12), RFLT, 'F'},
+ {"X13", XM_REG(13), RFLT, 'F'},
+ {"X14", XM_REG(14), RFLT, 'F'},
+ {"X15", XM_REG(15), RFLT, 'F'},
+ {"X16", XM_REG(16), RFLT, 'F'},
+/*
+ {"F0", FP_REG(7), RFLT, '3'},
+ {"F1", FP_REG(6), RFLT, '3'},
+ {"F2", FP_REG(5), RFLT, '3'},
+ {"F3", FP_REG(4), RFLT, '3'},
+ {"F4", FP_REG(3), RFLT, '3'},
+ {"F5", FP_REG(2), RFLT, '3'},
+ {"F6", FP_REG(1), RFLT, '3'},
+ {"F7", FP_REG(0), RFLT, '3'},
+*/
+ { 0 }
+};
+
+Mach mamd64=
+{
+ "amd64",
+ MI386, /* machine type */ /* TO DO */
+ amd64reglist, /* register list */
+ REGSIZE, /* size of registers in bytes */
+ FPREGSIZE, /* size of fp registers in bytes */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ 0, /* link register */
+ "setSB", /* static base register name (bogus anyways) */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0x80100000, /* kernel base */ /* TO DO: uvlong or vlong */
+ 0, /* kernel text mask */
+ 1, /* quantization of pc */
+ 8, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/6obj.c b/utils/libmach/6obj.c
new file mode 100644
index 00000000..7fb95115
--- /dev/null
+++ b/utils/libmach/6obj.c
@@ -0,0 +1,142 @@
+/*
+ * 6obj.c - identify and parse an amd64 object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "6c/6.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char sym;
+ char flags;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is6(char *t)
+{
+ uchar *s = (uchar*)t;
+
+ return s[0] == (ANAME&0xff) /* aslo = ANAME */
+ && s[1] == ((ANAME>>8)&0xff)
+ && s[2] == D_FILE /* type */
+ && s[3] == 1 /* sym */
+ && s[4] == '<'; /* name of file */
+}
+
+int
+_read6(Biobuf *bp, Prog* p)
+{
+ int as, n, c;
+ Addr a;
+
+ as = Bgetc(bp); /* as(low) */
+ if(as < 0)
+ return 0;
+ c = Bgetc(bp); /* as(high) */
+ if(c < 0)
+ return 0;
+ as |= ((c & 0xff) << 8);
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 4); /* lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(!(a.flags & T_SYM))
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ int t;
+ long l;
+ vlong off;
+
+ off = 0;
+ a.sym = -1;
+ a.flags = Bgetc(bp); /* flags */
+ if(a.flags & T_INDEX)
+ skip(bp, 2);
+ if(a.flags & T_OFFSET){
+ l = Bgetc(bp);
+ l |= Bgetc(bp) << 8;
+ l |= Bgetc(bp) << 16;
+ l |= Bgetc(bp) << 24;
+ off = l;
+ if(a.flags & T_64){
+ l = Bgetc(bp);
+ l |= Bgetc(bp) << 8;
+ l |= Bgetc(bp) << 16;
+ l |= Bgetc(bp) << 24;
+ off = ((vlong)l << 32) | (off & 0xFFFFFFFF);
+ }
+ if(off < 0)
+ off = -off;
+ }
+ if(a.flags & T_SYM)
+ a.sym = Bgetc(bp);
+ if(a.flags & T_FCONST)
+ skip(bp, 8);
+ else
+ if(a.flags & T_SCONST)
+ skip(bp, NSNAME);
+ if(a.flags & T_TYPE) {
+ t = Bgetc(bp);
+ if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
+ _offset(a.sym, off);
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/8.c b/utils/libmach/8.c
new file mode 100644
index 00000000..9c7bff11
--- /dev/null
+++ b/utils/libmach/8.c
@@ -0,0 +1,78 @@
+/*
+ * 386 definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "ureg8.h"
+#include "mach.h"
+
+#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x)
+
+#define PC REGOFF(pc)
+#define SP REGOFF(u0.sp)
+#define AX REGOFF(ax)
+
+#define REGSIZE sizeof(struct Ureg)
+#define FP_CTL(x) (REGSIZE+4*(x))
+#define FP_REG(x) (FP_CTL(7)+10*(x))
+#define FPREGSIZE (6*4+8*10)
+
+Reglist i386reglist[] = {
+ {"DI", REGOFF(di), RINT, 'X'},
+ {"SI", REGOFF(si), RINT, 'X'},
+ {"BP", REGOFF(bp), RINT, 'X'},
+ {"BX", REGOFF(bx), RINT, 'X'},
+ {"DX", REGOFF(dx), RINT, 'X'},
+ {"CX", REGOFF(cx), RINT, 'X'},
+ {"AX", REGOFF(ax), RINT, 'X'},
+ {"GS", REGOFF(gs), RINT, 'X'},
+ {"FS", REGOFF(fs), RINT, 'X'},
+ {"ES", REGOFF(es), RINT, 'X'},
+ {"DS", REGOFF(ds), RINT, 'X'},
+ {"TRAP", REGOFF(trap), RINT, 'X'},
+ {"ECODE", REGOFF(ecode), RINT, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"CS", REGOFF(cs), RINT, 'X'},
+ {"EFLAGS", REGOFF(flags), RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"SS", REGOFF(ss), RINT, 'X'},
+
+ {"E0", FP_CTL(0), RFLT, 'X'},
+ {"E1", FP_CTL(1), RFLT, 'X'},
+ {"E2", FP_CTL(2), RFLT, 'X'},
+ {"E3", FP_CTL(3), RFLT, 'X'},
+ {"E4", FP_CTL(4), RFLT, 'X'},
+ {"E5", FP_CTL(5), RFLT, 'X'},
+ {"E6", FP_CTL(6), RFLT, 'X'},
+ {"F0", FP_REG(7), RFLT, '3'},
+ {"F1", FP_REG(6), RFLT, '3'},
+ {"F2", FP_REG(5), RFLT, '3'},
+ {"F3", FP_REG(4), RFLT, '3'},
+ {"F4", FP_REG(3), RFLT, '3'},
+ {"F5", FP_REG(2), RFLT, '3'},
+ {"F6", FP_REG(1), RFLT, '3'},
+ {"F7", FP_REG(0), RFLT, '3'},
+ { 0 }
+};
+
+Mach mi386 =
+{
+ "386",
+ MI386, /* machine type */
+ i386reglist, /* register list */
+ REGSIZE, /* size of registers in bytes */
+ FPREGSIZE, /* size of fp registers in bytes */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ 0, /* link register */
+ "setSB", /* static base register name (bogus anyways) */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0x80100000, /* kernel base */
+ 0, /* kernel text mask */
+ 1, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/8db.c b/utils/libmach/8db.c
new file mode 100644
index 00000000..86b6e1f2
--- /dev/null
+++ b/utils/libmach/8db.c
@@ -0,0 +1,1850 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+/*
+ * i386-specific debugger interface
+ */
+
+static char *i386excep(Map*, Rgetter);
+
+static int i386trace(Map*, ulong, ulong, ulong, Tracer);
+static ulong i386frame(Map*, ulong, ulong, ulong, ulong);
+static int i386foll(Map*, ulong, Rgetter, ulong*);
+static int i386inst(Map*, ulong, char, char*, int);
+static int i386das(Map*, ulong, char*, int);
+static int i386instlen(Map*, ulong);
+
+static char STARTSYM[] = "_main";
+static char PROFSYM[] = "_mainp";
+static char FRAMENAME[] = ".frame";
+static char *excname[] =
+{
+ "divide error", /* 0 */
+ "debug exception", /* 1 */
+ 0,0, /* 2, 3 */
+ "overflow", /* 4 */
+ "bounds check", /* 5 */
+ "invalid opcode", /* 6 */
+ "math coprocessor emulation", /* 7 */
+ "double fault", /* 8 */
+ "math coprocessor overrun", /* 9 */
+ "invalid TSS", /* 10 */
+ "segment not present", /* 11 */
+ "stack exception", /* 12 */
+ "general protection violation", /* 13 */
+ "page fault", /* 14 */
+ 0, /* 15 */
+ "math coprocessor error", /* 16 */
+ 0,0,0,0,0,0,0, /* 17-23 */
+ "clock", /* 24 */
+ "keyboard", /* 25 */
+ 0, /* 26 */
+ "modem status", /* 27 */
+ "serial line status", /* 28 */
+ 0, /* 29 */
+ "floppy disk", /* 30 */
+ 0,0,0,0,0, /* 31-35 */
+ "mouse", /* 36 */
+ "math coprocessor", /* 37 */
+ "hard disk", /* 38 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */
+ 0,0,0,0,0,0,0,0,0, /* 55-63 */
+ "system call", /* 64 */
+};
+
+Machdata i386mach =
+{
+ {0xCC, 0, 0, 0}, /* break point: INT 3 */
+ 1, /* break point size */
+
+ leswab, /* convert short to local byte order */
+ leswal, /* convert long to local byte order */
+ leswav, /* convert vlong to local byte order */
+ i386trace, /* C traceback */
+ i386frame, /* frame finder */
+ i386excep, /* print exception */
+ 0, /* breakpoint fixup */
+ leieeesftos, /* single precision float printer */
+ leieeedftos, /* double precision float printer */
+ i386foll, /* following addresses */
+ i386inst, /* print instruction */
+ i386das, /* dissembler */
+ i386instlen, /* instruction size calculation */
+};
+
+static char*
+i386excep(Map *map, Rgetter rget)
+{
+ ulong c;
+ ulong pc;
+ static char buf[16];
+
+ c = (*rget)(map, "TRAP");
+ if(c > 64 || excname[c] == 0) {
+ if (c == 3) {
+ pc = (*rget)(map, "PC");
+ if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
+ if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
+ return "breakpoint";
+ }
+ sprint(buf, "exception %ld", c);
+ return buf;
+ } else
+ return excname[c];
+}
+
+static int
+i386trace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace)
+{
+ int i;
+ ulong osp;
+ Symbol s, f;
+
+ USED(link);
+ i = 0;
+ osp = 0;
+ while(findsym(pc, CTEXT, &s)) {
+ if (osp == sp)
+ break;
+ osp = sp;
+
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc != s.value) { /* not at first instruction */
+ if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+ sp += f.value-mach->szaddr;
+ }
+
+ if (get4(map, sp, (long *) &pc) < 0)
+ break;
+
+ if(pc == 0)
+ break;
+
+ (*trace)(map, pc, sp, &s);
+ sp += mach->szaddr;
+
+ if(++i > 40)
+ break;
+ }
+ return i;
+}
+
+static ulong
+i386frame(Map *map, ulong addr, ulong pc, ulong sp, ulong link)
+{
+ Symbol s, f;
+
+ USED(link);
+ while (findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc != s.value) { /* not first instruction */
+ if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+ sp += f.value-mach->szaddr;
+ }
+
+ if (s.value == addr)
+ return sp;
+
+ if (get4(map, sp, (long *)&pc) < 0)
+ break;
+ sp += mach->szaddr;
+ }
+ return 0;
+}
+
+ /* I386/486 - Disassembler and related functions */
+
+/*
+ * an instruction
+ */
+typedef struct Instr Instr;
+struct Instr
+{
+ uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
+ ulong addr; /* address of start of instruction */
+ int n; /* number of bytes in instruction */
+ char *prefix; /* instr prefix */
+ char *segment; /* segment override */
+ uchar jumptype; /* set to the operand type for jump/ret/call */
+ char osize; /* 'W' or 'L' */
+ char asize; /* address size 'W' or 'L' */
+ uchar mod; /* bits 6-7 of mod r/m field */
+ uchar reg; /* bits 3-5 of mod r/m field */
+ char ss; /* bits 6-7 of SIB */
+ char index; /* bits 3-5 of SIB */
+ char base; /* bits 0-2 of SIB */
+ short seg; /* segment of far address */
+ ulong disp; /* displacement */
+ ulong imm; /* immediate */
+ ulong imm2; /* second immediate operand */
+ char *curr; /* fill level in output buffer */
+ char *end; /* end of output buffer */
+ char *err; /* error message */
+};
+
+ /* 386 register (ha!) set */
+enum{
+ AX=0,
+ CX,
+ DX,
+ BX,
+ SP,
+ BP,
+ SI,
+ DI,
+};
+ /* Operand Format codes */
+/*
+%A - address size register modifier (!asize -> 'E')
+%C - Control register CR0/CR1/CR2
+%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I - second immediate operand
+%O - Operand size register modifier (!osize -> 'E')
+%T - Test register TR6/TR7
+%S - size code ('W' or 'L')
+%X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d - displacement 16-32 bits
+%e - effective address - Mod R/M value
+%f - floating point register F0-F7 - from Mod R/M register
+%g - segment register
+%i - immediate operand 8-32 bits
+%p - PC-relative - signed displacement in immediate field
+%r - Reg from Mod R/M
+%x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+ char operand[2];
+ void *proto; /* actually either (char*) or (Optable*) */
+};
+ /* Operand decoding codes */
+enum {
+ Ib = 1, /* 8-bit immediate - (no sign extension)*/
+ Ibs, /* 8-bit immediate (sign extended) */
+ Jbs, /* 8-bit sign-extended immediate in jump or call */
+ Iw, /* 16-bit immediate -> imm */
+ Iw2, /* 16-bit immediate -> imm2 */
+ Iwd, /* Operand-sized immediate (no sign extension)*/
+ Awd, /* Address offset */
+ Iwds, /* Operand-sized immediate (sign extended) */
+ RM, /* Word or long R/M field with register (/r) */
+ RMB, /* Byte R/M field with register (/r) */
+ RMOP, /* Word or long R/M field with op code (/digit) */
+ RMOPB, /* Byte R/M field with op code (/digit) */
+ RMR, /* R/M register only (mod = 11) */
+ RMM, /* R/M memory only (mod = 0/1/2) */
+ R0, /* Base reg of Mod R/M is literal 0x00 */
+ R1, /* Base reg of Mod R/M is literal 0x01 */
+ FRMOP, /* Floating point R/M field with opcode */
+ FRMEX, /* Extended floating point R/M field with opcode */
+ JUMP, /* Jump or Call flag - no operand */
+ RET, /* Return flag - no operand */
+ OA, /* literal 0x0a byte */
+ PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ AUX, /* Multi-byte op code - Auxiliary table */
+ PRE, /* Instr Prefix */
+ SEG, /* Segment Prefix */
+ OPOVER, /* Operand size override */
+ ADDOVER, /* Address size override */
+};
+
+static Optable optab0F00[8]=
+{
+ 0,0, "MOVW LDT,%e", /* 0x00 */
+ 0,0, "MOVW TR,%e", /* 0x01 */
+ 0,0, "MOVW %e,LDT", /* 0x02 */
+ 0,0, "MOVW %e,TR", /* 0x03 */
+ 0,0, "VERR %e", /* 0x04 */
+ 0,0, "VERW %e", /* 0x05 */
+};
+
+static Optable optab0F01[8]=
+{
+ 0,0, "MOVL GDTR,%e", /* 0x00 */
+ 0,0, "MOVL IDTR,%e", /* 0x01 */
+ 0,0, "MOVL %e,GDTR", /* 0x02 */
+ 0,0, "MOVL %e,IDTR", /* 0x03 */
+ 0,0, "MOVW MSW,%e", /* 0x04 */ /* word */
+ 0,0, "", /* 0x05 */
+ 0,0, "MOVW %e,MSW", /* 0x06 */ /* word */
+};
+
+static Optable optab0FBA[8]=
+{
+ 0,0, "", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "", /* 0x02 */
+ 0,0, "", /* 0x03 */
+ Ib,0, "BT%S %i,%e", /* 0x04 */
+ Ib,0, "BTS%S %i,%e", /* 0x05 */
+ Ib,0, "BTR%S %i,%e", /* 0x06 */
+ Ib,0, "BTC%S %i,%e", /* 0x07 */
+};
+
+static Optable optab0F[256]=
+{
+ RMOP,0, optab0F00, /* 0x00 */
+ RMOP,0, optab0F01, /* 0x01 */
+ RM,0, "LAR %e,%r", /* 0x02 */
+ RM,0, "LSL %e,%r", /* 0x03 */
+ 0,0, "", /* 0x04 */
+ 0,0, "", /* 0x05 */
+ 0,0, "CLTS", /* 0x06 */
+ 0,0, "", /* 0x07 */
+ 0,0, "INVD", /* 0x08 */
+ 0,0, "WBINVD", /* 0x09 */
+ 0,0, "", /* 0x0a */
+ 0,0, "", /* 0x0b */
+ 0,0, "", /* 0x0c */
+ 0,0, "", /* 0x0d */
+ 0,0, "", /* 0x0e */
+ 0,0, "", /* 0x0f */
+ 0,0, "", /* 0x10 */
+ 0,0, "", /* 0x11 */
+ 0,0, "", /* 0x12 */
+ 0,0, "", /* 0x13 */
+ 0,0, "", /* 0x14 */
+ 0,0, "", /* 0x15 */
+ 0,0, "", /* 0x16 */
+ 0,0, "", /* 0x17 */
+ 0,0, "", /* 0x18 */
+ 0,0, "", /* 0x19 */
+ 0,0, "", /* 0x1a */
+ 0,0, "", /* 0x1b */
+ 0,0, "", /* 0x1c */
+ 0,0, "", /* 0x1d */
+ 0,0, "", /* 0x1e */
+ 0,0, "", /* 0x1f */
+ RMR,0, "MOVL %C,%e", /* 0x20 */
+ RMR,0, "MOVL %D,%e", /* 0x21 */
+ RMR,0, "MOVL %e,%C", /* 0x22 */
+ RMR,0, "MOVL %e,%D", /* 0x23 */
+ RMR,0, "MOVL %T,%e", /* 0x24 */
+ 0,0, "", /* 0x25 */
+ RMR,0, "MOVL %e,%T", /* 0x26 */
+ 0,0, "", /* 0x27 */
+ 0,0, "", /* 0x28 */
+ 0,0, "", /* 0x29 */
+ 0,0, "", /* 0x2a */
+ 0,0, "", /* 0x2b */
+ 0,0, "", /* 0x2c */
+ 0,0, "", /* 0x2d */
+ 0,0, "", /* 0x2e */
+ 0,0, "", /* 0x2f */
+ 0,0, "WRMSR", /* 0x30 */
+ 0,0, "RDTSC", /* 0x31 */
+ 0,0, "RDMSR", /* 0x32 */
+ 0,0, "", /* 0x33 */
+ 0,0, "", /* 0x34 */
+ 0,0, "", /* 0x35 */
+ 0,0, "", /* 0x36 */
+ 0,0, "", /* 0x37 */
+ 0,0, "", /* 0x38 */
+ 0,0, "", /* 0x39 */
+ 0,0, "", /* 0x3a */
+ 0,0, "", /* 0x3b */
+ 0,0, "", /* 0x3c */
+ 0,0, "", /* 0x3d */
+ 0,0, "", /* 0x3e */
+ 0,0, "", /* 0x3f */
+ 0,0, "", /* 0x40 */
+ 0,0, "", /* 0x41 */
+ 0,0, "", /* 0x42 */
+ 0,0, "", /* 0x43 */
+ 0,0, "", /* 0x44 */
+ 0,0, "", /* 0x45 */
+ 0,0, "", /* 0x46 */
+ 0,0, "", /* 0x47 */
+ 0,0, "", /* 0x48 */
+ 0,0, "", /* 0x49 */
+ 0,0, "", /* 0x4a */
+ 0,0, "", /* 0x4b */
+ 0,0, "", /* 0x4c */
+ 0,0, "", /* 0x4d */
+ 0,0, "", /* 0x4e */
+ 0,0, "", /* 0x4f */
+ 0,0, "", /* 0x50 */
+ 0,0, "", /* 0x51 */
+ 0,0, "", /* 0x52 */
+ 0,0, "", /* 0x53 */
+ 0,0, "", /* 0x54 */
+ 0,0, "", /* 0x55 */
+ 0,0, "", /* 0x56 */
+ 0,0, "", /* 0x57 */
+ 0,0, "", /* 0x58 */
+ 0,0, "", /* 0x59 */
+ 0,0, "", /* 0x5a */
+ 0,0, "", /* 0x5b */
+ 0,0, "", /* 0x5c */
+ 0,0, "", /* 0x5d */
+ 0,0, "", /* 0x5e */
+ 0,0, "", /* 0x5f */
+ 0,0, "", /* 0x60 */
+ 0,0, "", /* 0x61 */
+ 0,0, "", /* 0x62 */
+ 0,0, "", /* 0x63 */
+ 0,0, "", /* 0x64 */
+ 0,0, "", /* 0x65 */
+ 0,0, "", /* 0x66 */
+ 0,0, "", /* 0x67 */
+ 0,0, "", /* 0x68 */
+ 0,0, "", /* 0x69 */
+ 0,0, "", /* 0x6a */
+ 0,0, "", /* 0x6b */
+ 0,0, "", /* 0x6c */
+ 0,0, "", /* 0x6d */
+ 0,0, "", /* 0x6e */
+ 0,0, "", /* 0x6f */
+ 0,0, "", /* 0x70 */
+ 0,0, "", /* 0x71 */
+ 0,0, "", /* 0x72 */
+ 0,0, "", /* 0x73 */
+ 0,0, "", /* 0x74 */
+ 0,0, "", /* 0x75 */
+ 0,0, "", /* 0x76 */
+ 0,0, "", /* 0x77 */
+ 0,0, "", /* 0x78 */
+ 0,0, "", /* 0x79 */
+ 0,0, "", /* 0x7a */
+ 0,0, "", /* 0x7b */
+ 0,0, "", /* 0x7c */
+ 0,0, "", /* 0x7d */
+ 0,0, "", /* 0x7e */
+ 0,0, "", /* 0x7f */
+ Iwds,0, "JOS %p", /* 0x80 */
+ Iwds,0, "JOC %p", /* 0x81 */
+ Iwds,0, "JCS %p", /* 0x82 */
+ Iwds,0, "JCC %p", /* 0x83 */
+ Iwds,0, "JEQ %p", /* 0x84 */
+ Iwds,0, "JNE %p", /* 0x85 */
+ Iwds,0, "JLS %p", /* 0x86 */
+ Iwds,0, "JHI %p", /* 0x87 */
+ Iwds,0, "JMI %p", /* 0x88 */
+ Iwds,0, "JPL %p", /* 0x89 */
+ Iwds,0, "JPS %p", /* 0x8a */
+ Iwds,0, "JPC %p", /* 0x8b */
+ Iwds,0, "JLT %p", /* 0x8c */
+ Iwds,0, "JGE %p", /* 0x8d */
+ Iwds,0, "JLE %p", /* 0x8e */
+ Iwds,0, "JGT %p", /* 0x8f */
+ RMB,0, "SETOS %e", /* 0x90 */
+ RMB,0, "SETOC %e", /* 0x91 */
+ RMB,0, "SETCS %e", /* 0x92 */
+ RMB,0, "SETCC %e", /* 0x93 */
+ RMB,0, "SETEQ %e", /* 0x94 */
+ RMB,0, "SETNE %e", /* 0x95 */
+ RMB,0, "SETLS %e", /* 0x96 */
+ RMB,0, "SETHI %e", /* 0x97 */
+ RMB,0, "SETMI %e", /* 0x98 */
+ RMB,0, "SETPL %e", /* 0x99 */
+ RMB,0, "SETPS %e", /* 0x9a */
+ RMB,0, "SETPC %e", /* 0x9b */
+ RMB,0, "SETLT %e", /* 0x9c */
+ RMB,0, "SETGE %e", /* 0x9d */
+ RMB,0, "SETLE %e", /* 0x9e */
+ RMB,0, "SETGT %e", /* 0x9f */
+ 0,0, "PUSHL FS", /* 0xa0 */
+ 0,0, "POPL FS", /* 0xa1 */
+ 0,0, "CPUID", /* 0xa2 */
+ RM,0, "BT%S %r,%e", /* 0xa3 */
+ RM,Ib, "SHLD%S %r,%i,%e", /* 0xa4 */
+ RM,0, "SHLD%S %r,CL,%e", /* 0xa5 */
+ 0,0, "", /* 0xa6 */
+ 0,0, "", /* 0xa7 */
+ 0,0, "PUSHL GS", /* 0xa8 */
+ 0,0, "POPL GS", /* 0xa9 */
+ 0,0, "", /* 0xaa */
+ RM,0, "BTS%S %r,%e", /* 0xab */
+ RM,Ib, "SHRD%S %r,%i,%e", /* 0xac */
+ RM,0, "SHRD%S %r,CL,%e", /* 0xad */
+ 0,0, "", /* 0xae */
+ RM,0, "IMUL%S %e,%r", /* 0xaf */
+ 0,0, "", /* 0xb0 */
+ 0,0, "", /* 0xb1 */
+ RMM,0, "LSS %e,%r", /* 0xb2 */
+ RM,0, "BTR%S %r,%e", /* 0xb3 */
+ RMM,0, "LFS %e,%r", /* 0xb4 */
+ RMM,0, "LGS %e,%r", /* 0xb5 */
+ RMB,0, "MOVBZX %e,%R", /* 0xb6 */
+ RM,0, "MOVWZX %e,%R", /* 0xb7 */
+ 0,0, "", /* 0xb8 */
+ 0,0, "", /* 0xb9 */
+ RMOP,0, optab0FBA, /* 0xba */
+ RM,0, "BTC%S %e,%r", /* 0xbb */
+ RM,0, "BSF%S %e,%r", /* 0xbc */
+ RM,0, "BSR%S %e,%r", /* 0xbd */
+ RMB,0, "MOVBSX %e,%R", /* 0xbe */
+ RM,0, "MOVWSX %e,%R", /* 0xbf */
+};
+
+static Optable optab80[8]=
+{
+ Ib,0, "ADDB %i,%e", /* 0x00 */
+ Ib,0, "ORB %i,%e", /* 0x01 */
+ Ib,0, "ADCB %i,%e", /* 0x02 */
+ Ib,0, "SBBB %i,%e", /* 0x03 */
+ Ib,0, "ANDB %i,%e", /* 0x04 */
+ Ib,0, "SUBB %i,%e", /* 0x05 */
+ Ib,0, "XORB %i,%e", /* 0x06 */
+ Ib,0, "CMPB %e,%i", /* 0x07 */
+};
+
+static Optable optab81[8]=
+{
+ Iwd,0, "ADD%S %i,%e", /* 0x00 */
+ Iwd,0, "OR%S %i,%e", /* 0x01 */
+ Iwd,0, "ADC%S %i,%e", /* 0x02 */
+ Iwd,0, "SBB%S %i,%e", /* 0x03 */
+ Iwd,0, "AND%S %i,%e", /* 0x04 */
+ Iwd,0, "SUB%S %i,%e", /* 0x05 */
+ Iwd,0, "XOR%S %i,%e", /* 0x06 */
+ Iwd,0, "CMP%S %e,%i", /* 0x07 */
+};
+
+static Optable optab83[8]=
+{
+ Ibs,0, "ADD%S %i,%e", /* 0x00 */
+ Ibs,0, "OR%S %i,%e", /* 0x01 */
+ Ibs,0, "ADC%S %i,%e", /* 0x02 */
+ Ibs,0, "SBB%S %i,%e", /* 0x03 */
+ Ibs,0, "AND%S %i,%e", /* 0x04 */
+ Ibs,0, "SUB%S %i,%e", /* 0x05 */
+ Ibs,0, "XOR%S %i,%e", /* 0x06 */
+ Ibs,0, "CMP%S %e,%i", /* 0x07 */
+};
+
+static Optable optabC0[8] =
+{
+ Ib,0, "ROLB %i,%e", /* 0x00 */
+ Ib,0, "RORB %i,%e", /* 0x01 */
+ Ib,0, "RCLB %i,%e", /* 0x02 */
+ Ib,0, "RCRB %i,%e", /* 0x03 */
+ Ib,0, "SHLB %i,%e", /* 0x04 */
+ Ib,0, "SHRB %i,%e", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ Ib,0, "SARB %i,%e", /* 0x07 */
+};
+
+static Optable optabC1[8] =
+{
+ Ib,0, "ROL%S %i,%e", /* 0x00 */
+ Ib,0, "ROR%S %i,%e", /* 0x01 */
+ Ib,0, "RCL%S %i,%e", /* 0x02 */
+ Ib,0, "RCR%S %i,%e", /* 0x03 */
+ Ib,0, "SHL%S %i,%e", /* 0x04 */
+ Ib,0, "SHR%S %i,%e", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ Ib,0, "SAR%S %i,%e", /* 0x07 */
+};
+
+static Optable optabD0[8] =
+{
+ 0,0, "ROLB %e", /* 0x00 */
+ 0,0, "RORB %e", /* 0x01 */
+ 0,0, "RCLB %e", /* 0x02 */
+ 0,0, "RCRB %e", /* 0x03 */
+ 0,0, "SHLB %e", /* 0x04 */
+ 0,0, "SHRB %e", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ 0,0, "SARB %e", /* 0x07 */
+};
+
+static Optable optabD1[8] =
+{
+ 0,0, "ROL%S %e", /* 0x00 */
+ 0,0, "ROR%S %e", /* 0x01 */
+ 0,0, "RCL%S %e", /* 0x02 */
+ 0,0, "RCR%S %e", /* 0x03 */
+ 0,0, "SHL%S %e", /* 0x04 */
+ 0,0, "SHR%S %e", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ 0,0, "SAR%S %e", /* 0x07 */
+};
+
+static Optable optabD2[8] =
+{
+ 0,0, "ROLB CL,%e", /* 0x00 */
+ 0,0, "RORB CL,%e", /* 0x01 */
+ 0,0, "RCLB CL,%e", /* 0x02 */
+ 0,0, "RCRB CL,%e", /* 0x03 */
+ 0,0, "SHLB CL,%e", /* 0x04 */
+ 0,0, "SHRB CL,%e", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ 0,0, "SARB CL,%e", /* 0x07 */
+};
+
+static Optable optabD3[8] =
+{
+ 0,0, "ROL%S CL,%e", /* 0x00 */
+ 0,0, "ROR%S CL,%e", /* 0x01 */
+ 0,0, "RCL%S CL,%e", /* 0x02 */
+ 0,0, "RCR%S CL,%e", /* 0x03 */
+ 0,0, "SHL%S CL,%e", /* 0x04 */
+ 0,0, "SHR%S CL,%e", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ 0,0, "SAR%S CL,%e", /* 0x07 */
+};
+
+static Optable optabD8[8+8] =
+{
+ 0,0, "FADDF %e,F0", /* 0x00 */
+ 0,0, "FMULF %e,F0", /* 0x01 */
+ 0,0, "FCOMF %e,F0", /* 0x02 */
+ 0,0, "FCOMFP %e,F0", /* 0x03 */
+ 0,0, "FSUBF %e,F0", /* 0x04 */
+ 0,0, "FSUBRF %e,F0", /* 0x05 */
+ 0,0, "FDIVF %e,F0", /* 0x06 */
+ 0,0, "FDIVRF %e,F0", /* 0x07 */
+ 0,0, "FADDD %f,F0", /* 0x08 */
+ 0,0, "FMULD %f,F0", /* 0x09 */
+ 0,0, "FCOMD %f,F0", /* 0x0a */
+ 0,0, "FCOMPD %f,F0", /* 0x0b */
+ 0,0, "FSUBD %f,F0", /* 0x0c */
+ 0,0, "FSUBRD %f,F0", /* 0x0d */
+ 0,0, "FDIVD %f,F0", /* 0x0e */
+ 0,0, "FDIVRD %f,F0", /* 0x0f */
+};
+/*
+ * optabD9 and optabDB use the following encoding:
+ * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ * else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ * the instructions for MOD == 3, follow the 8 instructions
+ * for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+ 0,0, "FMOVF %e,F0", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "FMOVF F0,%e", /* 0x02 */
+ 0,0, "FMOVFP F0,%e", /* 0x03 */
+ 0,0, "FLDENV%S %e", /* 0x04 */
+ 0,0, "FLDCW %e", /* 0x05 */
+ 0,0, "FSTENV%S %e", /* 0x06 */
+ 0,0, "FSTCW %e", /* 0x07 */
+ 0,0, "FMOVD F0,F0", /* 0x08 */ /* Mod R/M = 11xx xxxx*/
+ 0,0, "FMOVD F1,F0", /* 0x09 */
+ 0,0, "FMOVD F2,F0", /* 0x0a */
+ 0,0, "FMOVD F3,F0", /* 0x0b */
+ 0,0, "FMOVD F4,F0", /* 0x0c */
+ 0,0, "FMOVD F5,F0", /* 0x0d */
+ 0,0, "FMOVD F6,F0", /* 0x0e */
+ 0,0, "FMOVD F7,F0", /* 0x0f */
+ 0,0, "FXCHD F0,F0", /* 0x10 */
+ 0,0, "FXCHD F1,F0", /* 0x11 */
+ 0,0, "FXCHD F2,F0", /* 0x12 */
+ 0,0, "FXCHD F3,F0", /* 0x13 */
+ 0,0, "FXCHD F4,F0", /* 0x14 */
+ 0,0, "FXCHD F5,F0", /* 0x15 */
+ 0,0, "FXCHD F6,F0", /* 0x16 */
+ 0,0, "FXCHD F7,F0", /* 0x17 */
+ 0,0, "FNOP", /* 0x18 */
+ 0,0, "", /* 0x19 */
+ 0,0, "", /* 0x1a */
+ 0,0, "", /* 0x1b */
+ 0,0, "", /* 0x1c */
+ 0,0, "", /* 0x1d */
+ 0,0, "", /* 0x1e */
+ 0,0, "", /* 0x1f */
+ 0,0, "", /* 0x20 */
+ 0,0, "", /* 0x21 */
+ 0,0, "", /* 0x22 */
+ 0,0, "", /* 0x23 */
+ 0,0, "", /* 0x24 */
+ 0,0, "", /* 0x25 */
+ 0,0, "", /* 0x26 */
+ 0,0, "", /* 0x27 */
+ 0,0, "FCHS", /* 0x28 */
+ 0,0, "FABS", /* 0x29 */
+ 0,0, "", /* 0x2a */
+ 0,0, "", /* 0x2b */
+ 0,0, "FTST", /* 0x2c */
+ 0,0, "FXAM", /* 0x2d */
+ 0,0, "", /* 0x2e */
+ 0,0, "", /* 0x2f */
+ 0,0, "FLD1", /* 0x30 */
+ 0,0, "FLDL2T", /* 0x31 */
+ 0,0, "FLDL2E", /* 0x32 */
+ 0,0, "FLDPI", /* 0x33 */
+ 0,0, "FLDLG2", /* 0x34 */
+ 0,0, "FLDLN2", /* 0x35 */
+ 0,0, "FLDZ", /* 0x36 */
+ 0,0, "", /* 0x37 */
+ 0,0, "F2XM1", /* 0x38 */
+ 0,0, "FYL2X", /* 0x39 */
+ 0,0, "FPTAN", /* 0x3a */
+ 0,0, "FPATAN", /* 0x3b */
+ 0,0, "FXTRACT", /* 0x3c */
+ 0,0, "FPREM1", /* 0x3d */
+ 0,0, "FDECSTP", /* 0x3e */
+ 0,0, "FNCSTP", /* 0x3f */
+ 0,0, "FPREM", /* 0x40 */
+ 0,0, "FYL2XP1", /* 0x41 */
+ 0,0, "FSQRT", /* 0x42 */
+ 0,0, "FSINCOS", /* 0x43 */
+ 0,0, "FRNDINT", /* 0x44 */
+ 0,0, "FSCALE", /* 0x45 */
+ 0,0, "FSIN", /* 0x46 */
+ 0,0, "FCOS", /* 0x47 */
+};
+
+static Optable optabDA[8+8] =
+{
+ 0,0, "FADDL %e,F0", /* 0x00 */
+ 0,0, "FMULL %e,F0", /* 0x01 */
+ 0,0, "FCOML %e,F0", /* 0x02 */
+ 0,0, "FCOMLP %e,F0", /* 0x03 */
+ 0,0, "FSUBL %e,F0", /* 0x04 */
+ 0,0, "FSUBRL %e,F0", /* 0x05 */
+ 0,0, "FDIVL %e,F0", /* 0x06 */
+ 0,0, "FDIVRL %e,F0", /* 0x07 */
+ 0,0, "", /* 0x08 */
+ 0,0, "", /* 0x09 */
+ 0,0, "", /* 0x0a */
+ 0,0, "", /* 0x0b */
+ 0,0, "", /* 0x0c */
+ R1,0, "FUCOMPP", /* 0x0d */
+};
+
+static Optable optabDB[8+64] =
+{
+ 0,0, "FMOVL %e,F0", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "FMOVL F0,%e", /* 0x02 */
+ 0,0, "FMOVLP F0,%e", /* 0x03 */
+ 0,0, "", /* 0x04 */
+ 0,0, "FMOVX %e,F0", /* 0x05 */
+ 0,0, "", /* 0x06 */
+ 0,0, "FMOVXP F0,%e", /* 0x07 */
+ 0,0, "", /* 0x08 */
+ 0,0, "", /* 0x09 */
+ 0,0, "", /* 0x0a */
+ 0,0, "", /* 0x0b */
+ 0,0, "", /* 0x0c */
+ 0,0, "", /* 0x0d */
+ 0,0, "", /* 0x0e */
+ 0,0, "", /* 0x0f */
+ 0,0, "", /* 0x10 */
+ 0,0, "", /* 0x11 */
+ 0,0, "", /* 0x12 */
+ 0,0, "", /* 0x13 */
+ 0,0, "", /* 0x14 */
+ 0,0, "", /* 0x15 */
+ 0,0, "", /* 0x16 */
+ 0,0, "", /* 0x17 */
+ 0,0, "", /* 0x18 */
+ 0,0, "", /* 0x19 */
+ 0,0, "", /* 0x1a */
+ 0,0, "", /* 0x1b */
+ 0,0, "", /* 0x1c */
+ 0,0, "", /* 0x1d */
+ 0,0, "", /* 0x1e */
+ 0,0, "", /* 0x1f */
+ 0,0, "", /* 0x20 */
+ 0,0, "", /* 0x21 */
+ 0,0, "", /* 0x22 */
+ 0,0, "", /* 0x23 */
+ 0,0, "", /* 0x24 */
+ 0,0, "", /* 0x25 */
+ 0,0, "", /* 0x26 */
+ 0,0, "", /* 0x27 */
+ 0,0, "", /* 0x28 */
+ 0,0, "", /* 0x29 */
+ 0,0, "FCLEX", /* 0x2a */
+ 0,0, "FINIT", /* 0x2b */
+};
+
+static Optable optabDC[8+8] =
+{
+ 0,0, "FADDD %e,F0", /* 0x00 */
+ 0,0, "FMULD %e,F0", /* 0x01 */
+ 0,0, "FCOMD %e,F0", /* 0x02 */
+ 0,0, "FCOMDP %e,F0", /* 0x03 */
+ 0,0, "FSUBD %e,F0", /* 0x04 */
+ 0,0, "FSUBRD %e,F0", /* 0x05 */
+ 0,0, "FDIVD %e,F0", /* 0x06 */
+ 0,0, "FDIVRD %e,F0", /* 0x07 */
+ 0,0, "FADDD F0,%f", /* 0x08 */
+ 0,0, "FMULD F0,%f", /* 0x09 */
+ 0,0, "", /* 0x0a */
+ 0,0, "", /* 0x0b */
+ 0,0, "FSUBRD F0,%f", /* 0x0c */
+ 0,0, "FSUBD F0,%f", /* 0x0d */
+ 0,0, "FDIVRD F0,%f", /* 0x0e */
+ 0,0, "FDIVD F0,%f", /* 0x0f */
+};
+
+static Optable optabDD[8+8] =
+{
+ 0,0, "FMOVD %e,F0", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "FMOVD F0,%e", /* 0x02 */
+ 0,0, "FMOVDP F0,%e", /* 0x03 */
+ 0,0, "FRSTOR%S %e", /* 0x04 */
+ 0,0, "", /* 0x05 */
+ 0,0, "FSAVE%S %e", /* 0x06 */
+ 0,0, "FSTSW %e", /* 0x07 */
+ 0,0, "FFREED %f", /* 0x08 */
+ 0,0, "", /* 0x09 */
+ 0,0, "FMOVD %f,F0", /* 0x0a */
+ 0,0, "FMOVDP %f,F0", /* 0x0b */
+ 0,0, "FUCOMD %f,F0", /* 0x0c */
+ 0,0, "FUCOMDP %f,F0", /* 0x0d */
+};
+
+static Optable optabDE[8+8] =
+{
+ 0,0, "FADDW %e,F0", /* 0x00 */
+ 0,0, "FMULW %e,F0", /* 0x01 */
+ 0,0, "FCOMW %e,F0", /* 0x02 */
+ 0,0, "FCOMWP %e,F0", /* 0x03 */
+ 0,0, "FSUBW %e,F0", /* 0x04 */
+ 0,0, "FSUBRW %e,F0", /* 0x05 */
+ 0,0, "FDIVW %e,F0", /* 0x06 */
+ 0,0, "FDIVRW %e,F0", /* 0x07 */
+ 0,0, "FADDDP F0,%f", /* 0x08 */
+ 0,0, "FMULDP F0,%f", /* 0x09 */
+ 0,0, "", /* 0x0a */
+ R1,0, "FCOMPDP", /* 0x0b */
+ 0,0, "FSUBRDP F0,%f", /* 0x0c */
+ 0,0, "FSUBDP F0,%f", /* 0x0d */
+ 0,0, "FDIVRDP F0,%f", /* 0x0e */
+ 0,0, "FDIVDP F0,%f", /* 0x0f */
+};
+
+static Optable optabDF[8+8] =
+{
+ 0,0, "FMOVW %e,F0", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "FMOVW F0,%e", /* 0x02 */
+ 0,0, "FMOVWP F0,%e", /* 0x03 */
+ 0,0, "FBLD %e", /* 0x04 */
+ 0,0, "FMOVL %e,F0", /* 0x05 */
+ 0,0, "FBSTP %e", /* 0x06 */
+ 0,0, "FMOVLP F0,%e", /* 0x07 */
+ 0,0, "", /* 0x08 */
+ 0,0, "", /* 0x09 */
+ 0,0, "", /* 0x0a */
+ 0,0, "", /* 0x0b */
+ R0,0, "FSTSW %OAX", /* 0x0c */
+};
+
+static Optable optabF6[8] =
+{
+ Ib,0, "TESTB %i,%e", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "NOTB %e", /* 0x02 */
+ 0,0, "NEGB %e", /* 0x03 */
+ 0,0, "MULB AL,%e", /* 0x04 */
+ 0,0, "IMULB AL,%e", /* 0x05 */
+ 0,0, "DIVB AL,%e", /* 0x06 */
+ 0,0, "IDIVB AL,%e", /* 0x07 */
+};
+
+static Optable optabF7[8] =
+{
+ Iwd,0, "TEST%S %i,%e", /* 0x00 */
+ 0,0, "", /* 0x01 */
+ 0,0, "NOT%S %e", /* 0x02 */
+ 0,0, "NEG%S %e", /* 0x03 */
+ 0,0, "MUL%S %OAX,%e", /* 0x04 */
+ 0,0, "IMUL%S %OAX,%e", /* 0x05 */
+ 0,0, "DIV%S %OAX,%e", /* 0x06 */
+ 0,0, "IDIV%S %OAX,%e", /* 0x07 */
+};
+
+static Optable optabFE[8] =
+{
+ 0,0, "INCB %e", /* 0x00 */
+ 0,0, "DECB %e", /* 0x01 */
+};
+
+static Optable optabFF[8] =
+{
+ 0,0, "INC%S %e", /* 0x00 */
+ 0,0, "DEC%S %e", /* 0x01 */
+ JUMP,0, "CALL*%S %e", /* 0x02 */
+ JUMP,0, "CALLF*%S %e", /* 0x03 */
+ JUMP,0, "JMP*%S %e", /* 0x04 */
+ JUMP,0, "JMPF*%S %e", /* 0x05 */
+ 0,0, "PUSHL %e", /* 0x06 */
+};
+
+static Optable optable[256] =
+{
+ RMB,0, "ADDB %r,%e", /* 0x00 */
+ RM,0, "ADD%S %r,%e", /* 0x01 */
+ RMB,0, "ADDB %e,%r", /* 0x02 */
+ RM,0, "ADD%S %e,%r", /* 0x03 */
+ Ib,0, "ADDB %i,AL", /* 0x04 */
+ Iwd,0, "ADD%S %i,%OAX", /* 0x05 */
+ 0,0, "PUSHL ES", /* 0x06 */
+ 0,0, "POPL ES", /* 0x07 */
+ RMB,0, "ORB %r,%e", /* 0x08 */
+ RM,0, "OR%S %r,%e", /* 0x09 */
+ RMB,0, "ORB %e,%r", /* 0x0a */
+ RM,0, "OR%S %e,%r", /* 0x0b */
+ Ib,0, "ORB %i,AL", /* 0x0c */
+ Iwd,0, "OR%S %i,%OAX", /* 0x0d */
+ 0,0, "PUSHL CS", /* 0x0e */
+ AUX,0, optab0F, /* 0x0f */
+ RMB,0, "ADCB %r,%e", /* 0x10 */
+ RM,0, "ADC%S %r,%e", /* 0x11 */
+ RMB,0, "ADCB %e,%r", /* 0x12 */
+ RM,0, "ADC%S %e,%r", /* 0x13 */
+ Ib,0, "ADCB %i,AL", /* 0x14 */
+ Iwd,0, "ADC%S %i,%OAX", /* 0x15 */
+ 0,0, "PUSHL SS", /* 0x16 */
+ 0,0, "POPL SS", /* 0x17 */
+ RMB,0, "SBBB %r,%e", /* 0x18 */
+ RM,0, "SBB%S %r,%e", /* 0x19 */
+ RMB,0, "SBBB %e,%r", /* 0x1a */
+ RM,0, "SBB%S %e,%r", /* 0x1b */
+ Ib,0, "SBBB %i,AL", /* 0x1c */
+ Iwd,0, "SBB%S %i,%OAX", /* 0x1d */
+ 0,0, "PUSHL DS", /* 0x1e */
+ 0,0, "POPL DS", /* 0x1f */
+ RMB,0, "ANDB %r,%e", /* 0x20 */
+ RM,0, "AND%S %r,%e", /* 0x21 */
+ RMB,0, "ANDB %e,%r", /* 0x22 */
+ RM,0, "AND%S %e,%r", /* 0x23 */
+ Ib,0, "ANDB %i,AL", /* 0x24 */
+ Iwd,0, "AND%S %i,%OAX", /* 0x25 */
+ SEG,0, "ES:", /* 0x26 */
+ 0,0, "DAA", /* 0x27 */
+ RMB,0, "SUBB %r,%e", /* 0x28 */
+ RM,0, "SUB%S %r,%e", /* 0x29 */
+ RMB,0, "SUBB %e,%r", /* 0x2a */
+ RM,0, "SUB%S %e,%r", /* 0x2b */
+ Ib,0, "SUBB %i,AL", /* 0x2c */
+ Iwd,0, "SUB%S %i,%OAX", /* 0x2d */
+ SEG,0, "CS:", /* 0x2e */
+ 0,0, "DAS", /* 0x2f */
+ RMB,0, "XORB %r,%e", /* 0x30 */
+ RM,0, "XOR%S %r,%e", /* 0x31 */
+ RMB,0, "XORB %e,%r", /* 0x32 */
+ RM,0, "XOR%S %e,%r", /* 0x33 */
+ Ib,0, "XORB %i,AL", /* 0x34 */
+ Iwd,0, "XOR%S %i,%OAX", /* 0x35 */
+ SEG,0, "SS:", /* 0x36 */
+ 0,0, "AAA", /* 0x37 */
+ RMB,0, "CMPB %r,%e", /* 0x38 */
+ RM,0, "CMP%S %r,%e", /* 0x39 */
+ RMB,0, "CMPB %e,%r", /* 0x3a */
+ RM,0, "CMP%S %e,%r", /* 0x3b */
+ Ib,0, "CMPB %i,AL", /* 0x3c */
+ Iwd,0, "CMP%S %i,%OAX", /* 0x3d */
+ SEG,0, "DS:", /* 0x3e */
+ 0,0, "AAS", /* 0x3f */
+ 0,0, "INC%S %OAX", /* 0x40 */
+ 0,0, "INC%S %OCX", /* 0x41 */
+ 0,0, "INC%S %ODX", /* 0x42 */
+ 0,0, "INC%S %OBX", /* 0x43 */
+ 0,0, "INC%S %OSP", /* 0x44 */
+ 0,0, "INC%S %OBP", /* 0x45 */
+ 0,0, "INC%S %OSI", /* 0x46 */
+ 0,0, "INC%S %ODI", /* 0x47 */
+ 0,0, "DEC%S %OAX", /* 0x48 */
+ 0,0, "DEC%S %OCX", /* 0x49 */
+ 0,0, "DEC%S %ODX", /* 0x4a */
+ 0,0, "DEC%S %OBX", /* 0x4b */
+ 0,0, "DEC%S %OSP", /* 0x4c */
+ 0,0, "DEC%S %OBP", /* 0x4d */
+ 0,0, "DEC%S %OSI", /* 0x4e */
+ 0,0, "DEC%S %ODI", /* 0x4f */
+ 0,0, "PUSH%S %OAX", /* 0x50 */
+ 0,0, "PUSH%S %OCX", /* 0x51 */
+ 0,0, "PUSH%S %ODX", /* 0x52 */
+ 0,0, "PUSH%S %OBX", /* 0x53 */
+ 0,0, "PUSH%S %OSP", /* 0x54 */
+ 0,0, "PUSH%S %OBP", /* 0x55 */
+ 0,0, "PUSH%S %OSI", /* 0x56 */
+ 0,0, "PUSH%S %ODI", /* 0x57 */
+ 0,0, "POP%S %OAX", /* 0x58 */
+ 0,0, "POP%S %OCX", /* 0x59 */
+ 0,0, "POP%S %ODX", /* 0x5a */
+ 0,0, "POP%S %OBX", /* 0x5b */
+ 0,0, "POP%S %OSP", /* 0x5c */
+ 0,0, "POP%S %OBP", /* 0x5d */
+ 0,0, "POP%S %OSI", /* 0x5e */
+ 0,0, "POP%S %ODI", /* 0x5f */
+ 0,0, "PUSHA%S", /* 0x60 */
+ 0,0, "POPA%S", /* 0x61 */
+ RMM,0, "BOUND %e,%r", /* 0x62 */
+ RM,0, "ARPL %r,%e", /* 0x63 */
+ SEG,0, "FS:", /* 0x64 */
+ SEG,0, "GS:", /* 0x65 */
+ OPOVER,0, "", /* 0x66 */
+ ADDOVER,0, "", /* 0x67 */
+ Iwd,0, "PUSH%S %i", /* 0x68 */
+ RM,Iwd, "IMUL%S %e,%i,%r", /* 0x69 */
+ Ib,0, "PUSH%S %i", /* 0x6a */
+ RM,Ibs, "IMUL%S %e,%i,%r", /* 0x6b */
+ 0,0, "INSB DX,(%ODI)", /* 0x6c */
+ 0,0, "INS%S DX,(%ODI)", /* 0x6d */
+ 0,0, "OUTSB (%ASI),DX", /* 0x6e */
+ 0,0, "OUTS%S (%ASI),DX", /* 0x6f */
+ Jbs,0, "JOS %p", /* 0x70 */
+ Jbs,0, "JOC %p", /* 0x71 */
+ Jbs,0, "JCS %p", /* 0x72 */
+ Jbs,0, "JCC %p", /* 0x73 */
+ Jbs,0, "JEQ %p", /* 0x74 */
+ Jbs,0, "JNE %p", /* 0x75 */
+ Jbs,0, "JLS %p", /* 0x76 */
+ Jbs,0, "JHI %p", /* 0x77 */
+ Jbs,0, "JMI %p", /* 0x78 */
+ Jbs,0, "JPL %p", /* 0x79 */
+ Jbs,0, "JPS %p", /* 0x7a */
+ Jbs,0, "JPC %p", /* 0x7b */
+ Jbs,0, "JLT %p", /* 0x7c */
+ Jbs,0, "JGE %p", /* 0x7d */
+ Jbs,0, "JLE %p", /* 0x7e */
+ Jbs,0, "JGT %p", /* 0x7f */
+ RMOPB,0, optab80, /* 0x80 */
+ RMOP,0, optab81, /* 0x81 */
+ 0,0, "", /* 0x82 */
+ RMOP,0, optab83, /* 0x83 */
+ RMB,0, "TESTB %r,%e", /* 0x84 */
+ RM,0, "TEST%S %r,%e", /* 0x85 */
+ RMB,0, "XCHGB %r,%e", /* 0x86 */
+ RM,0, "XCHG%S %r,%e", /* 0x87 */
+ RMB,0, "MOVB %r,%e", /* 0x88 */
+ RM,0, "MOV%S %r,%e", /* 0x89 */
+ RMB,0, "MOVB %e,%r", /* 0x8a */
+ RM,0, "MOV%S %e,%r", /* 0x8b */
+ RM,0, "MOVW %g,%e", /* 0x8c */
+ RM,0, "LEA %e,%r", /* 0x8d */
+ RM,0, "MOVW %e,%g", /* 0x8e */
+ RM,0, "POP%S %e", /* 0x8f */
+ 0,0, "NOP", /* 0x90 */
+ 0,0, "XCHG %OCX,%OAX", /* 0x91 */
+ 0,0, "XCHG %OCX,%OAX", /* 0x92 */
+ 0,0, "XCHG %OCX,%OAX", /* 0x93 */
+ 0,0, "XCHG %OSP,%OAX", /* 0x94 */
+ 0,0, "XCHG %OBP,%OAX", /* 0x95 */
+ 0,0, "XCHG %OSI,%OAX", /* 0x96 */
+ 0,0, "XCHG %ODI,%OAX", /* 0x97 */
+ 0,0, "%X", /* 0x98 */ /* miserable CBW or CWDE */
+ 0,0, "%x", /* 0x99 */ /* idiotic CWD or CDQ */
+ PTR,0, "CALL%S %d", /* 0x9a */
+ 0,0, "WAIT", /* 0x9b */
+ 0,0, "PUSHF", /* 0x9c */
+ 0,0, "POPF", /* 0x9d */
+ 0,0, "SAHF", /* 0x9e */
+ 0,0, "LAHF", /* 0x9f */
+ Awd,0, "MOVB %i,AL", /* 0xa0 */
+ Awd,0, "MOV%S %i,%OAX", /* 0xa1 */
+ Awd,0, "MOVB AL,%i", /* 0xa2 */
+ Awd,0, "MOV%S %OAX,%i", /* 0xa3 */
+ 0,0, "MOVSB (%ASI),(%ADI)", /* 0xa4 */
+ 0,0, "MOVS%S (%ASI),(%ADI)", /* 0xa5 */
+ 0,0, "CMPSB (%ASI),(%ADI)", /* 0xa6 */
+ 0,0, "CMPS%S (%ASI),(%ADI)", /* 0xa7 */
+ Ib,0, "TESTB %i,AL", /* 0xa8 */
+ Iwd,0, "TEST%S %i,%OAX", /* 0xa9 */
+ 0,0, "STOSB AL,(%ADI)", /* 0xaa */
+ 0,0, "STOS%S %OAX,(%ADI)", /* 0xab */
+ 0,0, "LODSB (%ASI),AL", /* 0xac */
+ 0,0, "LODS%S (%ASI),%OAX", /* 0xad */
+ 0,0, "SCASB (%ADI),AL", /* 0xae */
+ 0,0, "SCAS%S (%ADI),%OAX", /* 0xaf */
+ Ib,0, "MOVB %i,AL", /* 0xb0 */
+ Ib,0, "MOVB %i,CL", /* 0xb1 */
+ Ib,0, "MOVB %i,DL", /* 0xb2 */
+ Ib,0, "MOVB %i,BL", /* 0xb3 */
+ Ib,0, "MOVB %i,AH", /* 0xb4 */
+ Ib,0, "MOVB %i,CH", /* 0xb5 */
+ Ib,0, "MOVB %i,DH", /* 0xb6 */
+ Ib,0, "MOVB %i,BH", /* 0xb7 */
+ Iwd,0, "MOV%S %i,%OAX", /* 0xb8 */
+ Iwd,0, "MOV%S %i,%OCX", /* 0xb9 */
+ Iwd,0, "MOV%S %i,%ODX", /* 0xba */
+ Iwd,0, "MOV%S %i,%OBX", /* 0xbb */
+ Iwd,0, "MOV%S %i,%OSP", /* 0xbc */
+ Iwd,0, "MOV%S %i,%OBP", /* 0xbd */
+ Iwd,0, "MOV%S %i,%OSI", /* 0xbe */
+ Iwd,0, "MOV%S %i,%ODI", /* 0xbf */
+ RMOPB,0, optabC0, /* 0xc0 */
+ RMOP,0, optabC1, /* 0xc1 */
+ Iw,0, "RET %i", /* 0xc2 */
+ RET,0, "RET", /* 0xc3 */
+ RM,0, "LES %e,%r", /* 0xc4 */
+ RM,0, "LDS %e,%r", /* 0xc5 */
+ RMB,Ib, "MOVB %i,%e", /* 0xc6 */
+ RM,Iwd, "MOV%S %i,%e", /* 0xc7 */
+ Iw2,Ib, "ENTER %i,%I", /* 0xc8 */ /* loony ENTER */
+ RET,0, "LEAVE", /* 0xc9 */ /* bizarre LEAVE */
+ Iw,0, "RETF %i", /* 0xca */
+ RET,0, "RETF", /* 0xcb */
+ 0,0, "INT 3", /* 0xcc */
+ Ib,0, "INTB %i", /* 0xcd */
+ 0,0, "INTO", /* 0xce */
+ 0,0, "IRET", /* 0xcf */
+ RMOPB,0, optabD0, /* 0xd0 */
+ RMOP,0, optabD1, /* 0xd1 */
+ RMOPB,0, optabD2, /* 0xd2 */
+ RMOP,0, optabD3, /* 0xd3 */
+ OA,0, "AAM", /* 0xd4 */
+ OA,0, "AAD", /* 0xd5 */
+ 0,0, "", /* 0xd6 */
+ 0,0, "XLAT", /* 0xd7 */
+ FRMOP,0, optabD8, /* 0xd8 */
+ FRMEX,0, optabD9, /* 0xd9 */
+ FRMOP,0, optabDA, /* 0xda */
+ FRMEX,0, optabDB, /* 0xdb */
+ FRMOP,0, optabDC, /* 0xdc */
+ FRMOP,0, optabDD, /* 0xdd */
+ FRMOP,0, optabDE, /* 0xde */
+ FRMOP,0, optabDF, /* 0xdf */
+ Jbs,0, "LOOPNE %p", /* 0xe0 */
+ Jbs,0, "LOOPE %p", /* 0xe1 */
+ Jbs,0, "LOOP %p", /* 0xe2 */
+ Jbs,0, "JCXZ %p", /* 0xe3 */
+ Ib,0, "INB %i,AL", /* 0xe4 */
+ Ib,0, "IN%S %i,%OAX", /* 0xe5 */
+ Ib,0, "OUTB AL,%i", /* 0xe6 */
+ Ib,0, "OUT%S %OAX,%i", /* 0xe7 */
+ Iwds,0, "CALL %p", /* 0xe8 */
+ Iwds,0, "JMP %p", /* 0xe9 */
+ PTR,0, "JMP %d", /* 0xea */
+ Jbs,0, "JMP %p", /* 0xeb */
+ 0,0, "INB DX,AL", /* 0xec */
+ 0,0, "IN%S DX,%OAX", /* 0xed */
+ 0,0, "OUTB AL,DX", /* 0xee */
+ 0,0, "OUT%S %OAX,DX", /* 0xef */
+ PRE,0, "LOCK", /* 0xf0 */
+ 0,0, "", /* 0xf1 */
+ PRE,0, "REPNE", /* 0xf2 */
+ PRE,0, "REP", /* 0xf3 */
+ 0,0, "HALT", /* 0xf4 */
+ 0,0, "CMC", /* 0xf5 */
+ RMOPB,0, optabF6, /* 0xf6 */
+ RMOP,0, optabF7, /* 0xf7 */
+ 0,0, "CLC", /* 0xf8 */
+ 0,0, "STC", /* 0xf9 */
+ 0,0, "CLI", /* 0xfa */
+ 0,0, "STI", /* 0xfb */
+ 0,0, "CLD", /* 0xfc */
+ 0,0, "STD", /* 0xfd */
+ RMOPB,0, optabFE, /* 0xfe */
+ RMOP,0, optabFF, /* 0xff */
+};
+
+/*
+ * get a byte of the instruction
+ */
+static int
+igetc(Map * map, Instr *ip, uchar *c)
+{
+ if(ip->n+1 > sizeof(ip->mem)){
+ werrstr("instruction too long");
+ return -1;
+ }
+ if (get1(map, ip->addr+ip->n, c, 1) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ ip->mem[ip->n++] = *c;
+ return 1;
+}
+
+/*
+ * get two bytes of the instruction
+ */
+static int
+igets(Map *map, Instr *ip, ushort *sp)
+{
+ uchar c;
+ ushort s;
+
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ s = c;
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ s |= (c<<8);
+ *sp = s;
+ return 1;
+}
+
+/*
+ * get 4 bytes of the instruction
+ */
+static int
+igetl(Map *map, Instr *ip, ulong *lp)
+{
+ ushort s;
+ long l;
+
+ if (igets(map, ip, &s) < 0)
+ return -1;
+ l = s;
+ if (igets(map, ip, &s) < 0)
+ return -1;
+ l |= (s<<16);
+ *lp = l;
+ return 1;
+}
+
+static int
+getdisp(Map *map, Instr *ip, int mod, int rm, int code)
+{
+ uchar c;
+ ushort s;
+
+ if (mod > 2)
+ return 1;
+ if (mod == 1) {
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ if (c&0x80)
+ ip->disp = c|0xffffff00;
+ else
+ ip->disp = c&0xff;
+ } else if (mod == 2 || rm == code) {
+ if (ip->asize == 'E') {
+ if (igetl(map, ip, &ip->disp) < 0)
+ return -1;
+ } else {
+ if (igets(map, ip, &s) < 0)
+ return -1;
+ if (s&0x8000)
+ ip->disp = s|0xffff0000;
+ else
+ ip->disp = s;
+ }
+ if (mod == 0)
+ ip->base = -1;
+ }
+ return 1;
+}
+
+static int
+modrm(Map *map, Instr *ip, uchar c)
+{
+ uchar rm, mod;
+
+ mod = (c>>6)&3;
+ rm = c&7;
+ ip->mod = mod;
+ ip->base = rm;
+ ip->reg = (c>>3)&7;
+ if (mod == 3) /* register */
+ return 1;
+ if (ip->asize == 0) { /* 16-bit mode */
+ switch(rm)
+ {
+ case 0:
+ ip->base = BX; ip->index = SI;
+ break;
+ case 1:
+ ip->base = BX; ip->index = DI;
+ break;
+ case 2:
+ ip->base = BP; ip->index = SI;
+ break;
+ case 3:
+ ip->base = BP; ip->index = DI;
+ break;
+ case 4:
+ ip->base = SI;
+ break;
+ case 5:
+ ip->base = DI;
+ break;
+ case 6:
+ ip->base = BP;
+ break;
+ case 7:
+ ip->base = BX;
+ break;
+ default:
+ break;
+ }
+ return getdisp(map, ip, mod, rm, 6);
+ }
+ if (rm == 4) { /* scummy sib byte */
+ if (igetc(map, ip, &c) < 0)
+ return -1;
+ ip->ss = (c>>6)&0x03;
+ ip->index = (c>>3)&0x07;
+ if (ip->index == 4)
+ ip->index = -1;
+ ip->base = c&0x07;
+ return getdisp(map, ip, mod, ip->base, 5);
+ }
+ return getdisp(map, ip, mod, rm, 5);
+}
+
+static Optable *
+mkinstr(Map *map, Instr *ip, ulong pc)
+{
+ int i, n;
+ uchar c;
+ ushort s;
+ Optable *op, *obase;
+ char buf[128];
+
+ memset(ip, 0, sizeof(*ip));
+ ip->base = -1;
+ ip->index = -1;
+ if(asstype == AI8086)
+ ip->osize = 'W';
+ else {
+ ip->osize = 'L';
+ ip->asize = 'E';
+ }
+ ip->addr = pc;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ obase = optable;
+newop:
+ op = &obase[c];
+ if (op->proto == 0) {
+badop:
+ n = snprint(buf, sizeof(buf), "opcode: ??");
+ for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+ _hexify(buf+n, ip->mem[i], 1);
+ strcpy(buf+n, "??");
+ werrstr(buf);
+ return 0;
+ }
+ for(i = 0; i < 2 && op->operand[i]; i++) {
+ switch(op->operand[i])
+ {
+ case Ib: /* 8-bit immediate - (no sign extension)*/
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ ip->imm = c&0xff;
+ break;
+ case Jbs: /* 8-bit jump immediate (sign extended) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c&0xff;
+ ip->jumptype = Jbs;
+ break;
+ case Ibs: /* 8-bit immediate (sign extended) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ if (ip->osize == 'L')
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c|0xff00;
+ else
+ ip->imm = c&0xff;
+ break;
+ case Iw: /* 16-bit immediate -> imm */
+ if (igets(map, ip, &s) < 0)
+ return 0;
+ ip->imm = s&0xffff;
+ ip->jumptype = Iw;
+ break;
+ case Iw2: /* 16-bit immediate -> in imm2*/
+ if (igets(map, ip, &s) < 0)
+ return 0;
+ ip->imm2 = s&0xffff;
+ break;
+ case Iwd: /* Operand-sized immediate (no sign extension)*/
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Awd: /* Address-sized immediate (no sign extension)*/
+ if (ip->asize == 'E') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Iwds: /* Operand-sized immediate (sign extended) */
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ if (s&0x8000)
+ ip->imm = s|0xffff0000;
+ else
+ ip->imm = s&0xffff;
+ }
+ ip->jumptype = Iwds;
+ break;
+ case OA: /* literal 0x0a byte */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (c != 0x0a)
+ goto badop;
+ break;
+ case R0: /* base register must be R0 */
+ if (ip->base != 0)
+ goto badop;
+ break;
+ case R1: /* base register must be R1 */
+ if (ip->base != 1)
+ goto badop;
+ break;
+ case RMB: /* R/M field with byte register (/r)*/
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ ip->osize = 'B';
+ break;
+ case RM: /* R/M field with register (/r) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ break;
+ case RMOPB: /* R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ c = ip->reg; /* secondary op code */
+ obase = (Optable*)op->proto;
+ ip->osize = 'B';
+ goto newop;
+ case RMOP: /* R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMOP: /* FP R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = ip->reg+8; /* 16 entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMEX: /* Extended FP R/M field with op code (/digit) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = (c&0x3f)+8; /* 64-entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case RMR: /* R/M register only (mod = 11) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) != 0xc0) {
+ werrstr("invalid R/M register: %x", c);
+ return 0;
+ }
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ break;
+ case RMM: /* R/M register only (mod = 11) */
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0) {
+ werrstr("invalid R/M memory mode: %x", c);
+ return 0;
+ }
+ if (modrm(map, ip, c) < 0)
+ return 0;
+ break;
+ case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ if (ip->osize == 'L') {
+ if (igetl(map, ip, &ip->disp) < 0)
+ return 0;
+ } else {
+ if (igets(map, ip, &s)< 0)
+ return 0;
+ ip->disp = s&0xffff;
+ }
+ if (igets(map, ip, (ushort*)&ip->seg) < 0)
+ return 0;
+ ip->jumptype = PTR;
+ break;
+ case AUX: /* Multi-byte op code - Auxiliary table */
+ obase = (Optable*)op->proto;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case PRE: /* Instr Prefix */
+ ip->prefix = (char*)op->proto;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case SEG: /* Segment Prefix */
+ ip->segment = (char*)op->proto;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case OPOVER: /* Operand size override */
+ ip->osize = 'W';
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case ADDOVER: /* Address size override */
+ ip->asize = 0;
+ if (igetc(map, ip, &c) < 0)
+ return 0;
+ goto newop;
+ case JUMP: /* mark instruction as JUMP or RET */
+ case RET:
+ ip->jumptype = op->operand[i];
+ break;
+ default:
+ werrstr("bad operand type %d", op->operand[i]);
+ return 0;
+ }
+ }
+ return op;
+}
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+ va_end(arg);
+}
+
+/*
+ * if we want to call 16 bit regs AX,BX,CX,...
+ * and 32 bit regs EAX,EBX,ECX,... then
+ * change the defs of ANAME and ONAME to:
+ * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
+ * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
+ */
+#define ANAME(ip) ""
+#define ONAME(ip) ""
+
+static char *reg[] = {
+ "AX", /* 0 */
+ "CX", /* 1 */
+ "DX", /* 2 */
+ "BX", /* 3 */
+ "SP", /* 4 */
+ "BP", /* 5 */
+ "SI", /* 6 */
+ "DI", /* 7 */
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+ int ret, offset;
+ Symbol s;
+ char *reg;
+
+ offset = ip->disp;
+ if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
+ bprint(ip, "%lux(SP)", offset);
+ return;
+ }
+
+ if (s.value > ip->disp) {
+ ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
+ reg = "(SP)";
+ } else {
+ offset -= s.value;
+ ret = getauto(&s, offset, CPARAM, &s);
+ reg = "(FP)";
+ }
+ if (ret)
+ bprint(ip, "%s+", s.name);
+ else
+ offset = ip->disp;
+ bprint(ip, "%lux%s", offset, reg);
+}
+
+static void
+pea(Instr *ip)
+{
+ if (ip->mod == 3) {
+ if (ip->osize == 'B')
+ bprint(ip, breg[ip->base]);
+ else
+ bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+ return;
+ }
+ if (ip->segment)
+ bprint(ip, ip->segment);
+ if (ip->asize == 'E' && ip->base == SP)
+ plocal(ip);
+ else {
+ bprint(ip,"%lux", ip->disp);
+ if (ip->base >= 0)
+ bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]);
+ }
+ if (ip->index >= 0)
+ bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
+}
+
+static void
+immediate(Instr *ip, long val)
+{
+ Symbol s;
+ long w;
+
+ if (findsym(val, CANY, &s)) {
+ w = val - s.value;
+ if (w < 0)
+ w = -w;
+ if (w < 4096) {
+ if (w)
+ bprint(ip, "%s+%lux(SB)", s.name, w);
+ else
+ bprint(ip, "%s(SB)", s.name);
+ return;
+ }
+ }
+ bprint(ip, "%lux", val);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+ if (ip->prefix)
+ bprint(ip, "%s ", ip->prefix);
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%')
+ *ip->curr++ = *fmt;
+ else switch(*++fmt)
+ {
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'A':
+ bprint(ip, "%s", ANAME(ip));
+ break;
+ case 'C':
+ bprint(ip, "CR%d", ip->reg);
+ break;
+ case 'D':
+ if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "DR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'I':
+ bprint(ip, "$");
+ immediate(ip, ip->imm2);
+ break;
+ case 'O':
+ bprint(ip,"%s", ONAME(ip));
+ break;
+ case 'i':
+ bprint(ip, "$");
+ immediate(ip,ip->imm);
+ break;
+ case 'R':
+ bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
+ break;
+ case 'S':
+ bprint(ip, "%c", ip->osize);
+ break;
+ case 'T':
+ if (ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "TR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'X':
+ if (ip->osize == 'L')
+ bprint(ip,"CWDE");
+ else
+ bprint(ip, "CBW");
+ break;
+ case 'd':
+ bprint(ip,"%lux:%lux",ip->seg,ip->disp);
+ break;
+ case 'e':
+ pea(ip);
+ break;
+ case 'f':
+ bprint(ip, "F%d", ip->base);
+ break;
+ case 'g':
+ if (ip->reg < 6)
+ bprint(ip,"%s",sreg[ip->reg]);
+ else
+ bprint(ip,"???");
+ break;
+ case 'p':
+ immediate(ip, ip->imm+ip->addr+ip->n);
+ break;
+ case 'r':
+ if (ip->osize == 'B')
+ bprint(ip,"%s",breg[ip->reg]);
+ else
+ bprint(ip, reg[ip->reg]);
+ break;
+ case 'x':
+ if (ip->osize == 'L')
+ bprint(ip,"CDQ");
+ else
+ bprint(ip, "CWD");
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+static int
+i386inst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ Instr instr;
+ Optable *op;
+
+ USED(modifier);
+ op = mkinstr(map, &instr, pc);
+ if (op == 0) {
+ buf[0] = 0;
+ errstr(buf, n);
+ return -1;
+ }
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ prinstr(&instr, op->proto);
+ return instr.n;
+}
+
+static int
+i386das(Map *map, ulong pc, char *buf, int n)
+{
+ Instr instr;
+ int i;
+
+ if (mkinstr(map, &instr, pc) == 0) {
+ buf[0] = 0;
+ errstr(buf, n);
+ return -1;
+ }
+ for(i = 0; i < instr.n && n > 2; i++) {
+ _hexify(buf, instr.mem[i], 1);
+ buf += 2;
+ n -= 2;
+ }
+ *buf = 0;
+ return instr.n;
+}
+
+static int
+i386instlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ if (mkinstr(map, &i, pc))
+ return i.n;
+ return -1;
+}
+
+static int
+i386foll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ Instr i;
+ Optable *op;
+ ushort s;
+ ulong l, addr;
+ int n;
+
+ op = mkinstr(map, &i, pc);
+ if (!op)
+ return -1;
+
+ n = 0;
+
+ switch(i.jumptype) {
+ case RET: /* RETURN or LEAVE */
+ case Iw: /* RETURN */
+ if (strcmp(op->proto, "LEAVE") == 0) {
+ if (get4(map, (*rget)(map, "BP"), (long*)&l) < 0)
+ return -1;
+ } else if (get4(map, (*rget)(map, mach->sp), (long*)&l) < 0)
+ return -1;
+ foll[0] = l;
+ return 1;
+ case Iwds: /* pc relative JUMP or CALL*/
+ case Jbs: /* pc relative JUMP or CALL */
+ foll[0] = pc+i.imm+i.n;
+ n = 1;
+ break;
+ case PTR: /* seg:displacement JUMP or CALL */
+ foll[0] = (i.seg<<4)+i.disp;
+ return 1;
+ case JUMP: /* JUMP or CALL EA */
+
+ if(i.mod == 3) {
+ foll[0] = (*rget)(map, reg[i.base]);
+ return 1;
+ }
+ /* calculate the effective address */
+ addr = i.disp;
+ if (i.base >= 0) {
+ if (get4(map, (*rget)(map, reg[i.base]), (long*)&l) < 0)
+ return -1;
+ addr += l;
+ }
+ if (i.index >= 0) {
+ if (get4(map, (*rget)(map, reg[i.index]), (long*)&l) < 0)
+ return -1;
+ addr += l*(1<<i.ss);
+ }
+ /* now retrieve a seg:disp value at that address */
+ if (get2(map, addr, &s) < 0) /* seg */
+ return -1;
+ foll[0] = s<<4;
+ addr += 2;
+ if (i.asize == 'L') {
+ if (get4(map, addr, (long*)&l) < 0) /* disp32 */
+ return -1;
+ foll[0] += l;
+ } else { /* disp16 */
+ if (get2(map, addr, &s) < 0)
+ return -1;
+ foll[0] += s;
+ }
+ return 1;
+ default:
+ break;
+ }
+ if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
+ return 1;
+ foll[n++] = pc+i.n;
+ return n;
+}
diff --git a/utils/libmach/8obj.c b/utils/libmach/8obj.c
new file mode 100644
index 00000000..9e322f12
--- /dev/null
+++ b/utils/libmach/8obj.c
@@ -0,0 +1,133 @@
+/*
+ * 8obj.c - identify and parse a 386 object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "8c/8.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char sym;
+ char flags;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_is8(char *t)
+{
+ uchar *s = (uchar*)t;
+
+ return s[0] == (ANAME&0xff) /* aslo = ANAME */
+ && s[1] == ((ANAME>>8)&0xff)
+ && s[2] == D_FILE /* type */
+ && s[3] == 1 /* sym */
+ && s[4] == '<'; /* name of file */
+}
+
+int
+_read8(Biobuf *bp, Prog* p)
+{
+ int as, n, c;
+ Addr a;
+
+ as = Bgetc(bp); /* as(low) */
+ if(as < 0)
+ return 0;
+ c = Bgetc(bp); /* as(high) */
+ if(c < 0)
+ return 0;
+ as |= ((c & 0xff) << 8);
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 4); /* lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(!(a.flags & T_SYM))
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ int t;
+ long off;
+
+ off = 0;
+ a.sym = -1;
+ a.flags = Bgetc(bp); /* flags */
+ if(a.flags & T_INDEX)
+ skip(bp, 2);
+ if(a.flags & T_OFFSET){
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ }
+ if(a.flags & T_SYM)
+ a.sym = Bgetc(bp);
+ if(a.flags & T_FCONST)
+ skip(bp, 8);
+ else
+ if(a.flags & T_SCONST)
+ skip(bp, NSNAME);
+ if(a.flags & T_TYPE) {
+ t = Bgetc(bp);
+ if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
+ _offset(a.sym, off);
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/NOTICE b/utils/libmach/NOTICE
new file mode 100644
index 00000000..53798daf
--- /dev/null
+++ b/utils/libmach/NOTICE
@@ -0,0 +1,31 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1994-1999 Lucent Technologies Inc.
+ Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+ Portions Copyright © 1997-1999 Vita Nuova Limited.
+ Portions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com).
+ Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/utils/libmach/a.out.h b/utils/libmach/a.out.h
new file mode 100644
index 00000000..8c0b7137
--- /dev/null
+++ b/utils/libmach/a.out.h
@@ -0,0 +1,45 @@
+typedef struct Exec Exec;
+struct Exec
+{
+ long magic; /* magic number */
+ long text; /* size of text segment */
+ long data; /* size of initialized data */
+ long bss; /* size of uninitialized data */
+ long syms; /* size of symbol table */
+ long entry; /* entry point */
+ long spsz; /* size of pc/sp offset table */
+ long pcsz; /* size of pc/line number table */
+};
+
+
+#define HDR_MAGIC 0x00008000 /* header expansion */
+
+#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
+#define A_MAGIC _MAGIC(0, 8) /* 68020 */
+#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
+#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
+#define K_MAGIC _MAGIC(0, 13) /* sparc */
+#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
+#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
+#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
+#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
+#define E_MAGIC _MAGIC(0, 20) /* arm */
+#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
+#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
+#define L_MAGIC _MAGIC(0, 23) /* dec alpha */
+#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
+#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
+#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
+
+#define MIN_MAGIC 8
+#define MAX_MAGIC 26 /* <= 90 */
+
+#define DYN_MAGIC 0x80000000 /* or'd in for dynamically loaded modules */
+
+typedef struct Sym Sym;
+struct Sym
+{
+ long value;
+ char type;
+ char *name;
+};
diff --git a/utils/libmach/access.c b/utils/libmach/access.c
new file mode 100644
index 00000000..6a58cdea
--- /dev/null
+++ b/utils/libmach/access.c
@@ -0,0 +1,215 @@
+/*
+ * functions to read and write an executable or file image
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+static int mget(Map*, ulong, char*, int);
+static int mput(Map*, ulong, char*, int);
+struct segment* reloc(Map*, ulong, long*);
+
+/*
+ * routines to get/put various types
+ */
+
+int
+get8(Map *map, ulong addr, vlong *x)
+{
+ if (!map) {
+ werrstr("get8: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ *x = (vlong)addr;
+ return 1;
+ }
+ if (mget(map, addr, (char *)x, 8) < 0)
+ return -1;
+ *x = machdata->swav(*x);
+ return (1);
+}
+
+int
+get4(Map *map, ulong addr, long *x)
+{
+ if (!map) {
+ werrstr("get4: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ *x = addr;
+ return 1;
+ }
+ if (mget(map, addr, (char *)x, 4) < 0)
+ return -1;
+ *x = machdata->swal(*x);
+ return (1);
+}
+
+int
+get2(Map *map, ulong addr, ushort *x)
+{
+ if (!map) {
+ werrstr("get2: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ *x = addr;
+ return 1;
+ }
+ if (mget(map, addr, (char *)x, 2) < 0)
+ return -1;
+ *x = machdata->swab(*x);
+ return (1);
+}
+
+int
+get1(Map *map, ulong addr, uchar *x, int size)
+{
+ uchar *cp;
+
+ if (!map) {
+ werrstr("get1: invalid map");
+ return -1;
+ }
+
+ if (map->nsegs == 1 && map->seg[0].fd < 0) {
+ cp = (uchar*)&addr;
+ while (cp < (uchar*)(&addr+1) && size-- > 0)
+ *x++ = *cp++;
+ while (size-- > 0)
+ *x++ = 0;
+ } else
+ return mget(map, addr, (char*)x, size);
+ return 1;
+}
+
+int
+put8(Map *map, ulong addr, vlong v)
+{
+ if (!map) {
+ werrstr("put8: invalid map");
+ return -1;
+ }
+ v = machdata->swav(v);
+ return mput(map, addr, (char *)&v, 8);
+}
+
+int
+put4(Map *map, ulong addr, long v)
+{
+ if (!map) {
+ werrstr("put4: invalid map");
+ return -1;
+ }
+ v = machdata->swal(v);
+ return mput(map, addr, (char *)&v, 4);
+}
+
+int
+put2(Map *map, ulong addr, ushort v)
+{
+ if (!map) {
+ werrstr("put2: invalid map");
+ return -1;
+ }
+ v = machdata->swab(v);
+ return mput(map, addr, (char *)&v, 2);
+}
+
+int
+put1(Map *map, ulong addr, uchar *v, int size)
+{
+ if (!map) {
+ werrstr("put1: invalid map");
+ return -1;
+ }
+ return mput(map, addr, (char *)v, size);
+}
+
+static int
+mget(Map *map, ulong addr, char *buf, int size)
+{
+ long off;
+ int i, j, k;
+ struct segment *s;
+
+ s = reloc(map, addr, &off);
+ if (!s)
+ return -1;
+ if (s->fd < 0) {
+ werrstr("unreadable map");
+ return -1;
+ }
+ if (s->mget)
+ return s->mget(s, addr, off, buf, size);
+ seek(s->fd, off, 0);
+ for (i = j = 0; i < 2; i++) { /* in case read crosses page */
+ k = read(s->fd, buf, size-j);
+ if (k < 0) {
+ werrstr("can't read address %lux: %r", addr);
+ return -1;
+ }
+ j += k;
+ if (j == size)
+ return j;
+ }
+ werrstr("partial read at address %lux", addr);
+ return -1;
+}
+
+static int
+mput(Map *map, ulong addr, char *buf, int size)
+{
+ long off;
+ int i, j, k;
+ struct segment *s;
+
+ s = reloc(map, addr, &off);
+ if (!s)
+ return -1;
+ if (s->fd < 0) {
+ werrstr("unwritable map");
+ return -1;
+ }
+ if (s->mput)
+ return s->mput(s, addr, off, buf, size);
+
+ seek(s->fd, off, 0);
+ for (i = j = 0; i < 2; i++) { /* in case read crosses page */
+ k = write(s->fd, buf, size-j);
+ if (k < 0) {
+ werrstr("can't write address %lux: %r", addr);
+ return -1;
+ }
+ j += k;
+ if (j == size)
+ return j;
+ }
+ werrstr("partial write at address %lux", addr);
+ return -1;
+}
+
+/*
+ * convert address to file offset; returns nonzero if ok
+ */
+struct segment*
+reloc(Map *map, ulong addr, long *offp)
+{
+ int i;
+
+ for (i = 0; i < map->nsegs; i++) {
+ if (map->seg[i].inuse)
+ if (map->seg[i].b <= addr && addr < map->seg[i].e) {
+ *offp = addr + map->seg[i].f - map->seg[i].b;
+ return &map->seg[i];
+ }
+ }
+ werrstr("can't translate address %lux", addr);
+ return 0;
+}
diff --git a/utils/libmach/ar.h b/utils/libmach/ar.h
new file mode 100644
index 00000000..71ffff12
--- /dev/null
+++ b/utils/libmach/ar.h
@@ -0,0 +1,18 @@
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+
+#define ARFMAG "`\n"
+#define SARNAME 16
+
+struct ar_hdr
+{
+ char name[SARNAME];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char fmag[2];
+};
+#define SAR_HDR 60
+
diff --git a/utils/libmach/bootexec.h b/utils/libmach/bootexec.h
new file mode 100644
index 00000000..a844ec7c
--- /dev/null
+++ b/utils/libmach/bootexec.h
@@ -0,0 +1,172 @@
+struct coffsect
+{
+ char name[8];
+ ulong phys;
+ ulong virt;
+ ulong size;
+ ulong fptr;
+ ulong fptrreloc;
+ ulong fptrlineno;
+ ulong nrelocnlineno;
+ ulong flags;
+};
+
+/*
+ * proprietary exec headers, needed to bootstrap various machines
+ */
+struct mipsexec
+{
+ short mmagic; /* (0x160) mips magic number */
+ short nscns; /* (unused) number of sections */
+ long timdat; /* (unused) time & date stamp */
+ long symptr; /* offset to symbol table */
+ long nsyms; /* size of symbol table */
+ short opthdr; /* (0x38) sizeof(optional hdr) */
+ short pcszs; /* flags */
+ short amagic; /* see above */
+ short vstamp; /* version stamp */
+ long tsize; /* text size in bytes */
+ long dsize; /* initialized data */
+ long bsize; /* uninitialized data */
+ long mentry; /* entry pt. */
+ long text_start; /* base of text used for this file */
+ long data_start; /* base of data used for this file */
+ long bss_start; /* base of bss used for this file */
+ long gprmask; /* general purpose register mask */
+union{
+ long mcprmask[4]; /* co-processor register masks */
+ long mpcsize;
+} u0;
+ long gp_value; /* the gp value used for this object */
+};
+
+struct mips4kexec
+{
+ struct mipsexec h;
+ struct coffsect itexts;
+ struct coffsect idatas;
+ struct coffsect ibsss;
+};
+
+struct sparcexec
+{
+ short sjunk; /* dynamic bit and version number */
+ short smagic; /* 0407 */
+ ulong stext;
+ ulong sdata;
+ ulong sbss;
+ ulong ssyms;
+ ulong sentry;
+ ulong strsize;
+ ulong sdrsize;
+};
+
+struct nextexec
+{
+ struct nexthdr{
+ ulong nmagic;
+ ulong ncputype;
+ ulong ncpusubtype;
+ ulong nfiletype;
+ ulong ncmds;
+ ulong nsizeofcmds;
+ ulong nflags;
+ }texth;
+
+ struct nextcmd{
+ ulong cmd;
+ ulong cmdsize;
+ uchar segname[16];
+ ulong vmaddr;
+ ulong vmsize;
+ ulong fileoff;
+ ulong filesize;
+ ulong maxprot;
+ ulong initprot;
+ ulong nsects;
+ ulong flags;
+ }textc;
+ struct nextsect{
+ char sectname[16];
+ char segname[16];
+ ulong addr;
+ ulong size;
+ ulong offset;
+ ulong align;
+ ulong reloff;
+ ulong nreloc;
+ ulong flags;
+ ulong reserved1;
+ ulong reserved2;
+ }texts;
+ struct nextcmd datac;
+ struct nextsect datas;
+ struct nextsect bsss;
+ struct nextsym{
+ ulong cmd;
+ ulong cmdsize;
+ ulong symoff;
+ ulong nsyms;
+ ulong spoff;
+ ulong pcoff;
+ }symc;
+};
+
+struct i386exec
+{
+ struct i386coff{
+ ulong isectmagic;
+ ulong itime;
+ ulong isyms;
+ ulong insyms;
+ ulong iflags;
+ } icoff;
+ struct i386hdr{
+ ulong imagic;
+ ulong itextsize;
+ ulong idatasize;
+ ulong ibsssize;
+ ulong ientry;
+ ulong itextstart;
+ ulong idatastart;
+ } ihdr;
+ struct coffsect itexts;
+ struct coffsect idatas;
+ struct coffsect ibsss;
+ struct coffsect icomments;
+};
+
+struct i960exec
+{
+ struct i960coff{
+ ulong i6sectmagic;
+ ulong i6time;
+ ulong i6syms;
+ ulong i6nsyms;
+ ulong i6opthdrflags;
+ }i6coff;
+ struct i960hdr{
+ ulong i6magic;
+ ulong i6textsize;
+ ulong i6datasize;
+ ulong i6bsssize;
+ ulong i6entry;
+ ulong i6textstart;
+ ulong i6datastart;
+ ulong i6tagentries;
+ }i6hdr;
+ struct i960sect{
+ char name[8];
+ ulong phys;
+ ulong virt;
+ ulong size;
+ ulong fptr;
+ ulong fptrreloc;
+ ulong fptrlineno;
+ ulong nrelocnlineno;
+ ulong flags;
+ ulong align;
+ }i6texts;
+ struct i960sect i6datas;
+};
+
diff --git a/utils/libmach/elf.h b/utils/libmach/elf.h
new file mode 100644
index 00000000..b182135b
--- /dev/null
+++ b/utils/libmach/elf.h
@@ -0,0 +1,101 @@
+/*
+ * Definitions needed for accessing Irix ELF headers
+ */
+typedef struct {
+ unsigned char ident[16]; /* ident bytes */
+ ushort type; /* file type */
+ ushort machine; /* target machine */
+ int version; /* file version */
+ ulong elfentry; /* start address */
+ ulong phoff; /* phdr file offset */
+ ulong shoff; /* shdr file offset */
+ int flags; /* file flags */
+ ushort ehsize; /* sizeof ehdr */
+ ushort phentsize; /* sizeof phdr */
+ ushort phnum; /* number phdrs */
+ ushort shentsize; /* sizeof shdr */
+ ushort shnum; /* number shdrs */
+ ushort shstrndx; /* shdr string index */
+} Ehdr;
+
+typedef struct {
+ int type; /* entry type */
+ ulong offset; /* file offset */
+ ulong vaddr; /* virtual address */
+ ulong paddr; /* physical address */
+ int filesz; /* file size */
+ ulong memsz; /* memory size */
+ int flags; /* entry flags */
+ int align; /* memory/file alignment */
+} Phdr;
+
+typedef struct {
+ ulong name; /* section name */
+ ulong type; /* SHT_... */
+ ulong flags; /* SHF_... */
+ ulong addr; /* virtual address */
+ ulong offset; /* file offset */
+ ulong size; /* section size */
+ ulong link; /* misc info */
+ ulong info; /* misc info */
+ ulong addralign; /* memory alignment */
+ ulong entsize; /* entry size if table */
+} Shdr;
+
+enum {
+ /* Ehdr codes */
+ MAG0 = 0, /* ident[] indexes */
+ MAG1 = 1,
+ MAG2 = 2,
+ MAG3 = 3,
+ CLASS = 4,
+ DATA = 5,
+ VERSION = 6,
+
+ ELFCLASSNONE = 0, /* ident[CLASS] */
+ ELFCLASS32 = 1,
+ ELFCLASS64 = 2,
+ ELFCLASSNUM = 3,
+
+ ELFDATANONE = 0, /* ident[DATA] */
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2,
+ ELFDATANUM = 3,
+
+ NOETYPE = 0, /* type */
+ REL = 1,
+ EXEC = 2,
+ DYN = 3,
+ CORE = 4,
+
+ NONE = 0, /* machine */
+ M32 = 1, /* AT&T WE 32100 */
+ SPARC = 2, /* Sun SPARC */
+ I386 = 3, /* Intel 80386 */
+ M68K = 4, /* Motorola 68000 */
+ M88K = 5, /* Motorola 88000 */
+ I486 = 6, /* Intel 80486 */
+ I860 = 7, /* Intel i860 */
+ MIPS = 8, /* Mips R2000 */
+ S370 = 9, /* Amdhal */
+ POWER = 20, /* PowerPC */
+ AMD64 = 62, /* Amd64 */
+
+ NO_VERSION = 0, /* version, ident[VERSION] */
+ CURRENT = 1,
+
+ /* Phdr Codes */
+ NOPTYPE = 0, /* type */
+ LOAD = 1,
+ DYNAMIC = 2,
+ INTERP = 3,
+ NOTE = 4,
+ SHLIB = 5,
+ PHDR = 6,
+
+ R = 0x4, /* flags */
+ W = 0x2,
+ X = 0x1,
+};
+
+#define ELF_MAG ((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F')
diff --git a/utils/libmach/executable.c b/utils/libmach/executable.c
new file mode 100644
index 00000000..a17d6ae2
--- /dev/null
+++ b/utils/libmach/executable.c
@@ -0,0 +1,570 @@
+#include <lib9.h>
+#include <bio.h>
+#include "bootexec.h"
+#include "mach.h"
+#include "elf.h"
+
+/*
+ * All a.out header types. The dummy entry allows canonical
+ * processing of the union as a sequence of longs
+ */
+
+typedef struct {
+ union{
+ Exec exec; /* in a.out.h */
+ Ehdr ehdr; /* in elf.h */
+ struct mipsexec mipsexec;
+ struct mips4kexec mips4kexec;
+ struct sparcexec sparcexec;
+ struct nextexec nextexec;
+ } e;
+ long dummy; /* padding to ensure extra long */
+} ExecHdr;
+
+static int nextboot(int, Fhdr*, ExecHdr*);
+static int sparcboot(int, Fhdr*, ExecHdr*);
+static int mipsboot(int, Fhdr*, ExecHdr*);
+static int mips4kboot(int, Fhdr*, ExecHdr*);
+static int common(int, Fhdr*, ExecHdr*);
+static int adotout(int, Fhdr*, ExecHdr*);
+static int elfdotout(int, Fhdr*, ExecHdr*);
+static int armdotout(int, Fhdr*, ExecHdr*);
+static void setsym(Fhdr*, long, long, long, long);
+static void setdata(Fhdr*, long, long, long, long);
+static void settext(Fhdr*, long, long, long, long);
+static void hswal(long*, int, long(*)(long));
+static long _round(long, long);
+
+/*
+ * definition of per-executable file type structures
+ */
+
+typedef struct Exectable{
+ long magic; /* big-endian magic number of file */
+ char *name; /* executable identifier */
+ int type; /* Internal code */
+ Mach *mach; /* Per-machine data */
+ ulong hsize; /* header size */
+ long (*swal)(long); /* beswal or leswal */
+ int (*hparse)(int, Fhdr*, ExecHdr*);
+} ExecTable;
+
+extern Mach mmips;
+extern Mach mmips2le;
+extern Mach mmips2be;
+extern Mach msparc;
+extern Mach m68020;
+extern Mach mi386;
+extern Mach marm;
+extern Mach mpower;
+
+ExecTable exectab[] =
+{
+ { V_MAGIC, /* Mips v.out */
+ "mips plan 9 executable",
+ FMIPS,
+ &mmips,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { M_MAGIC, /* Mips 4.out */
+ "mips 4k plan 9 executable BE",
+ FMIPS2BE,
+ &mmips2be,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { N_MAGIC, /* Mips 0.out */
+ "mips 4k plan 9 executable LE",
+ FMIPS2LE,
+ &mmips2le,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { 0x160<<16, /* Mips boot image */
+ "mips plan 9 boot image",
+ FMIPSB,
+ &mmips,
+ sizeof(struct mipsexec),
+ beswal,
+ mipsboot },
+ { (0x160<<16)|3, /* Mips boot image */
+ "mips 4k plan 9 boot image",
+ FMIPSB,
+ &mmips,
+ sizeof(struct mips4kexec),
+ beswal,
+ mips4kboot },
+ { K_MAGIC, /* Sparc k.out */
+ "sparc plan 9 executable",
+ FSPARC,
+ &msparc,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { 0x01030107, /* Sparc boot image */
+ "sparc plan 9 boot image",
+ FSPARCB,
+ &msparc,
+ sizeof(struct sparcexec),
+ beswal,
+ sparcboot },
+ { A_MAGIC, /* 68020 2.out & boot image */
+ "68020 plan 9 executable",
+ F68020,
+ &m68020,
+ sizeof(Exec),
+ beswal,
+ common },
+ { 0xFEEDFACE, /* Next boot image */
+ "next plan 9 boot image",
+ FNEXTB,
+ &m68020,
+ sizeof(struct nextexec),
+ beswal,
+ nextboot },
+ { I_MAGIC, /* I386 8.out & boot image */
+ "386 plan 9 executable",
+ FI386,
+ &mi386,
+ sizeof(Exec),
+ beswal,
+ common },
+ { ELF_MAG,
+ "Irix 5.X Elf executable",
+ FMIPS,
+ &mmips,
+ sizeof(Ehdr),
+ beswal,
+ elfdotout },
+ { E_MAGIC, /* Arm 5.out */
+ "Arm plan 9 executable",
+ FARM,
+ &marm,
+ sizeof(Exec),
+ beswal,
+ common },
+ { (143<<16)|0413, /* (Free|Net)BSD Arm */
+ "Arm *BSD executable",
+ FARM,
+ &marm,
+ sizeof(Exec),
+ leswal,
+ armdotout },
+ { Q_MAGIC, /* PowerPC q.out */
+ "power plan 9 executable",
+ FPOWER,
+ &mpower,
+ sizeof(Exec),
+ beswal,
+ common },
+ { 0 },
+};
+
+Mach *mach = &mmips; /* Global current machine table */
+
+ExecTable*
+couldbe4k(ExecTable *mp)
+{
+ Dir *d;
+ ExecTable *f;
+
+ if((d=dirstat("/proc/1/regs")) == nil)
+ return mp;
+ if(d->length < 32*8){ /* R3000 */
+ free(d);
+ return mp;
+ }
+ free(d);
+ for (f = exectab; f->magic; f++)
+ if(f->magic == M_MAGIC) {
+ f->name = "mips plan 9 executable on mips2 kernel";
+ return f;
+ }
+ return mp;
+}
+
+
+int
+crackhdr(int fd, Fhdr *fp)
+{
+ ExecTable *mp;
+ ExecHdr d;
+ int nb, magic, ret;
+
+ fp->type = FNONE;
+ nb = read(fd, (char *)&d.e, sizeof(d.e));
+ if (nb <= 0)
+ return 0;
+
+ ret = 0;
+ fp->magic = magic = beswal(d.e.exec.magic); /* big-endian */
+ for (mp = exectab; mp->magic; mp++) {
+ if (mp->magic == magic && nb >= mp->hsize) {
+ if(mp->magic == V_MAGIC)
+ mp = couldbe4k(mp);
+
+ hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal);
+ fp->type = mp->type;
+ fp->name = mp->name;
+ fp->hdrsz = mp->hsize; /* zero on bootables */
+ mach = mp->mach;
+ ret = mp->hparse(fd, fp, &d);
+ seek(fd, mp->hsize, 0); /* seek to end of header */
+ break;
+ }
+ }
+ if(mp->magic == 0)
+ werrstr("unknown header type");
+ return ret;
+}
+/*
+ * Convert header to canonical form
+ */
+static void
+hswal(long *lp, int n, long (*swap) (long))
+{
+ while (n--) {
+ *lp = (*swap) (*lp);
+ lp++;
+ }
+}
+/*
+ * Crack a normal a.out-type header
+ */
+static int
+adotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ long pgsize;
+
+ USED(fd);
+ pgsize = mach->pgsize;
+ settext(fp, hp->e.exec.entry, pgsize+sizeof(Exec),
+ hp->e.exec.text, sizeof(Exec));
+ setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
+ hp->e.exec.data, fp->txtsz+sizeof(Exec), hp->e.exec.bss);
+ setsym(fp, hp->e.exec.syms, hp->e.exec.spsz, hp->e.exec.pcsz, fp->datoff+fp->datsz);
+ return 1;
+}
+
+/*
+ * 68020 2.out and 68020 bootable images
+ * 386I 8.out and 386I bootable images
+ *
+ */
+static int
+common(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ long kbase;
+
+ adotout(fd, fp, hp);
+ kbase = mach->kbase;
+ if ((fp->entry & kbase) == kbase) { /* Boot image */
+ switch(fp->type) {
+ case F68020:
+ fp->type = F68020B;
+ fp->name = "68020 plan 9 boot image";
+ fp->hdrsz = 0; /* header stripped */
+ break;
+ case FI386:
+ fp->type = FI386B;
+ fp->txtaddr = sizeof(Exec);
+ fp->name = "386 plan 9 boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ break;
+ case FARM:
+ fp->txtaddr = kbase+0x8000+sizeof(Exec);
+ fp->name = "ARM plan 9 boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ return 1;
+ default:
+ break;
+ }
+ fp->txtaddr |= kbase;
+ fp->entry |= kbase;
+ fp->dataddr |= kbase;
+ }
+ else if (fp->type == FARM && (fp->entry == 0x8020 || fp->entry == 0x8080)) {
+ fp->txtaddr = fp->entry;
+ fp->name = "ARM Inferno boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ }
+ else if (fp->type == FPOWER && fp->entry == 0x3020) {
+ fp->txtaddr = fp->entry;
+ fp->name = "Power Inferno boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ }
+ return 1;
+}
+
+/*
+ * mips bootable image.
+ */
+static int
+mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ switch(hp->e.mipsexec.amagic) {
+ default:
+ case 0407: /* some kind of mips */
+ fp->type = FMIPSB;
+ settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize,
+ sizeof(struct mipsexec)+4);
+ setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize,
+ fp->txtoff+hp->e.mipsexec.tsize, hp->e.mipsexec.bsize);
+ break;
+ case 0413: /* some kind of mips */
+ fp->type = FMIPSB;
+ settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize, 0);
+ setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize, hp->e.mipsexec.tsize,
+ hp->e.mipsexec.bsize);
+ break;
+ }
+ setsym(fp, hp->e.mipsexec.nsyms, 0, hp->e.mipsexec.u0.mpcsize, hp->e.mipsexec.symptr);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * mips4k bootable image.
+ */
+static int
+mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ switch(hp->e.mipsexec.amagic) {
+ default:
+ case 0407: /* some kind of mips */
+ fp->type = FMIPSB;
+ settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize,
+ sizeof(struct mips4kexec));
+ setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize,
+ fp->txtoff+hp->e.mipsexec.tsize, hp->e.mipsexec.bsize);
+ break;
+ case 0413: /* some kind of mips */
+ fp->type = FMIPSB;
+ settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize, 0);
+ setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize, hp->e.mipsexec.tsize,
+ hp->e.mipsexec.bsize);
+ break;
+ }
+ setsym(fp, hp->e.mipsexec.nsyms, 0, hp->e.mipsexec.u0.mpcsize, hp->e.mipsexec.symptr);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * sparc bootable image
+ */
+static int
+sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ fp->type = FSPARCB;
+ settext(fp, hp->e.sparcexec.sentry, hp->e.sparcexec.sentry, hp->e.sparcexec.stext,
+ sizeof(struct sparcexec));
+ setdata(fp, hp->e.sparcexec.sentry+hp->e.sparcexec.stext, hp->e.sparcexec.sdata,
+ fp->txtoff+hp->e.sparcexec.stext, hp->e.sparcexec.sbss);
+ setsym(fp, hp->e.sparcexec.ssyms, 0, hp->e.sparcexec.sdrsize, fp->datoff+hp->e.sparcexec.sdata);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * next bootable image
+ */
+static int
+nextboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ fp->type = FNEXTB;
+ settext(fp, hp->e.nextexec.textc.vmaddr, hp->e.nextexec.textc.vmaddr,
+ hp->e.nextexec.texts.size, hp->e.nextexec.texts.offset);
+ setdata(fp, hp->e.nextexec.datac.vmaddr, hp->e.nextexec.datas.size,
+ hp->e.nextexec.datas.offset, hp->e.nextexec.bsss.size);
+ setsym(fp, hp->e.nextexec.symc.nsyms, hp->e.nextexec.symc.spoff, hp->e.nextexec.symc.pcoff,
+ hp->e.nextexec.symc.symoff);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+static Shdr*
+elfsectbyname(int fd, Ehdr *hp, Shdr *sp, char *name)
+{
+ int i, offset, n;
+ char s[64];
+
+ offset = sp[hp->shstrndx].offset;
+ for(i = 1; i < hp->shnum; i++) {
+ seek(fd, offset+sp[i].name, 0);
+ n = read(fd, s, sizeof(s)-1);
+ if(n < 0)
+ continue;
+ s[n] = 0;
+ if(strcmp(s, name) == 0)
+ return &sp[i];
+ }
+ return 0;
+}
+/*
+ * Decode an Irix 5.x ELF header
+ */
+static int
+elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+
+ Ehdr *ep;
+ Shdr *es, *txt, *init, *s;
+ long addr, size, offset, bsize;
+
+ ep = &hp->e.ehdr;
+ fp->magic = ELF_MAG;
+ fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+
+ if(ep->shnum <= 0) {
+ werrstr("no ELF header sections");
+ return 0;
+ }
+ es = malloc(sizeof(Shdr)*ep->shnum);
+ if(es == 0)
+ return 0;
+
+ seek(fd, ep->shoff, 0);
+ if(read(fd, es, sizeof(Shdr)*ep->shnum) < 0){
+ free(es);
+ return 0;
+ }
+
+ txt = elfsectbyname(fd, ep, es, ".text");
+ init = elfsectbyname(fd, ep, es, ".init");
+ if(txt == 0 || init == 0 || init != txt+1)
+ goto bad;
+ if(txt->addr+txt->size != init->addr)
+ goto bad;
+ settext(fp, ep->elfentry, txt->addr, txt->size+init->size, txt->offset);
+
+ addr = 0;
+ offset = 0;
+ size = 0;
+ s = elfsectbyname(fd, ep, es, ".data");
+ if(s) {
+ addr = s->addr;
+ size = s->size;
+ offset = s->offset;
+ }
+
+ s = elfsectbyname(fd, ep, es, ".rodata");
+ if(s) {
+ if(addr){
+ if(addr+size != s->addr)
+ goto bad;
+ } else {
+ addr = s->addr;
+ offset = s->offset;
+ }
+ size += s->size;
+ }
+
+ s = elfsectbyname(fd, ep, es, ".got");
+ if(s) {
+ if(addr){
+ if(addr+size != s->addr)
+ goto bad;
+ } else {
+ addr = s->addr;
+ offset = s->offset;
+ }
+ size += s->size;
+ }
+
+ bsize = 0;
+ s = elfsectbyname(fd, ep, es, ".bss");
+ if(s) {
+ if(addr){
+ if(addr+size != s->addr)
+ goto bad;
+ } else {
+ addr = s->addr;
+ offset = s->offset;
+ }
+ bsize = s->size;
+ }
+
+ if(addr == 0)
+ goto bad;
+
+ setdata(fp, addr, size, offset, bsize);
+ fp->name = "IRIX Elf a.out executable";
+ free(es);
+ return 1;
+bad:
+ free(es);
+ werrstr("ELF sections scrambled");
+ return 0;
+}
+
+/*
+ * (Free|Net)BSD ARM header.
+ */
+static int
+armdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ long kbase;
+
+ USED(fd);
+ settext(fp, hp->e.exec.entry, sizeof(Exec), hp->e.exec.text, sizeof(Exec));
+ setdata(fp, fp->txtsz, hp->e.exec.data, fp->txtsz, hp->e.exec.bss);
+ setsym(fp, hp->e.exec.syms, hp->e.exec.spsz, hp->e.exec.pcsz, fp->datoff+fp->datsz);
+
+ kbase = 0xF0000000;
+ if ((fp->entry & kbase) == kbase) { /* Boot image */
+ fp->txtaddr = kbase+sizeof(Exec);
+ fp->name = "ARM *BSD boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = kbase+fp->txtsz;
+ }
+ return 1;
+}
+
+static void
+settext(Fhdr *fp, long e, long a, long s, long off)
+{
+ fp->txtaddr = a;
+ fp->entry = e;
+ fp->txtsz = s;
+ fp->txtoff = off;
+}
+static void
+setdata(Fhdr *fp, long a, long s, long off, long bss)
+{
+ fp->dataddr = a;
+ fp->datsz = s;
+ fp->datoff = off;
+ fp->bsssz = bss;
+}
+static void
+setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff)
+{
+ fp->symsz = sy;
+ fp->symoff = symoff;
+ fp->sppcsz = sppc;
+ fp->sppcoff = fp->symoff+fp->symsz;
+ fp->lnpcsz = lnpc;
+ fp->lnpcoff = fp->sppcoff+fp->sppcsz;
+}
+
+
+static long
+_round(long a, long b)
+{
+ long w;
+
+ w = (a/b)*b;
+ if (a!=w)
+ w += b;
+ return(w);
+}
diff --git a/utils/libmach/k.c b/utils/libmach/k.c
new file mode 100644
index 00000000..30ae15a0
--- /dev/null
+++ b/utils/libmach/k.c
@@ -0,0 +1,117 @@
+/*
+ * sparc definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "uregk.h"
+#include "mach.h"
+
+#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x)
+
+#define R1 REGOFF(u0.r1)
+#define R7 REGOFF(r7)
+#define PC REGOFF(pc)
+#define R15 REGOFF(r15)
+
+#define REGSIZE sizeof(struct Ureg)
+#define FP_REG(x) (REGSIZE+4*(x))
+#define FPREGSIZE (33*4)
+
+Reglist sparcreglist[] = {
+ {"Y", REGOFF(y), RINT|RRDONLY, 'X'},
+ {"TBR", REGOFF(tbr), RINT|RRDONLY, 'X'},
+ {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'},
+ {"PC", REGOFF(pc), RINT, 'X'},
+ {"R1", REGOFF(u0.r1), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R15", REGOFF(r15), RINT, 'X'},
+ {"R16", REGOFF(r16), RINT, 'X'},
+ {"R17", REGOFF(r17), RINT, 'X'},
+ {"R18", REGOFF(r18), RINT, 'X'},
+ {"R19", REGOFF(r19), RINT, 'X'},
+ {"R20", REGOFF(r20), RINT, 'X'},
+ {"R21", REGOFF(r21), RINT, 'X'},
+ {"R22", REGOFF(r22), RINT, 'X'},
+ {"R23", REGOFF(r23), RINT, 'X'},
+ {"R24", REGOFF(r24), RINT, 'X'},
+ {"R25", REGOFF(r25), RINT, 'X'},
+ {"R26", REGOFF(r26), RINT, 'X'},
+ {"R27", REGOFF(r27), RINT, 'X'},
+ {"R28", REGOFF(r28), RINT, 'X'},
+ {"R29", REGOFF(r29), RINT, 'X'},
+ {"R30", REGOFF(r30), RINT, 'X'},
+ {"R31", REGOFF(r31), RINT, 'X'},
+ {"NPC", REGOFF(npc), RINT, 'X'},
+
+ {"FSR", FP_REG(0), RINT, 'X'},
+ {"F0", FP_REG(1), RFLT, 'F'},
+ {"F1", FP_REG(2), RFLT, 'f'},
+ {"F2", FP_REG(3), RFLT, 'F'},
+ {"F3", FP_REG(4), RFLT, 'f'},
+ {"F4", FP_REG(5), RFLT, 'F'},
+ {"F5", FP_REG(6), RFLT, 'f'},
+ {"F6", FP_REG(7), RFLT, 'F'},
+ {"F7", FP_REG(8), RFLT, 'f'},
+ {"F8", FP_REG(9), RFLT, 'F'},
+ {"F9", FP_REG(10), RFLT, 'f'},
+ {"F10", FP_REG(11), RFLT, 'F'},
+ {"F11", FP_REG(12), RFLT, 'f'},
+ {"F12", FP_REG(13), RFLT, 'F'},
+ {"F13", FP_REG(14), RFLT, 'f'},
+ {"F14", FP_REG(15), RFLT, 'F'},
+ {"F15", FP_REG(16), RFLT, 'f'},
+ {"F16", FP_REG(17), RFLT, 'F'},
+ {"F17", FP_REG(18), RFLT, 'f'},
+ {"F18", FP_REG(19), RFLT, 'F'},
+ {"F19", FP_REG(20), RFLT, 'f'},
+ {"F20", FP_REG(21), RFLT, 'F'},
+ {"F21", FP_REG(22), RFLT, 'f'},
+ {"F22", FP_REG(23), RFLT, 'F'},
+ {"F23", FP_REG(24), RFLT, 'f'},
+ {"F24", FP_REG(25), RFLT, 'F'},
+ {"F25", FP_REG(26), RFLT, 'f'},
+ {"F26", FP_REG(27), RFLT, 'F'},
+ {"F27", FP_REG(28), RFLT, 'f'},
+ {"F28", FP_REG(29), RFLT, 'F'},
+ {"F29", FP_REG(30), RFLT, 'f'},
+ {"F30", FP_REG(31), RFLT, 'F'},
+ {"F31", FP_REG(32), RFLT, 'f'},
+ { 0 }
+};
+
+/*
+ * sparc has same stack format as mips
+ */
+Mach msparc =
+{
+ "sparc",
+ MSPARC, /* machine type */
+ sparcreglist, /* register list */
+ REGSIZE, /* register set size in bytes */
+ FPREGSIZE, /* floating point register size in bytes */
+ "PC", /* name of PC */
+ "R1", /* name of SP */
+ "R15", /* name of link register */
+ "setSB", /* static base register name */
+ 0, /* value */
+ 0x1000, /* page size */
+ 0xE0000000, /* kernel base */
+ 0, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/kdb.c b/utils/libmach/kdb.c
new file mode 100644
index 00000000..bffd5e77
--- /dev/null
+++ b/utils/libmach/kdb.c
@@ -0,0 +1,1055 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+/*
+ * Sparc-specific debugger interface
+ */
+
+static char *sparcexcep(Map*, Rgetter);
+static int sparcfoll(Map*, ulong, Rgetter, ulong*);
+static int sparcinst(Map*, ulong, char, char*, int);
+static int sparcdas(Map*, ulong, char*, int);
+static int sparcinstlen(Map*, ulong);
+
+Machdata sparcmach =
+{
+ {0x91, 0xd0, 0x20, 0x01}, /* breakpoint: TA $1 */
+ 4, /* break point size */
+
+ beswab, /* convert short to local byte order */
+ beswal, /* convert long to local byte order */
+ beswav, /* convert vlong to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* frame finder */
+ sparcexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ beieeesftos, /* single precision float printer */
+ beieeedftos, /* double precision float printer */
+ sparcfoll, /* following addresses */
+ sparcinst, /* print instruction */
+ sparcdas, /* dissembler */
+ sparcinstlen, /* instruction size */
+};
+
+static char *trapname[] =
+{
+ "reset",
+ "instruction access exception",
+ "illegal instruction",
+ "privileged instruction",
+ "fp disabled",
+ "window overflow",
+ "window underflow",
+ "unaligned address",
+ "fp exception",
+ "data access exception",
+ "tag overflow",
+};
+
+static char*
+excname(ulong tbr)
+{
+ static char buf[32];
+
+ if(tbr < sizeof trapname/sizeof(char*))
+ return trapname[tbr];
+ if(tbr >= 130)
+ sprint(buf, "trap instruction %ld", tbr-128);
+ else if(17<=tbr && tbr<=31)
+ sprint(buf, "interrupt level %ld", tbr-16);
+ else switch(tbr){
+ case 36:
+ return "cp disabled";
+ case 40:
+ return "cp exception";
+ case 128:
+ return "syscall";
+ case 129:
+ return "breakpoint";
+ default:
+ sprint(buf, "unknown trap %ld", tbr);
+ }
+ return buf;
+}
+
+static char*
+sparcexcep(Map *map, Rgetter rget)
+{
+ long tbr;
+
+ tbr = (*rget)(map, "TBR");
+ tbr = (tbr&0xFFF)>>4;
+ return excname(tbr);
+}
+
+ /* Sparc disassembler and related functions */
+
+typedef struct instr Instr;
+
+struct opcode {
+ char *mnemonic;
+ void (*f)(Instr*, char*);
+ int flag;
+};
+
+static char FRAMENAME[] = ".frame";
+
+struct instr {
+ uchar op; /* bits 31-30 */
+ uchar rd; /* bits 29-25 */
+ uchar op2; /* bits 24-22 */
+ uchar a; /* bit 29 */
+ uchar cond; /* bits 28-25 */
+ uchar op3; /* bits 24-19 */
+ uchar rs1; /* bits 18-14 */
+ uchar i; /* bit 13 */
+ uchar asi; /* bits 12-05 */
+ uchar rs2; /* bits 04-00 */
+ short simm13; /* bits 12-00, signed */
+ ushort opf; /* bits 13-05 */
+ ulong immdisp22; /* bits 21-00 */
+ ulong simmdisp22; /* bits 21-00, signed */
+ ulong disp30; /* bits 30-00 */
+ ulong imm32; /* SETHI+ADD constant */
+ int target; /* SETHI+ADD dest reg */
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ char *curr; /* current fill level in output buffer */
+ char *end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char *err; /* errmsg */
+};
+
+static Map *mymap; /* disassembler context */
+static int dascase;
+
+static int mkinstr(ulong, Instr*);
+static void bra1(Instr*, char*, char*[]);
+static void bra(Instr*, char*);
+static void fbra(Instr*, char*);
+static void cbra(Instr*, char*);
+static void unimp(Instr*, char*);
+static void fpop(Instr*, char*);
+static void shift(Instr*, char*);
+static void sethi(Instr*, char*);
+static void load(Instr*, char*);
+static void loada(Instr*, char*);
+static void store(Instr*, char*);
+static void storea(Instr*, char*);
+static void add(Instr*, char*);
+static void cmp(Instr*, char*);
+static void wr(Instr*, char*);
+static void jmpl(Instr*, char*);
+static void rd(Instr*, char*);
+static void loadf(Instr*, char*);
+static void storef(Instr*, char*);
+static void loadc(Instr*, char*);
+static void loadcsr(Instr*, char*);
+static void trap(Instr*, char*);
+
+static struct opcode sparcop0[8] = {
+ "UNIMP", unimp, 0, /* page 137 */ /* 0 */
+ "", 0, 0, /* 1 */
+ "B", bra, 0, /* page 119 */ /* 2 */
+ "", 0, 0, /* 3 */
+ "SETHI", sethi, 0, /* page 104 */ /* 4 */
+ "", 0, 0, /* 5 */
+ "FB", fbra, 0, /* page 121 */ /* 6 */
+ "CB", cbra, 0, /* page 123 */ /* 7 */
+};
+
+static struct opcode sparcop2[64] = {
+ "ADD", add, 0, /* page 108 */ /* 0x00 */
+ "AND", add, 0, /* page 106 */ /* 0x01 */
+ "OR", add, 0, /* 0x02 */
+ "XOR", add, 0, /* 0x03 */
+ "SUB", add, 0, /* page 110 */ /* 0x04 */
+ "ANDN", add, 0, /* 0x05 */
+ "ORN", add, 0, /* 0x06 */
+ "XORN", add, 0, /* 0x07 */
+ "ADDX", add, 0, /* 0x08 */
+ "", 0, 0, /* 0x09 */
+ "UMUL", add, 0, /* page 113 */ /* 0x0a */
+ "SMUL", add, 0, /* 0x0b */
+ "SUBX", add, 0, /* 0x0c */
+ "", 0, 0, /* 0x0d */
+ "UDIV", add, 0, /* page 115 */ /* 0x0e */
+ "SDIV", add, 0, /* 0x0f */
+ "ADDCC", add, 0, /* 0x10 */
+ "ANDCC", add, 0, /* 0x11 */
+ "ORCC", add, 0, /* 0x12 */
+ "XORCC", add, 0, /* 0x13 */
+ "SUBCC", cmp, 0, /* 0x14 */
+ "ANDNCC", add, 0, /* 0x15 */
+ "ORNCC", add, 0, /* 0x16 */
+ "XORNCC", add, 0, /* 0x17 */
+ "ADDXCC", add, 0, /* 0x18 */
+ "", 0, 0, /* 0x19 */
+ "UMULCC", add, 0, /* 0x1a */
+ "SMULCC", add, 0, /* 0x1b */
+ "SUBXCC", add, 0, /* 0x1c */
+ "", 0, 0, /* 0x1d */
+ "UDIVCC", add, 0, /* 0x1e */
+ "SDIVCC", add, 0, /* 0x1f */
+ "TADD", add, 0, /* page 109 */ /* 0x20 */
+ "TSUB", add, 0, /* page 111 */ /* 0x21 */
+ "TADDCCTV", add, 0, /* 0x22 */
+ "TSUBCCTV", add, 0, /* 0x23 */
+ "MULSCC", add, 0, /* page 112 */ /* 0x24 */
+ "SLL", shift, 0, /* page 107 */ /* 0x25 */
+ "SRL", shift, 0, /* 0x26 */
+ "SRA", shift, 0, /* 0x27 */
+ "rdy", rd, 0, /* page 131 */ /* 0x28 */
+ "rdpsr", rd, 0, /* 0x29 */
+ "rdwim", rd, 0, /* 0x2a */
+ "rdtbr", rd, 0, /* 0x2b */
+ "", 0, 0, /* 0x2c */
+ "", 0, 0, /* 0x2d */
+ "", 0, 0, /* 0x2e */
+ "", 0, 0, /* 0x2f */
+ "wry", wr, 0, /* page 133 */ /* 0x30 */
+ "wrpsr", wr, 0, /* 0x31 */
+ "wrwim", wr, 0, /* 0x32 */
+ "wrtbr", wr, 0, /* 0x33 */
+ "FPOP", fpop, 0, /* page 140 */ /* 0x34 */
+ "FPOP", fpop, 0, /* 0x35 */
+ "", 0, 0, /* 0x36 */
+ "", 0, 0, /* 0x37 */
+ "JMPL", jmpl, 0, /* page 126 */ /* 0x38 */
+ "RETT", add, 0, /* page 127 */ /* 0x39 */
+ "T", trap, 0, /* page 129 */ /* 0x3a */
+ "flush", add, 0, /* page 138 */ /* 0x3b */
+ "SAVE", add, 0, /* page 117 */ /* 0x3c */
+ "RESTORE", add, 0, /* 0x3d */
+};
+
+static struct opcode sparcop3[64]={
+ "ld", load, 0, /* 0x00 */
+ "ldub", load, 0, /* 0x01 */
+ "lduh", load, 0, /* 0x02 */
+ "ldd", load, 0, /* 0x03 */
+ "st", store, 0, /* 0x04 */
+ "stb", store, 0, /* page 95 */ /* 0x05 */
+ "sth", store, 0, /* 0x06 */
+ "std", store, 0, /* 0x07 */
+ "", 0, 0, /* 0x08 */
+ "ldsb", load, 0, /* page 90 */ /* 0x09 */
+ "ldsh", load, 0, /* 0x0a */
+ "", 0, 0, /* 0x0b */
+ "", 0, 0, /* 0x0c */
+ "ldstub", store, 0, /* page 101 */ /* 0x0d */
+ "", 0, 0, /* 0x0e */
+ "swap", load, 0, /* page 102 */ /* 0x0f */
+ "lda", loada, 0, /* 0x10 */
+ "lduba", loada, 0, /* 0x11 */
+ "lduha", loada, 0, /* 0x12 */
+ "ldda", loada, 0, /* 0x13 */
+ "sta", storea, 0, /* 0x14 */
+ "stba", storea, 0, /* 0x15 */
+ "stha", storea, 0, /* 0x16 */
+ "stda", storea, 0, /* 0x17 */
+ "", 0, 0, /* 0x18 */
+ "ldsba", loada, 0, /* 0x19 */
+ "ldsha", loada, 0, /* 0x1a */
+ "", 0, 0, /* 0x1b */
+ "", 0, 0, /* 0x1c */
+ "ldstuba", storea, 0, /* 0x1d */
+ "", 0, 0, /* 0x1e */
+ "swapa", loada, 0, /* 0x1f */
+ "ldf", loadf, 0, /* page 92 */ /* 0x20 */
+ "ldfsr", loadf,0, /* 0x21 */
+ "", 0, 0, /* 0x22 */
+ "lddf", loadf, 0, /* 0x23 */
+ "stf", storef, 0, /* page 97 */ /* 0x24 */
+ "stfsr", storef,0, /* 0x25 */
+ "stdfq", storef,0, /* 0x26 */
+ "stdf", storef, 0, /* 0x27 */
+ "", 0, 0, /* 0x28 */
+ "", 0, 0, /* 0x29 */
+ "", 0, 0, /* 0x2a */
+ "", 0, 0, /* 0x2b */
+ "", 0, 0, /* 0x2c */
+ "", 0, 0, /* 0x2d */
+ "", 0, 0, /* 0x2e */
+ "", 0, 0, /* 0x2f */
+ "ldc", loadc, 0, /* page 94 */ /* 0x30 */
+ "ldcsr", loadcsr,0, /* 0x31 */
+ "", 0, 0, /* 0x32 */
+ "lddc", loadc, 0, /* 0x33 */
+ "stc", loadc, 0, /* page 99 */ /* 0x34 */
+ "stcsr", loadcsr,0, /* 0x35 */
+ "stdcq", loadcsr,0, /* 0x36 */
+ "stdc", loadc, 0, /* 0x37 */
+};
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+ long w;
+
+ if (get4(mymap, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->op = (w >> 30) & 0x03;
+ i->rd = (w >> 25) & 0x1F;
+ i->op2 = (w >> 22) & 0x07;
+ i->a = (w >> 29) & 0x01;
+ i->cond = (w >> 25) & 0x0F;
+ i->op3 = (w >> 19) & 0x3F;
+ i->rs1 = (w >> 14) & 0x1F;
+ i->i = (w >> 13) & 0x01;
+ i->asi = (w >> 5) & 0xFF;
+ i->rs2 = (w >> 0) & 0x1F;
+ i->simm13 = (w >> 0) & 0x1FFF;
+ if(i->simm13 & (1<<12))
+ i->simm13 |= ~((1<<13)-1);
+ i->opf = (w >> 5) & 0x1FF;
+ i->immdisp22 = (w >> 0) & 0x3FFFFF;
+ i->simmdisp22 = i->immdisp22;
+ if(i->simmdisp22 & (1<<21))
+ i->simmdisp22 |= ~((1<<22)-1);
+ i->disp30 = (w >> 0) & 0x3FFFFFFF;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong pc, Instr *i)
+{
+ Instr xi;
+
+ if (decode(pc, i) < 0)
+ return -1;
+ if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */
+ if (decode(pc+4, &xi) < 0)
+ return -1;
+ if(xi.op==2 && xi.op3==0) /* ADD */
+ if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */
+ i->imm32 = xi.simm13 + (i->immdisp22<<10);
+ i->target = xi.rd;
+ i->w1 = xi.w0;
+ i->size++;
+ return 1;
+ }
+ }
+ if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */
+ if (decode(pc+4, &xi) < 0)
+ return -1;
+ if(i->op==2 && i->opf==1) /* FMOVS */
+ if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
+ i->w1 = xi.w0;
+ i->size++;
+ }
+ }
+ return 1;
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr instr;
+ void (*f)(Instr*, char*);
+
+ mymap = map;
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ if (mkinstr(pc, &instr) < 0)
+ return -1;
+ switch(instr.op){
+ case 0:
+ f = sparcop0[instr.op2].f;
+ if(f)
+ (*f)(&instr, sparcop0[instr.op2].mnemonic);
+ else
+ bprint(&instr, "unknown %lux", instr.w0);
+ break;
+
+ case 1:
+ bprint(&instr, "%X", "CALL\t");
+ instr.curr += symoff(instr.curr, instr.end-instr.curr,
+ pc+instr.disp30*4, CTEXT);
+ if (!dascase)
+ bprint(&instr, "(SB)");
+ break;
+
+ case 2:
+ f = sparcop2[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop2[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown %lux", instr.w0);
+ break;
+
+ case 3:
+ f = sparcop3[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop3[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown %lux", instr.w0);
+ break;
+ }
+ if (instr.err) {
+ if (instr.curr != buf)
+ bprint(&instr, "\t\t;");
+ bprint(&instr, instr.err);
+ }
+ return instr.size*4;
+}
+
+/* convert to lower case from upper, according to dascase */
+static int
+Xconv(Fmt *f)
+{
+ char buf[128];
+ char *s, *t, *oa;
+
+ oa = va_arg(f->args, char*);
+ if(dascase){
+ for(s=oa,t=buf; *t = *s; s++,t++)
+ if('A'<=*t && *t<='Z')
+ *t += 'a'-'A';
+ return fmtstrcpy(f, buf);
+ }
+ return fmtstrcpy(f, oa);
+}
+
+static int
+sparcinst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ static int fmtinstalled = 0;
+
+ /* a modifier of 'I' toggles the dissassembler type */
+ if (!fmtinstalled) {
+ fmtinstalled = 1;
+ fmtinstall('X', Xconv);
+ }
+ if ((asstype == ASUNSPARC && modifier == 'i')
+ || (asstype == ASPARC && modifier == 'I'))
+ dascase = 'a'-'A';
+ else
+ dascase = 0;
+ return printins(map, pc, buf, n);
+}
+
+static int
+sparcdas(Map *map, ulong pc, char *buf, int n)
+{
+ Instr instr;
+
+ mymap = map;
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ if (mkinstr(pc, &instr) < 0)
+ return -1;
+ if (instr.end-instr.curr > 8)
+ instr.curr = _hexify(instr.curr, instr.w0, 7);
+ if (instr.end-instr.curr > 9 && instr.size == 2) {
+ *instr.curr++ = ' ';
+ instr.curr = _hexify(instr.curr, instr.w1, 7);
+ }
+ *instr.curr = 0;
+ return instr.size*4;
+}
+
+static int
+sparcinstlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ return i.size*4;
+}
+
+static int
+plocal(Instr *i)
+{
+ int offset;
+ Symbol s;
+
+ if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
+ return -1;
+ if (s.value > i->simm13) {
+ if(getauto(&s, s.value-i->simm13, CAUTO, &s)) {
+ bprint(i, "%s+%d(SP)", s.name, s.value);
+ return 1;
+ }
+ } else {
+ offset = i->simm13-s.value;
+ if (getauto(&s, offset-4, CPARAM, &s)) {
+ bprint(i, "%s+%d(FP)", s.name, offset);
+ return 1;
+ }
+ }
+ return -1;
+}
+
+static void
+address(Instr *i)
+{
+ Symbol s, s2;
+ long off, off1;
+
+ if (i->rs1 == 1 && plocal(i) >= 0)
+ return;
+ off = mach->sb+i->simm13;
+ if(i->rs1 == 2 && findsym(off, CANY, &s)
+ && s.value-off < 4096
+ && (s.class == CDATA || s.class == CTEXT)) {
+ if(off==s.value && s.name[0]=='$'){
+ off1 = 0;
+ get4(mymap, s.value, &off1);
+ if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
+ bprint(i, "$%s(SB)", s2.name);
+ return;
+ }
+ }
+ bprint(i, "%s", s.name);
+ if (s.value != off)
+ bprint(i, "+%lux", s.value-off);
+ bprint(i, "(SB)");
+ return;
+ }
+ bprint(i, "%lux(R%d)", i->simm13, i->rs1);
+}
+
+static void
+unimp(Instr *i, char *m)
+{
+ bprint(i, "%X", m);
+}
+
+static char *bratab[16] = { /* page 91 */
+ "N", /* 0x0 */
+ "E", /* 0x1 */
+ "LE", /* 0x2 */
+ "L", /* 0x3 */
+ "LEU", /* 0x4 */
+ "CS", /* 0x5 */
+ "NEG", /* 0x6 */
+ "VS", /* 0x7 */
+ "A", /* 0x8 */
+ "NE", /* 0x9 */
+ "G", /* 0xa */
+ "GE", /* 0xb */
+ "GU", /* 0xc */
+ "CC", /* 0xd */
+ "POS", /* 0xe */
+ "VC", /* 0xf */
+};
+
+static char *fbratab[16] = { /* page 91 */
+ "N", /* 0x0 */
+ "NE", /* 0x1 */
+ "LG", /* 0x2 */
+ "UL", /* 0x3 */
+ "L", /* 0x4 */
+ "UG", /* 0x5 */
+ "G", /* 0x6 */
+ "U", /* 0x7 */
+ "A", /* 0x8 */
+ "E", /* 0x9 */
+ "UE", /* 0xa */
+ "GE", /* 0xb */
+ "UGE", /* 0xc */
+ "LE", /* 0xd */
+ "ULE", /* 0xe */
+ "O", /* 0xf */
+};
+
+static char *cbratab[16] = { /* page 91 */
+ "N", /* 0x0 */
+ "123", /* 0x1 */
+ "12", /* 0x2 */
+ "13", /* 0x3 */
+ "1", /* 0x4 */
+ "23", /* 0x5 */
+ "2", /* 0x6 */
+ "3", /* 0x7 */
+ "A", /* 0x8 */
+ "0", /* 0x9 */
+ "03", /* 0xa */
+ "02", /* 0xb */
+ "023", /* 0xc */
+ "01", /* 0xd */
+ "013", /* 0xe */
+ "012", /* 0xf */
+};
+
+static void
+bra1(Instr *i, char *m, char *tab[])
+{
+ long imm;
+
+ imm = i->simmdisp22;
+ if(i->a)
+ bprint(i, "%X%X.%c\t", m, tab[i->cond], 'A'+dascase);
+ else
+ bprint(i, "%X%X\t", m, tab[i->cond]);
+ i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT);
+ if (!dascase)
+ bprint(i, "(SB)");
+}
+
+static void
+bra(Instr *i, char *m) /* page 91 */
+{
+ bra1(i, m, bratab);
+}
+
+static void
+fbra(Instr *i, char *m) /* page 93 */
+{
+ bra1(i, m, fbratab);
+}
+
+static void
+cbra(Instr *i, char *m) /* page 95 */
+{
+ bra1(i, m, cbratab);
+}
+
+static void
+trap(Instr *i, char *m) /* page 101 */
+{
+ if(i->i == 0)
+ bprint(i, "%X%X\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
+ else
+ bprint(i, "%X%X\t$%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
+}
+
+static void
+sethi(Instr *i, char *m) /* page 89 */
+{
+ ulong imm;
+
+ imm = i->immdisp22<<10;
+ if(dascase){
+ bprint(i, "%X\t%lux, R%d", m, imm, i->rd);
+ return;
+ }
+ if(imm==0 && i->rd==0){
+ bprint(i, "NOP");
+ return;
+ }
+ if(i->target < 0){
+ bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
+ return;
+ }
+ bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
+}
+
+static char ldtab[] = {
+ 'W',
+ 'B',
+ 'H',
+ 'D',
+};
+
+static char*
+moveinstr(int op3, char *m)
+{
+ char *s;
+ int c;
+ static char buf[8];
+
+ if(!dascase){
+ /* batshit cases */
+ if(op3 == 0xF || op3 == 0x1F)
+ return "SWAP";
+ if(op3 == 0xD || op3 == 0x1D)
+ return "TAS"; /* really LDSTUB */
+ c = ldtab[op3&3];
+ s = "";
+ if((op3&11)==1 || (op3&11)==2)
+ s="U";
+ sprint(buf, "MOV%c%s", c, s);
+ return buf;
+ }
+ return m;
+}
+
+static void
+load(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+}
+
+static void
+loada(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
+ else
+ bprint(i, "unknown ld asi %lux", i->w0);
+}
+
+static void
+store(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d)",
+ m, i->rd, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\tR%d, ", m, i->rd);
+ address(i);
+ }
+}
+
+static void
+storea(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
+ else
+ bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
+}
+
+static void
+shift(Instr *i, char *m) /* page 88 */
+{
+ if(i->i == 0){
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1);
+ else
+ if(dascase)
+ bprint(i, "%X\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
+ else
+ bprint(i, "%X\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%X\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
+ else
+ bprint(i, "%X\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
+ else
+ if(dascase)
+ bprint(i, "%X\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
+ else
+ bprint(i, "%X\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
+ }
+}
+
+static void
+add(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(dascase)
+ bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */
+ bprint(i, "MOVW\tR%d", i->rs2);
+ else
+ bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1);
+ }else{
+ if(dascase)
+ bprint(i, "%X\tR%d, $%lux", m, i->rs1, i->simm13);
+ else
+ if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */
+ bprint(i, "MOVW\t$%lux", i->simm13);
+ else if(i->op3==0 && i->rd && i->rs1==2){
+ /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
+ bprint(i, "MOVW\t$");
+ address(i);
+ } else
+ bprint(i, "%X\t$%lux, R%d", m, i->simm13, i->rs1);
+ }
+ if(i->rs1 != i->rd)
+ bprint(i, ", R%d", i->rd);
+}
+
+static void
+cmp(Instr *i, char *m)
+{
+ if(dascase || i->rd){
+ add(i, m);
+ return;
+ }
+ if(i->i == 0)
+ bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
+ else
+ bprint(i, "CMP\tR%d, $%lux", i->rs1, i->simm13);
+}
+
+static char *regtab[4] = {
+ "Y",
+ "PSR",
+ "WIM",
+ "TBR",
+};
+
+static void
+wr(Instr *i, char *m) /* page 82 */
+{
+ if(dascase){
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%s\tR%d, $%lux", m, i->rs1, i->simm13);
+ }else{
+ if(i->i && i->simm13==0)
+ bprint(i, "MOVW\tR%d", i->rs1);
+ else if(i->i == 0)
+ bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
+ else
+ bprint(i, "wr\t$%lux, R%d", i->simm13, i->rs1);
+ }
+ bprint(i, ", %s", regtab[i->op3&3]);
+}
+
+static void
+rd(Instr *i, char *m) /* page 103 */
+{
+ if(i->rs1==15 && i->rd==0){
+ m = "stbar";
+ if(!dascase)
+ m = "STBAR";
+ bprint(i, "%s", m);
+ }else{
+ if(!dascase)
+ m = "MOVW";
+ bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
+ }
+}
+
+static void
+jmpl(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(i->rd == 15)
+ bprint(i, "%X\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
+ else
+ bprint(i, "%X\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
+ bprint(i, "RETURN");
+ else{
+ bprint(i, "%X\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+ }
+}
+
+static void
+loadf(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x20)
+ m = "FMOVF";
+ else if(i->op3 == 0x21)
+ m = "MOVW";
+ }
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ }
+ if(i->op3 == 0x21)
+ bprint(i, ", FSR");
+ else
+ bprint(i, ", R%d", i->rd);
+}
+
+static
+void storef(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x25 || i->op3 == 0x26)
+ m = "MOVW";
+ else if(i->op3 == 0x20)
+ m = "FMOVF";
+ }
+ bprint(i, "%s\t", m);
+ if(i->op3 == 0x25)
+ bprint(i, "FSR, ");
+ else if(i->op3 == 0x26)
+ bprint(i, "FQ, ");
+ else
+ bprint(i, "R%d, ", i->rd);
+ if(i->i == 0)
+ bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
+ else
+ address(i);
+}
+
+static
+void loadc(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", C%d", i->rd);
+ }
+}
+
+static
+void loadcsr(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", CSR");
+ }
+}
+
+static struct{
+ int opf;
+ char *name;
+} fptab1[] = { /* ignores rs1 */
+ 0xC4, "FITOS", /* page 109 */
+ 0xC8, "FITOD",
+ 0xCC, "FITOX",
+
+ 0xD1, "FSTOI", /* page 110 */
+ 0xD2, "FDTOI",
+ 0xD3, "FXTOI",
+
+ 0xC9, "FSTOD", /* page 111 */
+ 0xCD, "FSTOX",
+ 0xC6, "FDTOS",
+ 0xCE, "FDTOX",
+ 0xC7, "FXTOS",
+ 0xCB, "FXTOD",
+
+ 0x01, "FMOVS", /* page 112 */
+ 0x05, "FNEGS",
+ 0x09, "FABSS",
+
+ 0x29, "FSQRTS", /* page 113 */
+ 0x2A, "FSQRTD",
+ 0x2B, "FSQRTX",
+
+ 0, 0,
+};
+
+static struct{
+ int opf;
+ char *name;
+} fptab2[] = { /* uses rs1 */
+
+ 0x41, "FADDS", /* page 114 */
+ 0x42, "FADDD",
+ 0x43, "FADDX",
+ 0x45, "FSUBS",
+ 0x46, "FSUBD",
+ 0x47, "FSUBX",
+
+ 0x49, "FMULS", /* page 115 */
+ 0x4A, "FMULD",
+ 0x4B, "FMULX",
+ 0x4D, "FDIVS",
+ 0x4E, "FDIVD",
+ 0x4F, "FDIVX",
+
+ 0x51, "FCMPS", /* page 116 */
+ 0x52, "FCMPD",
+ 0x53, "FCMPX",
+ 0x55, "FCMPES",
+ 0x56, "FCMPED",
+ 0x57, "FCMPEX",
+
+ 0, 0
+};
+
+static void
+fpop(Instr *i, char *m) /* page 108-116 */
+{
+ int j;
+
+ if(dascase==0 && i->size==2){
+ bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab1[j].name; j++)
+ if(fptab1[j].opf == i->opf){
+ bprint(i, "%X\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab2[j].name; j++)
+ if(fptab2[j].opf == i->opf){
+ bprint(i, "%X\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
+ return;
+ }
+ bprint(i, "%X%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
+}
+
+static int
+sparcfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ ulong w, r1, r2;
+ char buf[8];
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ w = i.w0;
+ switch(w & 0xC1C00000){
+ case 0x00800000: /* branch on int cond */
+ case 0x01800000: /* branch on fp cond */
+ case 0x01C00000: /* branch on copr cond */
+ foll[0] = pc+8;
+ foll[1] = pc + (i.simmdisp22<<2);
+ return 2;
+ }
+
+ if((w&0xC0000000) == 0x40000000){ /* CALL */
+ foll[0] = pc + (i.disp30<<2);
+ return 1;
+ }
+
+ if((w&0xC1F80000) == 0x81C00000){ /* JMPL */
+ sprint(buf, "R%ld", (w>>14)&0xF);
+ r1 = (*rget)(map, buf);
+ if(w & 0x2000) /* JMPL R1+simm13 */
+ r2 = i.simm13;
+ else{ /* JMPL R1+R2 */
+ sprint(buf, "R%ld", w&0xF);
+ r2 = (*rget)(map, buf);
+ }
+ foll[0] = r1 + r2;
+ return 1;
+ }
+ foll[0] = pc+i.size*4;
+ return 1;
+}
diff --git a/utils/libmach/kobj.c b/utils/libmach/kobj.c
new file mode 100644
index 00000000..f8d7e613
--- /dev/null
+++ b/utils/libmach/kobj.c
@@ -0,0 +1,132 @@
+/*
+ * kobj.c - identify and parse a sparc object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "kc/k.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+
+int
+_isk(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+
+int
+_readk(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 5); /* reg (1 byte); lineno (4 bytes) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp, 1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type) {
+ default:
+ case D_NONE: case D_REG: case D_FREG: case D_CREG: case D_PREG:
+ break;
+ case D_BRANCH:
+ case D_OREG:
+ case D_ASI:
+ case D_CONST:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym!=0 && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/mach.h b/utils/libmach/mach.h
new file mode 100644
index 00000000..6a5d2569
--- /dev/null
+++ b/utils/libmach/mach.h
@@ -0,0 +1,294 @@
+/*
+ * Architecture-dependent application data
+ */
+#include "a.out.h"
+/*
+ * Supported architectures:
+ * mips,
+ * 68020,
+ * i386,
+ * amd64,
+ * sparc,
+ * mips2 (R4000)
+ * arm
+ */
+enum
+{
+ MMIPS, /* machine types */
+ MSPARC,
+ M68020,
+ MI386,
+ MI960, /* retired */
+ M3210, /* retired */
+ MMIPS2,
+ NMIPS2,
+ M29000, /* retired */
+ MARM,
+ MPOWER,
+
+ /* types of executables */
+ FNONE = 0, /* unidentified */
+ FMIPS, /* v.out */
+ FMIPSB, /* mips bootable */
+ FSPARC, /* k.out */
+ FSPARCB, /* Sparc bootable */
+ F68020, /* 2.out */
+ F68020B, /* 68020 bootable */
+ FNEXTB, /* Next bootable */
+ FI386, /* 8.out */
+ FI386B, /* I386 bootable */
+ FI960, /* retired */
+ FI960B, /* retired */
+ F3210, /* retired */
+ FMIPS2BE, /* 4.out */
+ F29000, /* retired */
+ FARM, /* 5.out */
+ FARMB, /* ARM bootable */
+ FPOWER, /* q.out */
+ FPOWERB, /* power pc bootable */
+ FMIPS2LE, /* 4k little endian */
+
+ ANONE = 0, /* dissembler types */
+ AMIPS,
+ AMIPSCO, /* native mips */
+ ASPARC,
+ ASUNSPARC, /* native sun */
+ A68020,
+ AI386,
+ AI8086, /* oh god */
+ AI960, /* retired */
+ A29000,
+ AARM,
+ APOWER,
+ /* object file types */
+ Obj68020 = 0, /* .2 */
+ ObjSparc, /* .k */
+ ObjMips, /* .v */
+ Obj386, /* .8 */
+ Obj960, /* retired */
+ Obj3210, /* .x */
+ ObjMips2, /* .4 */
+ Obj29000, /* retired */
+ ObjArm, /* .5 */
+ ObjPower, /* .q */
+ ObjMips2le, /* .0 */
+ Maxobjtype,
+
+ CNONE = 0, /* symbol table classes */
+ CAUTO,
+ CPARAM,
+ CSTAB,
+ CTEXT,
+ CDATA,
+ CANY /* to look for any class */
+};
+
+typedef struct Map Map;
+typedef struct Symbol Symbol;
+typedef struct Reglist Reglist;
+typedef struct Mach Mach;
+typedef struct Machdata Machdata;
+typedef struct segment segment;
+
+typedef int (*Rsegio)(segment*, ulong, long, char*, int);
+
+/*
+ * Structure to map a segment to a position in a file
+ */
+struct Map {
+ int nsegs; /* number of segments */
+ struct segment { /* per-segment map */
+ char *name; /* the segment name */
+ int fd; /* file descriptor */
+ int inuse; /* in use - not in use */
+ ulong b; /* base */
+ ulong e; /* end */
+ ulong f; /* offset within file */
+ Rsegio mget; /* special get if not 0 */
+ Rsegio mput; /* special put if not 0 */
+ } seg[1]; /* actually n of these */
+};
+
+
+
+/*
+ * Internal structure describing a symbol table entry
+ */
+struct Symbol {
+ void *handle; /* used internally - owning func */
+ /*struct {*/
+ char *name;
+ long value; /* address or stack offset */
+ char type; /* as in a.out.h */
+ char class; /* as above */
+ /*};*/
+};
+
+/*
+ * machine register description
+ */
+struct Reglist {
+ char *rname; /* register name */
+ short roffs; /* offset in u-block */
+ char rflags; /* INTEGER/FLOAT, WRITABLE */
+ char rformat; /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */
+};
+
+enum { /* bits in rflags field */
+ RINT = (0<<0),
+ RFLT = (1<<0),
+ RRDONLY = (1<<1)
+};
+/*
+ * Machine-dependent data is stored in two structures:
+ * Mach - miscellaneous general parameters
+ * Machdata - jump vector of service functions used by debuggers
+ *
+ * Mach is defined in 2.c, 4.c, v.c, k.c, 8.c, 6.c and set in executable.c
+ *
+ * Machdata is defined in 2db.c, 4db.c, vdb.c, kdb.c, 8db.c, and 6db.c
+ * and set in the debugger startup.
+ */
+
+
+struct Mach{
+ char *name;
+ int mtype; /* machine type code */
+ Reglist *reglist; /* register set */
+ ulong regsize; /* sizeof registers in bytes*/
+ ulong fpregsize; /* sizeof fp registers in bytes*/
+ char *pc; /* pc name */
+ char *sp; /* sp name */
+ char *link; /* link register name */
+ char *sbreg; /* static base register name */
+ ulong sb; /* static base register value */
+ int pgsize; /* page size */
+ ulong kbase; /* kernel base address */
+ ulong ktmask; /* ktzero = kbase & ~ktmask */
+ int pcquant; /* quantization of pc */
+ int szaddr; /* sizeof(void*) */
+ int szreg; /* sizeof(register) */
+ int szfloat; /* sizeof(float) */
+ int szdouble; /* sizeof(double) */
+};
+
+extern Mach *mach; /* Current machine */
+
+typedef vlong (*Rgetter)(Map*, char*);
+typedef void (*Tracer)(Map*, ulong, ulong, Symbol*);
+
+struct Machdata { /* Machine-dependent debugger support */
+ uchar bpinst[4]; /* break point instr. */
+ short bpsize; /* size of break point instr. */
+
+ ushort (*swab)(ushort); /* short to local byte order */
+ long (*swal)(long); /* long to local byte order */
+ vlong (*swav)(vlong); /* vlong to local byte order */
+ int (*ctrace)(Map*, ulong, ulong, ulong, Tracer); /* C traceback */
+ ulong (*findframe)(Map*, ulong, ulong, ulong, ulong);/* frame finder */
+ char* (*excep)(Map*, Rgetter); /* last exception */
+ ulong (*bpfix)(ulong); /* breakpoint fixup */
+ int (*sftos)(char*, int, void*); /* single precision float */
+ int (*dftos)(char*, int, void*); /* double precision float */
+ int (*foll)(Map*, ulong, Rgetter, ulong*); /* follow set */
+ int (*das)(Map*, ulong, char, char*, int); /* symbolic disassembly */
+ int (*hexinst)(Map*, ulong, char*, int); /* hex disassembly */
+ int (*instsize)(Map*, ulong); /* instruction size */
+};
+
+/*
+ * Common a.out header describing all architectures
+ */
+typedef struct Fhdr
+{
+ char *name; /* identifier of executable */
+ short type; /* file type - see codes above*/
+ short hdrsz; /* size of this header */
+ long magic; /* magic number */
+ long txtaddr; /* text address */
+ long entry; /* entry point */
+ long txtsz; /* text size */
+ long txtoff; /* start of text in file */
+ long dataddr; /* start of data segment */
+ long datsz; /* size of data seg */
+ long datoff; /* offset to data seg in file */
+ long bsssz; /* size of bss */
+ long symsz; /* size of symbol table */
+ long symoff; /* offset of symbol table in file */
+ long sppcsz; /* size of sp-pc table */
+ long sppcoff; /* offset of sp-pc table in file */
+ long lnpcsz; /* size of line number-pc table */
+ long lnpcoff; /* size of line number-pc table */
+} Fhdr;
+
+extern int asstype; /* dissembler type - machdata.c */
+extern Machdata *machdata; /* jump vector - machdata.c */
+
+Map* attachproc(int, int, int, Fhdr*);
+Map* attachremt(int, Fhdr*);
+int beieee80ftos(char*, int, void*);
+int beieeesftos(char*, int, void*);
+int beieeedftos(char*, int, void*);
+ushort beswab(ushort);
+long beswal(long);
+vlong beswav(vlong);
+int cisctrace(Map*, ulong, ulong, ulong, Tracer);
+ulong ciscframe(Map*, ulong, ulong, ulong, ulong);
+int crackhdr(int fd, Fhdr*);
+long file2pc(char*, ulong);
+int fileelem(Sym**, uchar *, char*, int);
+int fileline(char*, int, ulong);
+int filesym(int, char*, int);
+int findlocal(Symbol*, char*, Symbol*);
+int findseg(Map*, char*);
+int findsym(long, int, Symbol *);
+int fnbound(long, ulong*);
+int fpformat(Map*, Reglist*, char*, int, int);
+int get1(Map*, ulong, uchar*, int);
+int get2(Map*, ulong, ushort*);
+int get4(Map*, ulong, long*);
+int get8(Map*, ulong, vlong*);
+int getauto(Symbol*, int, int, Symbol*);
+Sym* getsym(int);
+int globalsym(Symbol *, int);
+char* _hexify(char*, ulong, int);
+int ieeesftos(char*, int, ulong);
+int ieeedftos(char*, int, ulong, ulong);
+int isar(Biobuf*);
+int leieee80ftos(char*, int, void*);
+int leieeesftos(char*, int, void*);
+int leieeedftos(char*, int, void*);
+ushort leswab(ushort);
+long leswal(long);
+vlong leswav(vlong);
+long line2addr(ulong, ulong, ulong);
+Map* loadmap(Map*, int, Fhdr*);
+int localaddr(Map*, char*, char*, long*, Rgetter);
+int localsym(Symbol*, int);
+int lookup(char*, char*, Symbol*);
+void machbytype(int);
+int machbyname(char*);
+int nextar(Biobuf*, int, char*);
+Map* newmap(Map*, int);
+void objtraverse(void(*)(Sym*, void*), void*);
+int objtype(Biobuf*, char**);
+long pc2sp(ulong);
+long pc2line(ulong);
+int put1(Map*, ulong, uchar*, int);
+int put2(Map*, ulong, ushort);
+int put4(Map*, ulong, long);
+int put8(Map*, ulong, vlong);
+int readar(Biobuf*, int, int, int);
+int readobj(Biobuf*, int);
+struct segment* reloc(Map*, ulong, long*);
+ulong riscframe(Map*, ulong, ulong, ulong, ulong);
+int risctrace(Map*, ulong, ulong, ulong, Tracer);
+int setmap(Map*, int, ulong, ulong, ulong, char*);
+void setmapio(Map*, int, Rsegio, Rsegio);
+Sym* symbase(long*);
+int syminit(int, Fhdr*);
+int symoff(char*, int, long, int);
+void textseg(ulong, Fhdr*);
+int textsym(Symbol*, int);
+void unusemap(Map*, int);
+
diff --git a/utils/libmach/machdata.c b/utils/libmach/machdata.c
new file mode 100644
index 00000000..a82e14e8
--- /dev/null
+++ b/utils/libmach/machdata.c
@@ -0,0 +1,450 @@
+/*
+ * Debugger utilities shared by at least two architectures
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+#define STARTSYM "_main"
+#define PROFSYM "_mainp"
+#define FRAMENAME ".frame"
+
+extern Machdata mipsmach;
+
+int asstype = AMIPS; /* disassembler type */
+Machdata *machdata; /* machine-dependent functions */
+
+int
+localaddr(Map *map, char *fn, char *var, long *r, Rgetter rget)
+{
+ Symbol s;
+ ulong fp;
+ ulong pc, sp, link;
+
+ if (!lookup(fn, 0, &s)) {
+ werrstr("function not found");
+ return -1;
+ }
+ pc = rget(map, mach->pc);
+ sp = rget(map, mach->sp);
+ if(mach->link)
+ link = rget(map, mach->link);
+ else
+ link = 0;
+ fp = machdata->findframe(map, s.value, pc, sp, link);
+ if (fp == 0) {
+ werrstr("stack frame not found");
+ return -1;
+ }
+
+ if (!var || !var[0]) {
+ *r = fp;
+ return 1;
+ }
+
+ if (findlocal(&s, var, &s) == 0) {
+ werrstr("local variable not found");
+ return -1;
+ }
+
+ switch (s.class) {
+ case CAUTO:
+ *r = fp - s.value;
+ break;
+ case CPARAM: /* assume address size is stack width */
+ *r = fp + s.value + mach->szaddr;
+ break;
+ default:
+ werrstr("local variable not found: %d", s.class);
+ return -1;
+ }
+ return 1;
+}
+
+/*
+ * Print value v as name[+offset] and then the string s.
+ */
+int
+symoff(char *buf, int n, long v, int space)
+{
+ Symbol s;
+ int r;
+ long delta;
+
+ r = delta = 0; /* to shut compiler up */
+ if (v) {
+ r = findsym(v, space, &s);
+ if (r)
+ delta = v-s.value;
+ if (delta < 0)
+ delta = -delta;
+ }
+ if (v == 0 || r == 0)
+ return snprint(buf, n, "%lux", v);
+ if (s.type != 't' && s.type != 'T' && delta >= 4096)
+ return snprint(buf, n, "%lux", v);
+ if (strcmp(s.name, ".string") == 0)
+ return snprint(buf, n, "%lux", v);
+ if (delta)
+ return snprint(buf, n, "%s+%lux", s.name, v-s.value);
+ else
+ return snprint(buf, n, "%s", s.name);
+}
+/*
+ * Format floating point registers
+ *
+ * Register codes in format field:
+ * 'X' - print as 32-bit hexadecimal value
+ * 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
+ * 'f' - 32-bit ieee float
+ * '8' - big endian 80-bit ieee extended float
+ * '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
+ */
+int
+fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
+{
+ char reg[12];
+ long r;
+
+ switch(rp->rformat)
+ {
+ case 'X':
+ if (get4(map, rp->roffs, &r) < 0)
+ return -1;
+ snprint(buf, n, "%lux", r);
+ break;
+ case 'F': /* first reg of double reg pair */
+ if (modif == 'F')
+ if (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f') {
+ if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
+ return -1;
+ machdata->dftos(buf, n, reg);
+ return 2;
+ }
+ /* treat it like 'f' */
+ if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
+ return -1;
+ machdata->sftos(buf, n, reg);
+ break;
+ case 'f': /* 32 bit float */
+ if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
+ return -1;
+ machdata->sftos(buf, n, reg);
+ break;
+ case '3': /* little endian ieee 80 with hole in bytes 8&9 */
+ if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
+ return -1;
+ memmove(reg+10, reg+8, 2); /* open hole */
+ memset(reg+8, 0, 2); /* fill it */
+ leieee80ftos(buf, n, reg);
+ break;
+ case '8': /* big-endian ieee 80 */
+ if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
+ return -1;
+ beieee80ftos(buf, n, reg);
+ break;
+ default: /* unknown */
+ break;
+ }
+ return 1;
+}
+
+char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+/*
+ * These routines assume that if the number is representable
+ * in IEEE floating point, it will be representable in the native
+ * double format. Naive but workable, probably.
+ */
+int
+ieeedftos(char *buf, int n, ulong h, ulong l)
+{
+ double fr;
+ int exp;
+
+ if (n <= 0)
+ return 0;
+
+
+ if(h & (1L<<31)){
+ *buf++ = '-';
+ h &= ~(1L<<31);
+ }else
+ *buf++ = ' ';
+ n--;
+ if(l == 0 && h == 0)
+ return snprint(buf, n, "0.");
+ exp = (h>>20) & ((1L<<11)-1L);
+ if(exp == 0)
+ return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
+ if(exp == ((1L<<11)-1L)){
+ if(l==0 && (h&((1L<<20)-1L)) == 0)
+ return snprint(buf, n, "Inf");
+ else
+ return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
+ }
+ exp -= (1L<<10) - 2L;
+ fr = l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ fr = ldexp(fr, exp);
+ return snprint(buf, n, "%.18g", fr);
+}
+
+int
+ieeesftos(char *buf, int n, ulong h)
+{
+ double fr;
+ int exp;
+
+ if (n <= 0)
+ return 0;
+
+ if(h & (1L<<31)){
+ *buf++ = '-';
+ h &= ~(1L<<31);
+ }else
+ *buf++ = ' ';
+ n--;
+ if(h == 0)
+ return snprint(buf, n, "0.");
+ exp = (h>>23) & ((1L<<8)-1L);
+ if(exp == 0)
+ return snprint(buf, n, "DeN(%.8lux)", h);
+ if(exp == ((1L<<8)-1L)){
+ if((h&((1L<<23)-1L)) == 0)
+ return snprint(buf, n, "Inf");
+ else
+ return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
+ }
+ exp -= (1L<<7) - 2L;
+ fr = (h & ((1L<<23)-1L)) | (1L<<23);
+ fr /= 1L<<24;
+ fr = ldexp(fr, exp);
+ return snprint(buf, n, "%.9g", fr);
+}
+
+int
+beieeesftos(char *buf, int n, void *s)
+{
+ return ieeesftos(buf, n, beswal(*(ulong*)s));
+}
+
+int
+beieeedftos(char *buf, int n, void *s)
+{
+ return ieeedftos(buf, n, beswal(*(ulong*)s), beswal(((ulong*)(s))[1]));
+}
+
+int
+leieeesftos(char *buf, int n, void *s)
+{
+ return ieeesftos(buf, n, leswal(*(ulong*)s));
+}
+
+int
+leieeedftos(char *buf, int n, void *s)
+{
+ return ieeedftos(buf, n, leswal(((ulong*)(s))[1]), leswal(*(ulong*)s));
+}
+
+/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
+int
+beieee80ftos(char *buf, int n, void *s)
+{
+ uchar *reg = (uchar*)s;
+ int i;
+ ulong x;
+ uchar ieee[8+8]; /* room for slop */
+ uchar *p, *q;
+
+ memset(ieee, 0, sizeof(ieee));
+ /* sign */
+ if(reg[0] & 0x80)
+ ieee[0] |= 0x80;
+
+ /* exponent */
+ x = ((reg[0]&0x7F)<<8) | reg[1];
+ if(x == 0) /* number is ±0 */
+ goto done;
+ if(x == 0x7FFF){
+ if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
+ x = 2047;
+ }else{ /* NaN */
+ x = 2047;
+ ieee[7] = 0x1; /* make sure */
+ }
+ ieee[0] |= x>>4;
+ ieee[1] |= (x&0xF)<<4;
+ goto done;
+ }
+ x -= 0x3FFF; /* exponent bias */
+ x += 1023;
+ if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
+ return snprint(buf, n, "not in range");
+ ieee[0] |= x>>4;
+ ieee[1] |= (x&0xF)<<4;
+
+ /* mantissa */
+ p = reg+4;
+ q = ieee+1;
+ for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
+ x = (p[0]&0x7F) << 1;
+ if(p[1] & 0x80)
+ x |= 1;
+ q[0] |= x>>4;
+ q[1] |= (x&0xF)<<4;
+ }
+ done:
+ return beieeedftos(buf, n, (void*)ieee);
+}
+
+
+int
+leieee80ftos(char *buf, int n, void *s)
+{
+ int i;
+ char *cp;
+ char b[12];
+
+ cp = (char*) s;
+ for(i=0; i<12; i++)
+ b[11-i] = *cp++;
+ return beieee80ftos(buf, n, b);
+}
+
+int
+cisctrace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace)
+{
+ Symbol s;
+ int found;
+ ulong opc;
+ long moved, j;
+
+ USED(link);
+ j = 0;
+ opc = 0;
+ while(pc && opc != pc) {
+ moved = pc2sp(pc);
+ if (moved == -1)
+ break;
+ found = findsym(pc, CTEXT, &s);
+ if (!found)
+ break;
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ sp += moved;
+ opc = pc;
+ if (get4(map, sp, (long *)&pc) < 0)
+ break;
+ (*trace)(map, pc, sp, &s);
+ sp += mach->szaddr; /*assumes address size = stack width*/
+ if(++j > 40)
+ break;
+ }
+ return j;
+}
+
+int
+risctrace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace)
+{
+ int i;
+ Symbol s, f;
+ ulong oldpc;
+
+ i = 0;
+ while(findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc == s.value) /* at first instruction */
+ f.value = 0;
+ else if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+
+ oldpc = pc;
+ if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
+ pc = link;
+ else
+ if (get4(map, sp, (long *) &pc) < 0)
+ break;
+
+ if(pc == 0 || (pc == oldpc && f.value == 0))
+ break;
+
+ sp += f.value;
+ (*trace)(map, pc-8, sp, &s);
+
+ if(++i > 40)
+ break;
+ }
+ return i;
+}
+
+ulong
+ciscframe(Map *map, ulong addr, ulong pc, ulong sp, ulong link)
+{
+ Symbol s;
+ int moved;
+
+ USED(link);
+ for(;;) {
+ moved = pc2sp(pc);
+ if (moved == -1)
+ break;
+ sp += moved;
+ findsym(pc, CTEXT, &s);
+ if (addr == s.value)
+ return sp;
+ if (get4(map, sp, (long *) &pc) < 0)
+ break;
+ sp += mach->szaddr; /*assumes sizeof(addr) = stack width*/
+ }
+ return 0;
+}
+
+ulong
+riscframe(Map *map, ulong addr, ulong pc, ulong sp, ulong link)
+{
+ Symbol s, f;
+
+ while (findsym(pc, CTEXT, &s)) {
+ if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+ break;
+
+ if(pc == s.value) /* at first instruction */
+ f.value = 0;
+ else
+ if(findlocal(&s, FRAMENAME, &f) == 0)
+ break;
+
+ sp += f.value;
+ if (s.value == addr)
+ return sp;
+
+ if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
+ pc = link;
+ else
+ if (get4(map, sp-f.value, (long *)&pc) < 0)
+ break;
+ }
+ return 0;
+}
diff --git a/utils/libmach/map.c b/utils/libmach/map.c
new file mode 100644
index 00000000..afb19b11
--- /dev/null
+++ b/utils/libmach/map.c
@@ -0,0 +1,203 @@
+/*
+ * file map routines
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+Map *
+newmap(Map *map, int n)
+{
+ int size;
+
+ size = sizeof(Map)+(n-1)*sizeof(struct segment);
+ if (map == 0)
+ map = malloc(size);
+ else
+ map = realloc(map, size);
+ if (map == 0) {
+ werrstr("out of memory: %r");
+ return 0;
+ }
+ memset(map, 0, size);
+ map->nsegs = n;
+ return map;
+}
+
+int
+setmap(Map *map, int fd, ulong b, ulong e, ulong f, char *name)
+{
+ int i;
+
+ if (map == 0)
+ return 0;
+ for (i = 0; i < map->nsegs; i++)
+ if (!map->seg[i].inuse)
+ break;
+ if (i >= map->nsegs)
+ return 0;
+ map->seg[i].b = b;
+ map->seg[i].e = e;
+ map->seg[i].f = f;
+ map->seg[i].inuse = 1;
+ map->seg[i].name = name;
+ map->seg[i].fd = fd;
+ return 1;
+}
+
+static ulong
+stacktop(int pid)
+{
+ char buf[64];
+ int fd;
+ int n;
+ char *cp;
+
+ sprint(buf, "/proc/%d/segment", pid);
+ fd = open(buf, 0);
+ if (fd < 0)
+ return 0;
+ n = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ buf[n] = 0;
+ if (strncmp(buf, "Stack", 5))
+ return 0;
+ for (cp = buf+5; *cp && *cp == ' '; cp++)
+ ;
+ if (!*cp)
+ return 0;
+ cp = strchr(cp, ' ');
+ if (!cp)
+ return 0;
+ while (*cp && *cp == ' ')
+ cp++;
+ if (!*cp)
+ return 0;
+ return strtoul(cp, 0, 16);
+}
+
+Map*
+attachproc(int pid, int kflag, int corefd, Fhdr *fp)
+{
+ char buf[64], *regs;
+ int fd;
+ Map *map;
+ ulong n;
+ int mode;
+
+ map = newmap(0, 4);
+ if (!map)
+ return 0;
+ if(kflag) {
+ regs = "kregs";
+ mode = OREAD;
+ } else {
+ regs = "regs";
+ mode = ORDWR;
+ }
+ if (mach->regsize) {
+ sprint(buf, "/proc/%d/%s", pid, regs);
+ fd = open(buf, mode);
+ if(fd < 0) {
+ free(map);
+ return 0;
+ }
+ setmap(map, fd, 0, mach->regsize, 0, "regs");
+ }
+ if (mach->fpregsize) {
+ sprint(buf, "/proc/%d/fpregs", pid);
+ fd = open(buf, mode);
+ if(fd < 0) {
+ close(map->seg[0].fd);
+ free(map);
+ return 0;
+ }
+ setmap(map, fd, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs");
+ }
+ setmap(map, corefd, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "text");
+ if(kflag || (ulong) fp->dataddr >= 0x7fffffff) {
+ setmap(map, corefd, fp->dataddr, 0xffffffff, fp->dataddr, "data");
+ return map;
+ }
+ n = stacktop(pid);
+ if (n == 0) {
+ setmap(map, corefd, fp->dataddr, 0x7fffffff, fp->dataddr, "data");
+ return map;
+ }
+ setmap(map, corefd, fp->dataddr, n, fp->dataddr, "data");
+ return map;
+}
+
+int
+findseg(Map *map, char *name)
+{
+ int i;
+
+ if (!map)
+ return -1;
+ for (i = 0; i < map->nsegs; i++)
+ if (map->seg[i].inuse && !strcmp(map->seg[i].name, name))
+ return i;
+ return -1;
+}
+
+void
+unusemap(Map *map, int i)
+{
+ if (map != 0 && 0 <= i && i < map->nsegs)
+ map->seg[i].inuse = 0;
+}
+
+Map*
+attachremt(int fd, Fhdr *f)
+{
+ Map *m;
+ ulong txt;
+
+ m = newmap(0, 3);
+ if (m == 0)
+ return 0;
+
+ /* Space for mach structures */
+ txt = f->txtaddr;
+ if(txt > 8*4096)
+ txt -= 8*4096;
+
+ setmap(m, fd, txt, f->txtaddr+f->txtsz, txt, "*text");
+ /*setmap(m, fd, f->dataddr, 0xffffffff, f->dataddr, "*data");*/ /* pc heap is < KTZERO */
+ setmap(m, fd, 4096, 0xffffffff, 4096, "*data");
+ setmap(m, fd, 0x0, mach->regsize, 0, "kreg");
+
+ return m;
+}
+
+Map*
+loadmap(Map *map, int fd, Fhdr *fp)
+{
+ map = newmap(map, 2);
+ if (map == 0)
+ return 0;
+
+ map->seg[0].b = fp->txtaddr;
+ map->seg[0].e = fp->txtaddr+fp->txtsz;
+ map->seg[0].f = fp->txtoff;
+ map->seg[0].fd = fd;
+ map->seg[0].inuse = 1;
+ map->seg[0].name = "text";
+ map->seg[1].b = fp->dataddr;
+ map->seg[1].e = fp->dataddr+fp->datsz;
+ map->seg[1].f = fp->datoff;
+ map->seg[1].fd = fd;
+ map->seg[1].inuse = 1;
+ map->seg[1].name = "data";
+ return map;
+}
+
+void
+setmapio(Map *map, int i, Rsegio get, Rsegio put)
+{
+ if (map != 0 && 0 <= i && i < map->nsegs) {
+ map->seg[i].mget = get;
+ map->seg[i].mput = put;
+ }
+}
diff --git a/utils/libmach/mkfile b/utils/libmach/mkfile
new file mode 100644
index 00000000..e2747136
--- /dev/null
+++ b/utils/libmach/mkfile
@@ -0,0 +1,46 @@
+<../../mkconfig
+
+LIB=libmach.a
+OFILES=\
+ 2.$O\
+ 4.$O\
+ 5.$O\
+ 6.$O\
+ 8.$O\
+ k.$O\
+ q.$O\
+ t.$O\
+ v.$O\
+ 2db.$O\
+ 4db.$O\
+ 5db.$O\
+ 8db.$O\
+ kdb.$O\
+ qdb.$O\
+ tdb.$O\
+ vdb.$O\
+ 2obj.$O\
+ 5obj.$O\
+ 6obj.$O\
+ 8obj.$O\
+ kobj.$O\
+ qobj.$O\
+ tobj.$O\
+ vobj.$O\
+ obj.$O\
+ map.$O\
+ swap.$O\
+ sym.$O\
+ access.$O\
+ machdata.$O\
+ setmach.$O\
+ executable.$O\
+ vcodas.$O\
+
+HFILES=mach.h a.out.h bootexec.h elf.h ureg2.h ureg4.h ureg6.h ureg8.h uregk.h uregv.h ureg5.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+CFLAGS= $CFLAGS -I..
+
+package:QV:
+ $TRUE
diff --git a/utils/libmach/obj.c b/utils/libmach/obj.c
new file mode 100644
index 00000000..39f2fad4
--- /dev/null
+++ b/utils/libmach/obj.c
@@ -0,0 +1,326 @@
+/*
+ * obj.c
+ * routines universal to all object files
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "ar.h"
+#include "mach.h"
+#include "obj.h"
+
+#define islocal(t) ((t)=='a' || (t)=='p')
+
+enum
+{
+ NNAMES = 50,
+ MAXIS = 8, /* max length to determine if a file is a .? file */
+ MAXOFF = 0x7fffffff, /* larger than any possible local offset */
+ NHASH = 1024, /* must be power of two */
+ HASHMUL = 79L,
+};
+
+int _is2(char*), /* in [$OS].c */
+ _is5(char*),
+ _is6(char*),
+ _is8(char*),
+ _is9(char*),
+ _isk(char*),
+ _isq(char*),
+ _ist(char*),
+ _isv(char*),
+ _isx(char*),
+ _read2(Biobuf*, Prog*),
+ _read5(Biobuf*, Prog*),
+ _read6(Biobuf*, Prog*),
+ _read8(Biobuf*, Prog*),
+ _read9(Biobuf*, Prog*),
+ _readk(Biobuf*, Prog*),
+ _readq(Biobuf*, Prog*),
+ _readt(Biobuf*, Prog*),
+ _readv(Biobuf*, Prog*),
+ _readx(Biobuf*, Prog*);
+
+typedef struct Obj Obj;
+typedef struct Symtab Symtab;
+
+struct Obj /* functions to handle each intermediate (.$O) file */
+{
+ char *name; /* name of each $O file */
+ int (*is)(char*); /* test for each type of $O file */
+ int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
+};
+
+static Obj obj[] =
+{ /* functions to identify and parse each type of obj */
+ /*[Obj68020]*/ "68020 .2", _is2, _read2,
+ /*[ObjSparc]*/ "sparc .k", _isk, _readk,
+ /*[ObjMips]*/ "mips .v", _isv, _readv,
+ /*[Obj386]*/ "386 .8", _is8, _read8,
+ /*[Obj960]*/ "960 .6", 0, 0,
+ /*[Obj3210]*/ "3210 .x", 0, 0,
+ /*[ObjMips2]*/ "mips2 .4", 0, 0,
+ /*[Obj29000]*/ "29000 .9", 0, 0,
+ /*[ObjArm]*/ "arm .5", _is5, _read5,
+ /*[ObjPower]*/ "power .q", _isq, _readq,
+ /*[ObjMips2le]*/ "mips2 .0", 0, 0,
+ /*[Maxobjtype]*/ 0, 0
+};
+
+struct Symtab
+{
+ struct Sym s;
+ struct Symtab *next;
+};
+
+static Symtab *hash[NHASH];
+static Sym *names[NNAMES]; /* working set of active names */
+
+static int processprog(Prog*,int); /* decode each symbol reference */
+static void objreset(void);
+static void objlookup(int, char *, int );
+static void objupdate(int, int);
+
+int
+objtype(Biobuf *bp, char **name)
+{
+ int i;
+ char buf[MAXIS];
+
+ if(Bread(bp, buf, MAXIS) < MAXIS)
+ return -1;
+ Bseek(bp, -MAXIS, 1);
+ for (i = 0; i < Maxobjtype; i++) {
+ if (obj[i].is && (*obj[i].is)(buf)) {
+ if (name)
+ *name = obj[i].name;
+ return i;
+ }
+ }
+ return -1;
+}
+
+int
+isar(Biobuf *bp)
+{
+ int n;
+ char magbuf[SARMAG];
+
+ n = Bread(bp, magbuf, SARMAG);
+ if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * determine what kind of object file this is and process it.
+ * return whether or not this was a recognized intermediate file.
+ */
+int
+readobj(Biobuf *bp, int objtype)
+{
+ Prog p;
+
+ if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+ return 1;
+ objreset();
+ while ((*obj[objtype].read)(bp, &p))
+ if (!processprog(&p, 1))
+ return 0;
+ return 1;
+}
+
+int
+readar(Biobuf *bp, int objtype, int end, int doautos)
+{
+ Prog p;
+
+ if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+ return 1;
+ objreset();
+ while ((*obj[objtype].read)(bp, &p) && BOFFSET(bp) < end)
+ if (!processprog(&p, doautos))
+ return 0;
+ return 1;
+}
+
+/*
+ * decode a symbol reference or definition
+ */
+static int
+processprog(Prog *p, int doautos)
+{
+ if(p->kind == aNone)
+ return 1;
+ if(p->sym < 0 || p->sym >= NNAMES)
+ return 0;
+ switch(p->kind)
+ {
+ case aName:
+ if (!doautos)
+ if(p->type != 'U' && p->type != 'b')
+ break;
+ objlookup(p->sym, p->id, p->type);
+ break;
+ case aText:
+ objupdate(p->sym, 'T');
+ break;
+ case aData:
+ objupdate(p->sym, 'D');
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/*
+ * find the entry for s in the symbol array.
+ * make a new entry if it is not already there.
+ */
+static void
+objlookup(int id, char *name, int type)
+{
+ long h;
+ char *cp;
+ Sym *s;
+ Symtab *sp;
+
+ s = names[id];
+ if(s && strcmp(s->name, name) == 0) {
+ s->type = type;
+ return;
+ }
+
+ h = *name;
+ for(cp = name+1; *cp; h += *cp++)
+ h *= HASHMUL;
+ if(h < 0)
+ h = ~h;
+ h &= (NHASH-1);
+ if (type == 'U' || type == 'b' || islocal(type)) {
+ for(sp = hash[h]; sp; sp = sp->next)
+ if(strcmp(sp->s.name, name) == 0) {
+ switch(sp->s.type) {
+ case 'T':
+ case 'D':
+ case 'U':
+ if (type == 'U') {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ case 't':
+ case 'd':
+ case 'b':
+ if (type == 'b') {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ case 'a':
+ case 'p':
+ if (islocal(type)) {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ sp = malloc(sizeof(Symtab));
+ sp->s.name = name;
+ sp->s.type = type;
+ sp->s.value = islocal(type) ? MAXOFF : 0;
+ names[id] = &sp->s;
+ sp->next = hash[h];
+ hash[h] = sp;
+ return;
+}
+/*
+ * traverse the symbol lists
+ */
+void
+objtraverse(void (*fn)(Sym*, void*), void *pointer)
+{
+ int i;
+ Symtab *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s; s = s->next)
+ (*fn)(&s->s, pointer);
+}
+
+/*
+ * update the offset information for a 'a' or 'p' symbol in an intermediate file
+ */
+void
+_offset(int id, long off)
+{
+ Sym *s;
+
+ s = names[id];
+ if (s && s->name[0] && islocal(s->type) && s->value > off)
+ s->value = off;
+}
+
+/*
+ * update the type of a global text or data symbol
+ */
+static void
+objupdate(int id, int type)
+{
+ Sym *s;
+
+ s = names[id];
+ if (s && s->name[0])
+ if (s->type == 'U')
+ s->type = type;
+ else if (s->type == 'b')
+ s->type = tolower(type);
+}
+
+/*
+ * look for the next file in an archive
+ */
+int
+nextar(Biobuf *bp, int offset, char *buf)
+{
+ struct ar_hdr a;
+ int i, r;
+ long arsize;
+
+ if (offset&01)
+ offset++;
+ Bseek(bp, offset, 0);
+ r = Bread(bp, &a, SAR_HDR);
+ if(r != SAR_HDR)
+ return 0;
+ if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
+ return -1;
+ for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
+ buf[i] = a.name[i];
+ buf[i] = 0;
+ arsize = atol(a.size);
+ if (arsize&1)
+ arsize++;
+ return arsize + SAR_HDR;
+}
+
+static void
+objreset(void)
+{
+ int i;
+ Symtab *s, *n;
+
+ for(i = 0; i < NHASH; i++) {
+ for(s = hash[i]; s; s = n) {
+ n = s->next;
+ free(s->s.name);
+ free(s);
+ }
+ hash[i] = 0;
+ }
+ memset(names, 0, sizeof names);
+}
diff --git a/utils/libmach/obj.h b/utils/libmach/obj.h
new file mode 100644
index 00000000..2d2dfea6
--- /dev/null
+++ b/utils/libmach/obj.h
@@ -0,0 +1,24 @@
+/*
+ * obj.h -- defs for dealing with object files
+ */
+
+typedef enum Kind /* variable defs and references in obj */
+{
+ aNone, /* we don't care about this prog */
+ aName, /* introduces a name */
+ aText, /* starts a function */
+ aData, /* references to a global object */
+} Kind;
+
+typedef struct Prog Prog;
+
+struct Prog /* info from .$O files */
+{
+ Kind kind; /* what kind of symbol */
+ char type; /* type of the symbol: ie, 'T', 'a', etc. */
+ char sym; /* index of symbol's name */
+ char *id; /* name for the symbol, if it introduces one */
+};
+
+#define UNKNOWN '?'
+void _offset(int, long);
diff --git a/utils/libmach/q.c b/utils/libmach/q.c
new file mode 100644
index 00000000..858882bf
--- /dev/null
+++ b/utils/libmach/q.c
@@ -0,0 +1,122 @@
+/*
+ * PowerPC definition
+ * forsyth@terzarima.net
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "uregq.h"
+#include "mach.h"
+
+
+#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x)
+
+#define SP REGOFF(sp)
+#define PC REGOFF(pc)
+#define R3 REGOFF(r3) /* return reg */
+#define LR REGOFF(lr)
+#define R31 REGOFF(r31)
+#define FP_REG(x) (R31+4+8*(x))
+
+#define REGSIZE sizeof(struct Ureg)
+#define FPREGSIZE (8*33)
+
+Reglist powerreglist[] = {
+ {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'},
+ {"SRR1", REGOFF(status), RINT|RRDONLY, 'X'},
+ {"PC", REGOFF(pc), RINT, 'X'},
+ {"LR", REGOFF(lr), RINT, 'X'},
+ {"CR", REGOFF(cr), RINT, 'X'},
+ {"XER", REGOFF(xer), RINT, 'X'},
+ {"CTR", REGOFF(ctr), RINT, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"R0", REGOFF(r0), RINT, 'X'},
+ /* R1 is SP */
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R15", REGOFF(r15), RINT, 'X'},
+ {"R16", REGOFF(r16), RINT, 'X'},
+ {"R17", REGOFF(r17), RINT, 'X'},
+ {"R18", REGOFF(r18), RINT, 'X'},
+ {"R19", REGOFF(r19), RINT, 'X'},
+ {"R20", REGOFF(r20), RINT, 'X'},
+ {"R21", REGOFF(r21), RINT, 'X'},
+ {"R22", REGOFF(r22), RINT, 'X'},
+ {"R23", REGOFF(r23), RINT, 'X'},
+ {"R24", REGOFF(r24), RINT, 'X'},
+ {"R25", REGOFF(r25), RINT, 'X'},
+ {"R26", REGOFF(r26), RINT, 'X'},
+ {"R27", REGOFF(r27), RINT, 'X'},
+ {"R28", REGOFF(r28), RINT, 'X'},
+ {"R29", REGOFF(r29), RINT, 'X'},
+ {"R30", REGOFF(r30), RINT, 'X'},
+ {"R31", REGOFF(r31), RINT, 'X'},
+ {"F0", FP_REG(0), RFLT, 'D'},
+ {"F1", FP_REG(1), RFLT, 'D'},
+ {"F2", FP_REG(2), RFLT, 'D'},
+ {"F3", FP_REG(3), RFLT, 'D'},
+ {"F4", FP_REG(4), RFLT, 'D'},
+ {"F5", FP_REG(5), RFLT, 'D'},
+ {"F6", FP_REG(6), RFLT, 'D'},
+ {"F7", FP_REG(7), RFLT, 'D'},
+ {"F8", FP_REG(8), RFLT, 'D'},
+ {"F9", FP_REG(9), RFLT, 'D'},
+ {"F10", FP_REG(10), RFLT, 'D'},
+ {"F11", FP_REG(11), RFLT, 'D'},
+ {"F12", FP_REG(12), RFLT, 'D'},
+ {"F13", FP_REG(13), RFLT, 'D'},
+ {"F14", FP_REG(14), RFLT, 'D'},
+ {"F15", FP_REG(15), RFLT, 'D'},
+ {"F16", FP_REG(16), RFLT, 'D'},
+ {"F17", FP_REG(17), RFLT, 'D'},
+ {"F18", FP_REG(18), RFLT, 'D'},
+ {"F19", FP_REG(19), RFLT, 'D'},
+ {"F20", FP_REG(20), RFLT, 'D'},
+ {"F21", FP_REG(21), RFLT, 'D'},
+ {"F22", FP_REG(22), RFLT, 'D'},
+ {"F23", FP_REG(23), RFLT, 'D'},
+ {"F24", FP_REG(24), RFLT, 'D'},
+ {"F25", FP_REG(25), RFLT, 'D'},
+ {"F26", FP_REG(26), RFLT, 'D'},
+ {"F27", FP_REG(27), RFLT, 'D'},
+ {"F28", FP_REG(28), RFLT, 'D'},
+ {"F29", FP_REG(29), RFLT, 'D'},
+ {"F30", FP_REG(30), RFLT, 'D'},
+ {"F31", FP_REG(31), RFLT, 'D'},
+ {"FPSCR", FP_REG(32)+4, RFLT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mpower =
+{
+ "power",
+ MPOWER, /* machine type */
+ powerreglist, /* register set */
+ REGSIZE, /* register set size in bytes */
+ FPREGSIZE, /* floating point register size in bytes */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "LR", /* name of link register */
+ "setSB", /* static base register name */
+ 0, /* value */
+ 0x1000, /* page size */
+ 0x20000000, /* kernel base */
+ 0, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/qdb.c b/utils/libmach/qdb.c
new file mode 100644
index 00000000..f2aa682a
--- /dev/null
+++ b/utils/libmach/qdb.c
@@ -0,0 +1,1270 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+/*
+ * PowerPC-specific debugger interface
+ * forsyth@terzarima.net
+ */
+
+static char *powerexcep(Map*, Rgetter);
+static int powerfoll(Map*, ulong, Rgetter, ulong*);
+static int powerinst(Map*, ulong, char, char*, int);
+static int powerinstlen(Map*, ulong);
+static int powerdas(Map*, ulong, char*, int);
+
+/*
+ * Machine description
+ */
+Machdata powermach =
+{
+ {0x07f, 0xe0, 0x00, 0x08}, /* breakpoint (tw 31,r0,r0) */
+ 4, /* break point size */
+
+ beswab, /* convert short to local byte order */
+ beswal, /* convert long to local byte order */
+ beswav, /* vlong to local byte order */
+ risctrace, /* print C traceback */
+ riscframe, /* frame finder */
+ powerexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ beieeesftos, /* single precision float printer */
+ beieeedftos, /* double precisioin float printer */
+ powerfoll, /* following addresses */
+ powerinst, /* print instruction */
+ powerdas, /* dissembler */
+ powerinstlen, /* instruction size */
+};
+
+static char *excname[] =
+{
+ "reserved 0",
+ "system reset",
+ "machine check",
+ "data access",
+ "instruction access",
+ "external interrupt",
+ "alignment",
+ "program exception",
+ "floating-point unavailable",
+ "decrementer",
+ "i/o controller interface error",
+ "reserved B",
+ "system call",
+ "trace trap",
+ "floating point assist",
+ "reserved",
+ "ITLB miss",
+ "DTLB load miss",
+ "DTLB store miss",
+ "instruction address breakpoint"
+ "SMI interrupt"
+ "reserved 15",
+ "reserved 16",
+ "reserved 17",
+ "reserved 18",
+ "reserved 19",
+ "reserved 1A",
+ /* the following are made up on a program exception */
+ "floating point exception", /* 1B: FPEXC */
+ "illegal instruction", /* 1C */
+ "privileged instruction", /* 1D */
+ "trap", /* 1E */
+ "illegal operation", /* 1F */
+ "breakpoint", /* 20 */
+};
+
+static char*
+powerexcep(Map *map, Rgetter rget)
+{
+ long c;
+ static char buf[32];
+
+ c = (*rget)(map, "CAUSE") >> 8;
+ if(c < nelem(excname))
+ return excname[c];
+ sprint(buf, "unknown trap #%lx", c);
+ return buf;
+}
+
+/*
+ * disassemble PowerPC opcodes
+ */
+
+#define REGSP 1 /* should come from q.out.h, but there's a clash */
+#define REGSB 2
+
+static char FRAMENAME[] = ".frame";
+
+static Map *mymap;
+
+/*
+ * ibm conventions for these: bit 0 is top bit
+ * from table 10-1
+ */
+typedef struct {
+ uchar aa; /* bit 30 */
+ uchar crba; /* bits 11-15 */
+ uchar crbb; /* bits 16-20 */
+ long bd; /* bits 16-29 */
+ uchar crfd; /* bits 6-8 */
+ uchar crfs; /* bits 11-13 */
+ uchar bi; /* bits 11-15 */
+ uchar bo; /* bits 6-10 */
+ uchar crbd; /* bits 6-10 */
+ /*union {*/
+ short d; /* bits 16-31 */
+ short simm;
+ ushort uimm;
+ /*};*/
+ uchar fm; /* bits 7-14 */
+ uchar fra; /* bits 11-15 */
+ uchar frb; /* bits 16-20 */
+ uchar frc; /* bits 21-25 */
+ uchar frs; /* bits 6-10 */
+ uchar frd; /* bits 6-10 */
+ uchar crm; /* bits 12-19 */
+ long li; /* bits 6-29 || b'00' */
+ uchar lk; /* bit 31 */
+ uchar mb; /* bits 21-25 */
+ uchar me; /* bits 26-30 */
+ uchar nb; /* bits 16-20 */
+ uchar op; /* bits 0-5 */
+ uchar oe; /* bit 21 */
+ uchar ra; /* bits 11-15 */
+ uchar rb; /* bits 16-20 */
+ uchar rc; /* bit 31 */
+ /* union {*/
+ uchar rs; /* bits 6-10 */
+ uchar rd;
+ /*};*/
+ uchar sh; /* bits 16-20 */
+ ushort spr; /* bits 11-20 */
+ uchar to; /* bits 6-10 */
+ uchar imm; /* bits 16-19 */
+ ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */
+ long immediate;
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ short target;
+ char *curr; /* current fill level in output buffer */
+ char *end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char *err; /* errmsg */
+} Instr;
+
+#define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
+#define IB(v,b) IBF((v),(b),(b))
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+ long w;
+
+ if (get4(mymap, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->aa = IB(w, 30);
+ i->crba = IBF(w, 11, 15);
+ i->crbb = IBF(w, 16, 20);
+ i->bd = IBF(w, 16, 29)<<2;
+ if(i->bd & 0x8000)
+ i->bd |= ~0L<<16;
+ i->crfd = IBF(w, 6, 8);
+ i->crfs = IBF(w, 11, 13);
+ i->bi = IBF(w, 11, 15);
+ i->bo = IBF(w, 6, 10);
+ i->crbd = IBF(w, 6, 10);
+ i->uimm = IBF(w, 16, 31); /* also d, simm */
+ i->simm = i->uimm;
+ i->d = i->uimm;
+ i->fm = IBF(w, 7, 14);
+ i->fra = IBF(w, 11, 15);
+ i->frb = IBF(w, 16, 20);
+ i->frc = IBF(w, 21, 25);
+ i->frs = IBF(w, 6, 10);
+ i->frd = IBF(w, 6, 10);
+ i->crm = IBF(w, 12, 19);
+ i->li = IBF(w, 6, 29)<<2;
+ if(IB(w, 6))
+ i->li |= ~0<<25;
+ i->lk = IB(w, 31);
+ i->mb = IBF(w, 21, 25);
+ i->me = IBF(w, 26, 30);
+ i->nb = IBF(w, 16, 20);
+ i->op = IBF(w, 0, 5);
+ i->oe = IB(w, 21);
+ i->ra = IBF(w, 11, 15);
+ i->rb = IBF(w, 16, 20);
+ i->rc = IB(w, 31);
+ i->rs = IBF(w, 6, 10); /* also rd */
+ i->rd = i->rs;
+ i->sh = IBF(w, 16, 20);
+ i->spr = IBF(w, 11, 20);
+ i->to = IBF(w, 6, 10);
+ i->imm = IBF(w, 16, 19);
+ i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */
+ i->immediate = i->simm;
+ if(i->op == 15)
+ i->immediate <<= 16;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong pc, Instr *i)
+{
+ Instr x;
+
+ if(decode(pc, i) < 0)
+ return -1;
+ /*
+ * combine ADDIS/ORI (CAU/ORIL) into MOVW
+ */
+ if (i->op == 15 && i->ra==0) {
+ if(decode(pc+4, &x) < 0)
+ return -1;
+ if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
+ i->immediate |= (x.immediate & 0xFFFF);
+ i->w1 = x.w0;
+ i->target = x.rd;
+ i->size++;
+ return 1;
+ }
+ }
+ if (i->op == 15 && i->ra==REGSB && mach->sb) {
+ if(decode(pc+4, &x) < 0)
+ return -1;
+ if (x.op >= 32 && x.op < 54 && i->rd == x.ra) {
+ i->op = x.op;
+ i->ra = REGSB;
+ i->rs = i->rd = x.rd;
+ i->immediate += x.simm;
+ i->w1 = x.w0;
+ i->target = x.rd;
+ i->size++;
+ return 1;
+ }
+ }
+ return 1;
+}
+
+static int
+plocal(Instr *i)
+{
+ int offset;
+ Symbol s;
+
+ if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
+ return -1;
+ offset = s.value - i->immediate;
+ if (offset > 0) {
+ if(getauto(&s, offset, CAUTO, &s)) {
+ bprint(i, "%s+%d(SP)", s.name, s.value);
+ return 1;
+ }
+ } else {
+ if (getauto(&s, -offset-4, CPARAM, &s)) {
+ bprint(i, "%s+%d(FP)", s.name, -offset);
+ return 1;
+ }
+ }
+ return -1;
+}
+
+static int
+pglobal(Instr *i, long off, int anyoff, char *reg)
+{
+ Symbol s, s2;
+ long off1;
+
+ if(findsym(off, CANY, &s) &&
+ strcmp(s.name, ".string") != 0 &&
+ (ulong)(off-s.value) < 4096 &&
+ (s.class == CDATA || s.class == CTEXT)) {
+ if(off==s.value && s.name[0]=='$'){
+ off1 = 0;
+ get4(mymap, s.value, &off1);
+ if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
+ bprint(i, "$%s%s", s2.name, reg);
+ return 1;
+ }
+ }
+ bprint(i, "%s", s.name);
+ if (s.value != off)
+ bprint(i, "+%lux", off-s.value);
+ bprint(i, reg);
+ return 1;
+ }
+ if(!anyoff)
+ return 0;
+ bprint(i, "%lux%s", off, reg);
+ return 1;
+}
+
+static void
+address(Instr *i)
+{
+ if (i->ra == REGSP && plocal(i) >= 0)
+ return;
+ if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") > 0)
+ return;
+ if(i->immediate < 0)
+ bprint(i, "-%lx", -i->immediate);
+ else
+ bprint(i, "%lux", i->immediate);
+ if (i->ra == REGSB && mach->sb)
+ bprint(i, "(SB)");
+ else
+ bprint(i, "(R%d)", i->ra);
+}
+
+static char *tcrbits[] = {"LT", "GT", "EQ", "VS"};
+static char *fcrbits[] = {"GE", "LE", "NE", "VC"};
+
+typedef struct Opcode Opcode;
+
+struct Opcode {
+ uchar op;
+ ushort xo;
+ ushort xomask;
+ char *mnemonic;
+ void (*f)(Opcode *, Instr *);
+ char *ken;
+ int flags;
+};
+
+static void format(char *, Instr *, char *);
+
+static void
+branch(Opcode *o, Instr *i)
+{
+ char buf[8];
+ int bo, bi;
+
+ bo = i->bo & ~1; /* ignore prediction bit */
+ if(bo==4 || bo==12 || bo==20) { /* simple forms */
+ if(bo != 20) {
+ bi = i->bi&3;
+ sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
+ format(buf, i, 0);
+ bprint(i, "\t");
+ if(i->bi > 4)
+ bprint(i, "CR(%d),", i->bi/4);
+ } else
+ format("BR%L\t", i, 0);
+ if(i->op == 16)
+ format(0, i, "%J");
+ else if(i->op == 19 && i->xo == 528)
+ format(0, i, "(CTR)");
+ else if(i->op == 19 && i->xo == 16)
+ format(0, i, "(LR)");
+ } else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+addi(Opcode *o, Instr *i)
+{
+ if (i->op==14 && i->ra == 0)
+ format("MOVW", i, "%i,R%d");
+ else if (i->ra == REGSP || i->ra == REGSB) {
+ bprint(i, "MOVW\t$");
+ address(i);
+ bprint(i, ",R%d", i->rd);
+ } else if(i->op==14 && i->simm < 0) {
+ bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else if(i->ra == i->rd) {
+ format(o->mnemonic, i, "%i");
+ bprint(i, ",R%d", i->rd);
+ } else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+addis(Opcode *o, Instr *i)
+{
+ long v;
+
+ v = i->immediate;
+ if (i->op==15 && i->ra == 0) {
+ bprint(i, "MOVW\t$");
+ pglobal(i, i->immediate, 1, "");
+ bprint(i, ",R%d", i->rd);
+ }
+ else if (i->op==15 && i->ra == REGSB && mach->sb) {
+ bprint(i, "MOVW\t$");
+ address(i);
+ bprint(i, ",R%d", i->rd);
+/* how about auto/param addresses? */
+ } else if(i->op==15 && v < 0) {
+ bprint(i, "SUB\t$%d,R%d", -v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else {
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t$%ld,R%d", v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ }
+}
+
+static void
+andi(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "%I,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+gencc(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+gen(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, o->ken);
+ if (i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+ldx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b),R%d");
+ else
+ format(o->mnemonic, i, "(R%b+R%a),R%d");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+stx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "R%d,(R%b)");
+ else
+ format(o->mnemonic, i, "R%d,(R%b+R%a)");
+ if(i->rc && i->xo != 150)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+fldx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b),F%d");
+ else
+ format(o->mnemonic, i, "(R%b+R%a),F%d");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+fstx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "F%d,(R%b)");
+ else
+ format(o->mnemonic, i, "F%d,(R%b+R%a)");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+dcb(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b)");
+ else
+ format(o->mnemonic, i, "(R%b+R%a)");
+ if(i->rd)
+ bprint(i, " [illegal Rd]");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+lw(Opcode *o, Instr *i, char r)
+{
+ bprint(i, "%s\t", o->mnemonic);
+ address(i);
+ bprint(i, ",%c%d", r, i->rd);
+}
+
+static void
+load(Opcode *o, Instr *i)
+{
+ lw(o, i, 'R');
+}
+
+static void
+fload(Opcode *o, Instr *i)
+{
+ lw(o, i, 'F');
+}
+
+static void
+sw(Opcode *o, Instr *i, char r)
+{
+ int offset;
+ char *m;
+ Symbol s;
+
+ m = o->mnemonic;
+ if (i->ra == REGSP) {
+ if (findsym(i->addr, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) {
+ offset = s.value-i->immediate;
+ if (offset > 0 && getauto(&s, offset, CAUTO, &s)) {
+ bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rs,
+ s.name, offset);
+ return;
+ }
+ }
+ }
+ if (i->ra == REGSP || i->ra == REGSB && mach->sb) {
+ bprint(i, "%s\t%c%d,", m, r, i->rs);
+ address(i);
+ return;
+ }
+ if (r == 'F')
+ format(m, i, "F%d,%l");
+ else
+ format(m, i, o->ken);
+}
+
+static void
+store(Opcode *o, Instr *i)
+{
+ sw(o, i, 'R');
+}
+
+static void
+fstore(Opcode *o, Instr *i)
+{
+ sw(o, i, 'F');
+}
+
+static void
+shifti(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "$%k,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+shift(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "R%b,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+add(Opcode *o, Instr *i)
+{
+ if (i->rd == i->ra)
+ format(o->mnemonic, i, "R%b,R%d");
+ else if (i->rd == i->rb)
+ format(o->mnemonic, i, "R%a,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+sub(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ if(i->op == 31) {
+ bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */
+ if(i->rd != i->rb)
+ bprint(i, ",R%d", i->rd);
+ } else
+ bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
+}
+
+static void
+qdiv(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ if(i->op == 31)
+ bprint(i, "\tR%d,R%d", i->rb, i->ra);
+ else
+ bprint(i, "\t$%d,R%d", i->simm, i->ra);
+ if(i->ra != i->rd)
+ bprint(i, ",R%d", i->rd);
+}
+
+static void
+and(Opcode *o, Instr *i)
+{
+ if (i->op == 31) {
+ /* Rb,Rs,Ra */
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "R%b,R%a");
+ else if (i->ra == i->rb)
+ format(o->mnemonic, i, "R%s,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+ } else {
+ /* imm,Rs,Ra */
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "%I,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+ }
+}
+
+static void
+or(Opcode *o, Instr *i)
+{
+ if (i->op == 31) {
+ /* Rb,Rs,Ra */
+ if (i->rs == 0 && i->ra == 0 && i->rb == 0)
+ format("NOP", i, 0);
+ else if (i->rs == i->rb)
+ format("MOVW", i, "R%b,R%a");
+ else
+ and(o, i);
+ } else
+ and(o, i);
+}
+
+static void
+shifted(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
+ if (i->rs == i->ra)
+ bprint(i, "R%d", i->ra);
+ else
+ bprint(i, "R%d,R%d", i->rs, i->ra);
+}
+
+static void
+neg(Opcode *o, Instr *i)
+{
+ if (i->rd == i->ra)
+ format(o->mnemonic, i, "R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static char ir2[] = "R%a,R%d"; /* reverse of IBM order */
+static char ir3[] = "R%b,R%a,R%d";
+static char ir3r[] = "R%a,R%b,R%d";
+static char il3[] = "R%b,R%s,R%a";
+static char il2u[] = "%I,R%s,R%a";
+static char il3s[] = "$%k,R%s,R%a";
+static char il2[] = "R%s,R%a";
+static char icmp3[] = "R%a,R%b,%D";
+static char cr3op[] = "%b,%a,%d";
+static char ir2i[] = "%i,R%a,R%d";
+static char fp2[] = "F%b,F%d";
+static char fp3[] = "F%b,F%a,F%d";
+static char fp3c[] = "F%c,F%a,F%d";
+static char fp4[] = "F%a,F%c,F%b,F%d";
+static char fpcmp[] = "F%a,F%b,%D";
+static char ldop[] = "%l,R%d";
+static char stop[] = "R%d,%l";
+static char fldop[] = "%l,F%d";
+static char fstop[] = "F%d,%l";
+static char rlim[] = "R%b,R%s,$%z,R%a";
+static char rlimi[] = "$%k,R%s,$%z,R%a";
+
+#define OEM IBF(~0,22,30)
+#define FP4 IBF(~0,26,30)
+#define ALL ((ushort)~0)
+/*
+notes:
+ 10-26: crfD = rD>>2; rD&3 mbz
+ also, L bit (bit 10) mbz or selects 64-bit operands
+*/
+
+static Opcode opcodes[] = {
+ {31, 360, OEM, "ABS%V%C", 0, ir2}, /* POWER */
+
+ {31, 266, OEM, "ADD%V%C", add, ir3},
+ {31, 10, OEM, "ADDC%V%C", add, ir3},
+ {31, 138, OEM, "ADDE%V%C", add, ir3},
+ {14, 0, 0, "ADD", addi, ir2i},
+ {12, 0, 0, "ADDC", addi, ir2i},
+ {13, 0, 0, "ADDCCC", addi, ir2i},
+ {15, 0, 0, "ADD", addis, 0},
+ {31, 234, OEM, "ADDME%V%C", gencc, ir2},
+ {31, 202, OEM, "ADDZE%V%C", gencc, ir2},
+
+ {31, 28, ALL, "AND%C", and, il3},
+ {31, 60, ALL, "ANDN%C", and, il3},
+ {28, 0, 0, "ANDCC", andi, il2u},
+ {29, 0, 0, "ANDCC", shifted, 0},
+
+ {18, 0, 0, "B%L", gencc, "%j"},
+ {16, 0, 0, "BC%L", branch, "%d,%a,%J"},
+ {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"},
+ {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"},
+
+ {31, 531, ALL, "CLCS", gen, ir2}, /* POWER */
+
+ {31, 0, ALL, "CMP", 0, icmp3},
+ {11, 0, 0, "CMP", 0, "R%a,%i,%D"},
+ {31, 32, ALL, "CMPU", 0, icmp3},
+ {10, 0, 0, "CMPU", 0, "R%a,%I,%D"},
+
+ {31, 26, ALL, "CNTLZ%C", gencc, ir2},
+
+ {19, 257, ALL, "CRAND", gen, cr3op},
+ {19, 129, ALL, "CRANDN", gen, cr3op},
+ {19, 289, ALL, "CREQV", gen, cr3op},
+ {19, 225, ALL, "CRNAND", gen, cr3op},
+ {19, 33, ALL, "CRNOR", gen, cr3op},
+ {19, 449, ALL, "CROR", gen, cr3op},
+ {19, 417, ALL, "CRORN", gen, cr3op},
+ {19, 193, ALL, "CRXOR", gen, cr3op},
+
+ {31, 86, ALL, "DCBF", dcb, 0},
+ {31, 470, ALL, "DCBI", dcb, 0},
+ {31, 54, ALL, "DCBST", dcb, 0},
+ {31, 278, ALL, "DCBT", dcb, 0},
+ {31, 246, ALL, "DCBTST", dcb, 0},
+ {31, 1014, ALL, "DCBZ", dcb, 0},
+
+ {31, 331, OEM, "DIV%V%C", qdiv, ir3}, /* POWER */
+ {31, 363, OEM, "DIVS%V%C", qdiv, ir3}, /* POWER */
+ {31, 491, OEM, "DIVW%V%C", qdiv, ir3},
+ {31, 459, OEM, "DIVWU%V%C", qdiv, ir3},
+
+ {31, 264, OEM, "DOZ%V%C", gencc, ir3r}, /* POWER */
+ {9, 0, 0, "DOZ", gen, ir2i}, /* POWER */
+
+ {31, 310, ALL, "ECIWX", ldx, 0},
+ {31, 438, ALL, "ECOWX", stx, 0},
+ {31, 854, ALL, "EIEIO", gen, 0},
+
+ {31, 284, ALL, "EQV%C", gencc, il3},
+
+ {31, 954, ALL, "EXTSB%C", gencc, il2},
+ {31, 922, ALL, "EXTSH%C", gencc, il2},
+
+ {63, 264, ALL, "FABS%C", gencc, fp2},
+ {63, 21, ALL, "FADD%C", gencc, fp3},
+ {59, 21, ALL, "FADDS%C", gencc, fp3},
+ {63, 32, ALL, "FCMPO", gen, fpcmp},
+ {63, 0, ALL, "FCMPU", gen, fpcmp},
+ {63, 14, ALL, "FCTIW%C", gencc, fp2},
+ {63, 15, ALL, "FCTIWZ%C", gencc, fp2},
+ {63, 18, ALL, "FDIV%C", gencc, fp3},
+ {59, 18, ALL, "FDIVS%C", gencc, fp3},
+ {63, 29, FP4, "FMADD%C", gencc, fp4},
+ {59, 29, FP4, "FMADDS%C", gencc, fp4},
+ {63, 72, ALL, "FMOVD%C", gencc, fp2},
+ {63, 28, FP4, "FMSUB%C", gencc, fp4},
+ {59, 28, FP4, "FMSUBS%C", gencc, fp4},
+ {63, 25, FP4, "FMUL%C", gencc, fp3c},
+ {59, 25, FP4, "FMULS%C", gencc, fp3c},
+ {63, 136, ALL, "FNABS%C", gencc, fp2},
+ {63, 40, ALL, "FNEG%C", gencc, fp2},
+ {63, 31, FP4, "FNMADD%C", gencc, fp4},
+ {59, 31, FP4, "FNMADDS%C", gencc, fp4},
+ {63, 30, FP4, "FNMSUB%C", gencc, fp4},
+ {59, 30, FP4, "FNMSUBS%C", gencc, fp4},
+ {63, 12, ALL, "FRSP%C", gencc, fp2},
+ {63, 20, FP4, "FSUB%C", gencc, fp3},
+ {59, 20, FP4, "FSUBS%C", gencc, fp3},
+
+ {31, 982, ALL, "ICBI", dcb, 0},
+ {19, 150, ALL, "ISYNC", gen, 0},
+
+ {34, 0, 0, "MOVBZ", load, ldop},
+ {35, 0, 0, "MOVBZU", load, ldop},
+ {31, 119, ALL, "MOVBZU", ldx, 0},
+ {31, 87, ALL, "MOVBZ", ldx, 0},
+ {50, 0, 0, "FMOVD", fload, fldop},
+ {51, 0, 0, "FMOVDU", fload, fldop},
+ {31, 631, ALL, "FMOVDU", fldx, 0},
+ {31, 599, ALL, "FMOVD", fldx, 0},
+ {48, 0, 0, "FMOVS", load, fldop},
+ {49, 0, 0, "FMOVSU", load, fldop},
+ {31, 567, ALL, "FMOVSU", fldx, 0},
+ {31, 535, ALL, "FMOVS", fldx, 0},
+ {42, 0, 0, "MOVH", load, ldop},
+ {43, 0, 0, "MOVHU", load, ldop},
+ {31, 375, ALL, "MOVHU", ldx, 0},
+ {31, 343, ALL, "MOVH", ldx, 0},
+ {31, 790, ALL, "MOVHBR", ldx, 0},
+ {40, 0, 0, "MOVHZ", load, ldop},
+ {41, 0, 0, "MOVHZU", load, ldop},
+ {31, 311, ALL, "MOVHZU", ldx, 0},
+ {31, 279, ALL, "MOVHZ", ldx, 0},
+ {46, 0, 0, "MOVMW", load, ldop},
+ {31, 277, ALL, "LSCBX%C", ldx, 0}, /* POWER */
+ {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"},
+ {31, 533, ALL, "LSW", ldx, 0},
+ {31, 20, ALL, "LWAR", ldx, 0},
+ {31, 534, ALL, "MOVWBR", ldx, 0},
+ {32, 0, 0, "MOVW", load, ldop},
+ {33, 0, 0, "MOVWU", load, ldop},
+ {31, 55, ALL, "MOVWU", ldx, 0},
+ {31, 23, ALL, "MOVW", ldx, 0},
+
+ {31, 29, ALL, "MASKG%C", gencc, "R%s:R%b,R%d"}, /* POWER */
+ {31, 541, ALL, "MASKIR%C", gencc, "R%s,R%b,R%a"}, /* POWER */
+
+ {19, 0, ALL, "MOVFL", gen, "%S,%D"},
+ {63, 64, ALL, "MOVCRFS", gen, "%S,%D"},
+ {31, 512, ALL, "MOVW", gen, "XER,%D"},
+ {31, 19, ALL, "MOVW", gen, "CR,R%d"},
+
+ {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */
+ {31, 83, ALL, "MOVW", gen, "MSR,R%d"},
+ {31, 339, ALL, "MOVW", gen, "%P,R%d"},
+ {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"},
+ {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"},
+ {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"},
+ {63, 70, ALL, "MTFSB0%C", gencc, "%D"},
+ {63, 38, ALL, "MTFSB1%C", gencc, "%D"},
+ {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */
+ {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"},
+ {31, 146, ALL, "MOVW", gen, "R%s,MSR"},
+ {31, 467, ALL, "MOVW", gen, "R%s,%P"},
+ {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"},
+ {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"},
+
+ {31, 107, OEM, "MUL%V%C", gencc, ir3}, /* POWER */
+ {31, 75, ALL, "MULHW%C", gencc, ir3}, /* POWER */
+ {31, 11, ALL, "MULHWU%C", gencc, ir3}, /* POWER */
+
+ {31, 235, OEM, "MULLW%V%C", gencc, ir3},
+ {7, 0, 0, "MULLW", qdiv, "%i,R%a,R%d"},
+
+ {31, 488, OEM, "NABS%V%C", neg, ir2}, /* POWER */
+
+ {31, 476, ALL, "NAND%C", gencc, il3},
+ {31, 104, OEM, "NEG%V%C", neg, ir2},
+ {31, 124, ALL, "NOR%C", gencc, il3},
+ {31, 444, ALL, "OR%C", or, il3},
+ {31, 412, ALL, "ORN%C", or, il3},
+ {24, 0, 0, "OR", and, "%I,R%d,R%a"},
+ {25, 0, 0, "OR", shifted, 0},
+
+ {19, 50, ALL, "RFI", gen, 0},
+
+ {22, 0, 0, "RLMI%C", gencc, rlim}, /* POWER */
+ {20, 0, 0, "RLWMI%C", gencc, rlimi},
+ {21, 0, 0, "RLWNM%C", gencc, rlimi},
+ {23, 0, 0, "RLWNM%C", gencc, rlim},
+
+ {31, 537, ALL, "RRIB%C", gencc, il3}, /* POWER */
+
+ {17, 1, ALL, "SYSCALL", gen, 0},
+
+ {31, 153, ALL, "SLE%C", shift, il3}, /* POWER */
+ {31, 217, ALL, "SLEQ%C", shift, il3}, /* POWER */
+ {31, 184, ALL, "SLQ%C", shifti, il3s}, /* POWER */
+ {31, 248, ALL, "SLLQ%C", shifti, il3s}, /* POWER */
+ {31, 216, ALL, "SLLQ%C", shift, il3}, /* POWER */
+ {31, 152, ALL, "SLQ%C", shift, il3}, /* POWER */
+
+ {31, 24, ALL, "SLW%C", shift, il3},
+
+ {31, 920, ALL, "SRAQ%C", shift, il3}, /* POWER */
+ {31, 952, ALL, "SRAQ%C", shifti, il3s}, /* POWER */
+
+ {31, 792, ALL, "SRAW%C", shift, il3},
+ {31, 824, ALL, "SRAW%C", shifti, il3s},
+
+ {31, 665, ALL, "SRE%C", shift, il3}, /* POWER */
+ {31, 921, ALL, "SREA%C", shift, il3}, /* POWER */
+ {31, 729, ALL, "SREQ%C", shift, il3}, /* POWER */
+ {31, 696, ALL, "SRQ%C", shifti, il3s}, /* POWER */
+ {31, 760, ALL, "SRLQ%C", shifti, il3s}, /* POWER */
+ {31, 728, ALL, "SRLQ%C", shift, il3}, /* POWER */
+ {31, 664, ALL, "SRQ%C", shift, il3}, /* POWER */
+
+ {31, 536, ALL, "SRW%C", shift, il3},
+
+ {38, 0, 0, "MOVB", store, stop},
+ {39, 0, 0, "MOVBU", store, stop},
+ {31, 247, ALL, "MOVBU", stx, 0},
+ {31, 215, ALL, "MOVB", stx, 0},
+ {54, 0, 0, "FMOVD", fstore, fstop},
+ {55, 0, 0, "FMOVDU", fstore, fstop},
+ {31, 759, ALL, "FMOVDU", fstx, 0},
+ {31, 727, ALL, "FMOVD", fstx, 0},
+ {52, 0, 0, "FMOVS", fstore, fstop},
+ {53, 0, 0, "FMOVSU", fstore, fstop},
+ {31, 695, ALL, "FMOVSU", fstx, 0},
+ {31, 663, ALL, "FMOVS", fstx, 0},
+ {44, 0, 0, "MOVH", store, stop},
+ {31, 918, ALL, "MOVHBR", stx, 0},
+ {45, 0, 0, "MOVHU", store, stop},
+ {31, 439, ALL, "MOVHU", stx, 0},
+ {31, 407, ALL, "MOVH", stx, 0},
+ {47, 0, 0, "MOVMW", store, stop},
+ {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"},
+ {31, 661, ALL, "STSW", stx, 0},
+ {36, 0, 0, "MOVW", store, stop},
+ {31, 662, ALL, "MOVWBR", stx, 0},
+ {31, 150, ALL, "STWCCC", stx, 0},
+ {37, 0, 0, "MOVWU", store, stop},
+ {31, 183, ALL, "MOVWU", stx, 0},
+ {31, 151, ALL, "MOVW", stx, 0},
+
+ {31, 40, OEM, "SUB%V%C", sub, ir3},
+ {31, 8, OEM, "SUBC%V%C", sub, ir3},
+ {31, 136, OEM, "SUBE%V%C", sub, ir3},
+ {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"},
+ {31, 232, OEM, "SUBME%V%C", sub, ir2},
+ {31, 200, OEM, "SUBZE%V%C", sub, ir2},
+
+ {31, 598, ALL, "SYNC", gen, 0},
+ {31, 306, ALL, "TLBIE", gen, "R%b"},
+ {31, 370, ALL, "TLBIA", gen, 0},
+ {31, 1010, ALL, "TLBLI", gen, "R%b"},
+ {31, 978, ALL, "TLBLD", gen, "R%b"},
+ {31, 4, ALL, "TW", gen, "%d,R%a,R%b"},
+ {3, 0, 0, "TW", gen, "%d,R%a,%i"},
+
+ {31, 316, ALL, "XOR", and, il3},
+ {26, 0, 0, "XOR", and, il2u},
+ {27, 0, 0, "XOR", shifted, 0},
+
+ {0},
+};
+
+typedef struct Spr Spr;
+struct Spr {
+ int n;
+ char *name;
+};
+
+static Spr sprname[] = {
+ {0, "MQ"},
+ {1, "XER"},
+ {268, "TBL"},
+ {269, "TBU"},
+ {8, "LR"},
+ {9, "CTR"},
+ {528, "IBAT0U"},
+ {529, "IBAT0L"},
+ {530, "IBAT1U"},
+ {531, "IBAT1L"},
+ {532, "IBAT2U"},
+ {533, "IBAT2L"},
+ {534, "IBAT3U"},
+ {535, "IBAT3L"},
+ {536, "DBAT0U"},
+ {537, "DBAT0L"},
+ {538, "DBAT1U"},
+ {539, "DBAT1L"},
+ {540, "DBAT2U"},
+ {541, "DBAT2L"},
+ {542, "DBAT3U"},
+ {543, "DBAT3L"},
+ {25, "SDR1"},
+ {19, "DAR"},
+ {272, "SPRG0"},
+ {273, "SPRG1"},
+ {274, "SPRG2"},
+ {275, "SPRG3"},
+ {18, "DSISR"},
+ {26, "SRR0"},
+ {27, "SRR1"},
+ {284, "TBLW"},
+ {285, "TBUW"},
+ {22, "DEC"},
+ {282, "EAR"},
+ {1008, "HID0"},
+ {1009, "HID1"},
+ {976, "DMISS"},
+ {977, "DCMP"},
+ {978, "HASH1"},
+ {979, "HASH2"},
+ {980, "IMISS"},
+ {981, "ICMP"},
+ {982, "RPA"},
+ {1010, "IABR"},
+ {1013, "DABR"},
+ {0,0},
+};
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int n, s;
+ ulong mask;
+
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (mnemonic)
+ bprint(i, "\t");
+ for ( ; *f; f++) {
+ if (*f != '%') {
+ bprint(i, "%c", *f);
+ continue;
+ }
+ switch (*++f) {
+ case 'V':
+ if(i->oe)
+ bprint(i, "V");
+ break;
+
+ case 'C':
+ if(i->rc)
+ bprint(i, "CC");
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->ra);
+ break;
+
+ case 'b':
+ bprint(i, "%d", i->rb);
+ break;
+
+ case 'c':
+ bprint(i, "%d", i->frc);
+ break;
+
+ case 'd':
+ case 's':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'S':
+ if(i->ra & 3)
+ bprint(i, "CR(INVAL:%d)", i->ra);
+ else if(i->op == 63)
+ bprint(i, "FPSCR(%d)", i->crfs);
+ else
+ bprint(i, "CR(%d)", i->crfs);
+ break;
+
+ case 'D':
+ if(i->rd & 3)
+ bprint(i, "CR(INVAL:%d)", i->rd);
+ else if(i->op == 63)
+ bprint(i, "FPSCR(%d)", i->crfd);
+ else
+ bprint(i, "CR(%d)", i->crfd);
+ break;
+
+ case 'l':
+ address(i);
+ break;
+
+ case 'i':
+ bprint(i, "$%ld", i->simm);
+ break;
+
+ case 'I':
+ bprint(i, "$%lx", i->uimm);
+ break;
+
+ case 'w':
+ bprint(i, "[%lux]", i->w0);
+ break;
+
+ case 'P':
+ n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
+ for(s=0; sprname[s].name; s++)
+ if(sprname[s].n == n)
+ break;
+ if(sprname[s].name) {
+ if(n < 10)
+ bprint(i, sprname[s].name);
+ else
+ bprint(i, "SPR(%s)", sprname[s].name);
+ } else
+ bprint(i, "SPR(%d)", n);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */
+ break;
+
+ case 'm':
+ bprint(i, "%lx", i->crm);
+ break;
+
+ case 'M':
+ bprint(i, "%lx", i->fm);
+ break;
+
+ case 'z':
+ if(i->mb <= i->me)
+ mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
+ else
+ mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
+ bprint(i, "%lux", mask);
+ break;
+
+ case 'k':
+ bprint(i, "%d", i->sh);
+ break;
+
+ case 'K':
+ bprint(i, "$%x", i->imm);
+ break;
+
+ case 'L':
+ if(i->lk)
+ bprint(i, "L");
+ break;
+
+ case 'j':
+ if(i->aa)
+ pglobal(i, i->li, 1, "(SB)");
+ else
+ pglobal(i, i->addr+i->li, 1, "");
+ break;
+
+ case 'J':
+ if(i->aa)
+ pglobal(i, i->bd, 1, "(SB)");
+ else
+ pglobal(i, i->addr+i->bd, 1, "");
+ break;
+
+ case '\0':
+ bprint(i, "%%");
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+ Opcode *o;
+
+ mymap = map;
+ memset(&i, 0, sizeof(i));
+ i.curr = buf;
+ i.end = buf+n-1;
+ if(mkinstr(pc, &i) < 0)
+ return -1;
+ for(o = opcodes; o->mnemonic != 0; o++)
+ if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
+ if (o->f)
+ (*o->f)(o, &i);
+ else
+ format(o->mnemonic, &i, o->ken);
+ return i.size*4;
+ }
+ bprint(&i, "unknown %lux", i.w0);
+ return i.size*4;
+}
+
+static int
+powerinst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ USED(modifier);
+ return printins(map, pc, buf, n);
+}
+
+static int
+powerdas(Map *map, ulong pc, char *buf, int n)
+{
+ Instr instr;
+
+ mymap = map;
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ if (mkinstr(pc, &instr) < 0)
+ return -1;
+ if (instr.end-instr.curr > 8)
+ instr.curr = _hexify(instr.curr, instr.w0, 7);
+ if (instr.end-instr.curr > 9 && instr.size == 2) {
+ *instr.curr++ = ' ';
+ instr.curr = _hexify(instr.curr, instr.w1, 7);
+ }
+ *instr.curr = 0;
+ return instr.size*4;
+}
+
+static int
+powerinstlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ return i.size*4;
+}
+
+static int
+powerfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ char *reg;
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ foll[0] = pc+4;
+ foll[1] = pc+4;
+ switch(i.op) {
+ default:
+ return 1;
+
+ case 18: /* branch */
+ foll[0] = i.li;
+ if(!i.aa)
+ foll[0] += pc;
+ break;
+
+ case 16: /* conditional branch */
+ foll[0] = i.bd;
+ if(!i.aa)
+ foll[0] += pc;
+ break;
+
+ case 19: /* conditional branch to register */
+ if(i.xo == 528)
+ reg = "CTR";
+ else if(i.xo == 16)
+ reg = "LR";
+ else
+ return 1; /* not a branch */
+ foll[0] = (*rget)(map, reg);
+ break;
+ }
+ if(i.lk)
+ return 2;
+ return 1;
+}
diff --git a/utils/libmach/qobj.c b/utils/libmach/qobj.c
new file mode 100644
index 00000000..5decad08
--- /dev/null
+++ b/utils/libmach/qobj.c
@@ -0,0 +1,134 @@
+/*
+ * qobj.c - identify and parse a PowerPC object file
+ * forsyth@terzarima.net
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "qc/q.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_isq(char *s)
+{
+ return (s[0]&0377) == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_readq(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ n = Bgetc(bp); /* reg and flag */
+ skip(bp, 4); /* lineno(4) */
+ a = addr(bp);
+ if(n & 0x40)
+ addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE: case D_REG: case D_FREG: case D_CREG:
+ case D_FPSCR: case D_MSR: case D_SREG:
+ break;
+ case D_SPR:
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/setmach.c b/utils/libmach/setmach.c
new file mode 100644
index 00000000..cdac45f6
--- /dev/null
+++ b/utils/libmach/setmach.c
@@ -0,0 +1,143 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+ /* table for selecting machine-dependent parameters */
+
+typedef struct machtab Machtab;
+
+struct machtab
+{
+ char *name; /* machine name */
+ short type; /* executable type */
+ short boottype; /* bootable type */
+ int asstype; /* disassembler code */
+ Mach *mach; /* machine description */
+ Machdata *machdata; /* machine functions */
+};
+
+extern Mach mmips, msparc, m68020, mi386, marm, mmips2be, mmips2le, mpower;
+extern Machdata mipsmach, sparcmach, m68020mach, i386mach,
+ armmach, mipsmach2be, mipsmach2le, powermach;
+
+/*
+ * machine selection table. machines with native disassemblers should
+ * follow the plan 9 variant in the table; native modes are selectable
+ * only by name.
+ */
+Machtab machines[] =
+{
+ { "68020", /*68020*/
+ F68020,
+ F68020B,
+ A68020,
+ &m68020,
+ &m68020mach, },
+ { "68020", /*Next 68040 bootable*/
+ F68020,
+ FNEXTB,
+ A68020,
+ &m68020,
+ &m68020mach, },
+ { "mips2LE", /*plan 9 mips2 little endian*/
+ FMIPS2LE,
+ 0,
+ AMIPS,
+ &mmips2le,
+ &mipsmach2le, },
+ { "mips", /*plan 9 mips*/
+ FMIPS,
+ FMIPSB,
+ AMIPS,
+ &mmips,
+ &mipsmach, },
+ { "mips2", /*plan 9 mips2*/
+ FMIPS2BE,
+ FMIPSB,
+ AMIPS,
+ &mmips2be,
+ &mipsmach2be, },
+ { "mipsco", /*native mips - must follow plan 9*/
+ FMIPS,
+ FMIPSB,
+ AMIPSCO,
+ &mmips,
+ &mipsmach, },
+ { "sparc", /*plan 9 sparc */
+ FSPARC,
+ FSPARCB,
+ ASPARC,
+ &msparc,
+ &sparcmach, },
+ { "sunsparc", /*native sparc - must follow plan 9*/
+ FSPARC,
+ FSPARCB,
+ ASUNSPARC,
+ &msparc,
+ &sparcmach, },
+ { "386", /*plan 9 386*/
+ FI386,
+ FI386B,
+ AI386,
+ &mi386,
+ &i386mach, },
+ { "86", /*8086 - a peach of a machine*/
+ FI386,
+ FI386B,
+ AI8086,
+ &mi386,
+ &i386mach, },
+ { "arm", /*ARM*/
+ FARM,
+ FNONE,
+ AARM,
+ &marm,
+ &armmach, },
+ { "power", /*PowerPC*/
+ FPOWER,
+ FNONE,
+ APOWER,
+ &mpower,
+ &powermach, },
+ { 0 }, /*the terminator*/
+};
+
+/*
+ * select a machine by executable file type
+ */
+void
+machbytype(int type)
+{
+ Machtab *mp;
+
+ for (mp = machines; mp->name; mp++){
+ if (mp->type == type || mp->boottype == type) {
+ asstype = mp->asstype;
+ machdata = mp->machdata;
+ break;
+ }
+ }
+}
+/*
+ * select a machine by name
+ */
+int
+machbyname(char *name)
+{
+ Machtab *mp;
+
+ if (!name) {
+ asstype = AMIPS;
+ machdata = &mipsmach;
+ mach = &mmips;
+ return 1;
+ }
+ for (mp = machines; mp->name; mp++){
+ if (strcmp(mp->name, name) == 0) {
+ asstype = mp->asstype;
+ machdata = mp->machdata;
+ mach = mp->mach;
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/utils/libmach/swap.c b/utils/libmach/swap.c
new file mode 100644
index 00000000..3ca9cf27
--- /dev/null
+++ b/utils/libmach/swap.c
@@ -0,0 +1,79 @@
+#include <lib9.h>
+
+/*
+ * big-endian short
+ */
+ushort
+beswab(ushort s)
+{
+ uchar *p;
+
+ p = (uchar*)&s;
+ return (p[0]<<8) | p[1];
+}
+
+/*
+ * big-endian long
+ */
+long
+beswal(long l)
+{
+ uchar *p;
+
+ p = (uchar*)&l;
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+/*
+ * big-endian vlong
+ */
+vlong
+beswav(vlong v)
+{
+ uchar *p;
+
+ p = (uchar*)&v;
+ return ((vlong)p[0]<<56) | ((vlong)p[1]<<48) | ((vlong)p[2]<<40)
+ | ((vlong)p[3]<<32) | ((vlong)p[4]<<24)
+ | ((vlong)p[5]<<16) | ((vlong)p[6]<<8)
+ | (vlong)p[7];
+}
+
+/*
+ * little-endian short
+ */
+ushort
+leswab(ushort s)
+{
+ uchar *p;
+
+ p = (uchar*)&s;
+ return (p[1]<<8) | p[0];
+}
+
+/*
+ * little-endian long
+ */
+long
+leswal(long l)
+{
+ uchar *p;
+
+ p = (uchar*)&l;
+ return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
+}
+
+/*
+ * little-endian vlong
+ */
+vlong
+leswav(vlong v)
+{
+ uchar *p;
+
+ p = (uchar*)&v;
+ return ((vlong)p[7]<<56) | ((vlong)p[6]<<48) | ((vlong)p[5]<<40)
+ | ((vlong)p[4]<<32) | ((vlong)p[3]<<24)
+ | ((vlong)p[2]<<16) | ((vlong)p[1]<<8)
+ | (vlong)p[0];
+}
diff --git a/utils/libmach/sym.c b/utils/libmach/sym.c
new file mode 100644
index 00000000..6b62c555
--- /dev/null
+++ b/utils/libmach/sym.c
@@ -0,0 +1,1405 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+#define HUGEINT 0x7fffffff
+#define NNAME 20 /* a relic of the past */
+
+typedef struct txtsym Txtsym;
+typedef struct file File;
+typedef struct hist Hist;
+typedef struct pcl Pcl;
+
+struct txtsym { /* Text Symbol table */
+ int n; /* number of local vars */
+ Sym **locals; /* array of ptrs to autos */
+ Sym *sym; /* function symbol entry */
+};
+
+struct hist { /* Stack of include files & #line directives */
+ char *name; /* Assumes names Null terminated in file */
+ long line; /* line # where it was included */
+ long offset; /* line # of #line directive */
+};
+
+struct pcl {
+ uchar *pcline; /* start of pcline data for this file */
+ long pc; /* starting pc for pcline crunch */
+ long line; /* starting line for pcline crunch */
+};
+
+struct file { /* Per input file header to history stack */
+ long addr; /* address of first text sym */
+ union {
+ Txtsym *ftxt; /* first text symbol */
+ Sym *fsym; /* only during initilization */
+ } u0;
+ int n; /* size of history stack */
+ Hist *hist; /* history stack */
+ Pcl pcl; /* pcline startup data */
+};
+
+static int debug = 0;
+
+static Sym **autos; /* Base of auto variables */
+static File *files; /* Base of file arena */
+static int fmax; /* largest file path index */
+static Sym **fnames; /* file names path component table */
+static Sym **globals; /* globals by addr table */
+static Hist *hist; /* base of history stack */
+static int isbuilt; /* internal table init flag */
+static long nauto; /* number of automatics */
+static long nfiles; /* number of files */
+static long nglob; /* number of globals */
+static long nhist; /* number of history stack entries */
+static long nsym; /* number of symbols */
+static long ntxt; /* number of text symbols */
+static uchar *pcline; /* start of pc-line state table */
+static uchar *pclineend; /* end of pc-line table */
+static int npcl; /* number of files pcl-decoded so far */
+static uchar *spoff; /* start of pc-sp state table */
+static uchar *spoffend; /* end of pc-sp offset table */
+static Sym *symbols; /* symbol table */
+static Txtsym *txt; /* Base of text symbol table */
+static long txtstart; /* start of text segment */
+static long txtend; /* end of text segment */
+
+static void cleansyms(void);
+static int decodename(Biobuf*, Sym*);
+static short *encfname(char*);
+static int fline(char*, int, long, Hist*, Hist**);
+static void fillsym(Sym*, Symbol*);
+static int findglobal(char*, Symbol*);
+static int findlocvar(Symbol*, char *, Symbol*);
+static int findtext(char*, Symbol*);
+static int hcomp(Hist*, short*);
+static int hline(File*, short*, ulong*);
+static void printhist(char*, Hist*, int);
+static long pcl2line(ulong, Pcl *, Pcl *);
+static long pc2fline(ulong, File **);
+static int pc2filex(ulong);
+static int buildtbls(void);
+static int symcomp(void*, void*);
+static int symerrmsg(int, char*);
+static int txtcomp(void*, void*);
+static int filecomp(void*, void*);
+
+/*
+ * initialize the symbol tables
+ */
+int
+syminit(int fd, Fhdr *fp)
+{
+ Sym *p;
+ int i, size;
+ Biobuf b;
+ extern void thumbpctab(Biobuf*, Fhdr*);
+
+ if(fp->symsz == 0)
+ return 0;
+ if(fp->type == FNONE)
+ return 0;
+
+ cleansyms();
+ textseg(fp->txtaddr, fp);
+ /* minimum symbol record size = 4+1+2 bytes */
+ symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
+ if(symbols == 0) {
+ werrstr("can't malloc %ld bytes", fp->symsz);
+ return -1;
+ }
+
+ Binit(&b, fd, OREAD);
+ Bseek(&b, fp->symoff, 0);
+ nsym = 0;
+ size = 0;
+ for(p = symbols; size < fp->symsz; p++, nsym++) {
+ if(Bread(&b, &p->value, sizeof(p->value)) != sizeof(p->value))
+ return symerrmsg(sizeof(p->value), "symbol");
+ p->value = beswal(p->value);
+ if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
+ return symerrmsg(sizeof(p->value), "symbol");
+
+ i = decodename(&b, p);
+ if(i < 0)
+ return -1;
+ size += i+sizeof(p->value)+sizeof(p->type);
+
+ /* count global & auto vars, text symbols, and file names */
+ switch (p->type) {
+ case 'l':
+ case 'L':
+ case 't':
+ case 'T':
+ ntxt++;
+ break;
+ case 'd':
+ case 'D':
+ case 'b':
+ case 'B':
+ nglob++;
+ break;
+ case 'f':
+ if(strcmp(p->name, ".frame") == 0) {
+ p->type = 'm';
+ nauto++;
+ }
+ else if(p->value > fmax)
+ fmax = p->value; /* highest path index */
+ break;
+ case 'a':
+ case 'p':
+ case 'm':
+ nauto++;
+ break;
+ case 'z':
+ if(p->value == 1) { /* one extra per file */
+ nhist++;
+ nfiles++;
+ }
+ nhist++;
+ break;
+ default:
+ break;
+ }
+ }
+ if (debug)
+ fprint(2,"NG: %ld NT: %ld NF: %d\n", nglob, ntxt, fmax);
+ if (fp->sppcsz) { /* pc-sp offset table */
+ spoff = (uchar *)malloc(fp->sppcsz);
+ if(spoff == 0) {
+ werrstr("can't malloc %ld bytes", fp->sppcsz);
+ return -1;
+ }
+ Bseek(&b, fp->sppcoff, 0);
+ i = Bread(&b, spoff, fp->sppcsz);
+ if(i != fp->sppcsz){
+ spoff = 0;
+ return symerrmsg(fp->sppcsz, "sp-pc");
+ }
+ spoffend = spoff+fp->sppcsz;
+ }
+ if (fp->lnpcsz) { /* pc-line number table */
+ pcline = (uchar *)malloc(fp->lnpcsz);
+ if(pcline == 0) {
+ werrstr("can't malloc %ld bytes", fp->lnpcsz);
+ return -1;
+ }
+ Bseek(&b, fp->lnpcoff, 0);
+ i = Bread(&b, pcline, fp->lnpcsz);
+ if(i != fp->lnpcsz){
+ pcline = 0;
+ return symerrmsg(fp->lnpcsz, "pc-line");
+ }
+ pclineend = pcline+fp->lnpcsz;
+ }
+ if(fp->type == FARM) /* thumb pc table */
+ thumbpctab(&b, fp);
+ return nsym;
+}
+
+static int
+symerrmsg(int n, char *table)
+{
+ werrstr("can't read %d bytes of %s table", n, table);
+ return -1;
+}
+
+static int
+decodename(Biobuf *bp, Sym *p)
+{
+ char *cp;
+ int c1, c2;
+ int n;
+
+ if((p->type & 0x80) == 0) { /* old-style, fixed length names */
+ p->name = malloc(NNAME);
+ if(p->name == 0) {
+ werrstr("can't malloc %d bytes", NNAME);
+ return -1;
+ }
+ if(Bread(bp, p->name, NNAME) != NNAME)
+ return symerrmsg(NNAME, "symbol");
+ Bseek(bp, 3, 1);
+ return NNAME+3;
+ }
+
+ p->type &= ~0x80;
+ if(p->type == 'z' || p->type == 'Z') {
+ n = Bseek(bp, 0, 1);
+ if(Bgetc(bp) < 0) {
+ werrstr("can't read symbol name");
+ return -1;
+ }
+ for(;;) {
+ c1 = Bgetc(bp);
+ c2 = Bgetc(bp);
+ if(c1 < 0 || c2 < 0) {
+ werrstr("can't read symbol name");
+ return -1;
+ }
+ if(c1 == 0 && c2 == 0)
+ break;
+ }
+ n = Bseek(bp, 0, 1)-n;
+ p->name = malloc(n);
+ if(p->name == 0) {
+ werrstr("can't malloc %d bytes", n);
+ return -1;
+ }
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->name, n) != n) {
+ werrstr("can't read %d bytes of symbol name", n);
+ return -1;
+ }
+ } else {
+ cp = Brdline(bp, '\0');
+ if(cp == 0) {
+ werrstr("can't read symbol name");
+ return -1;
+ }
+ n = Blinelen(bp);
+ p->name = malloc(n);
+ if(p->name == 0) {
+ werrstr("can't malloc %d bytes", n);
+ return -1;
+ }
+ strcpy(p->name, cp);
+ }
+ return n;
+}
+/*
+ * free any previously loaded symbol tables
+ */
+static void
+cleansyms(void)
+{
+ if(globals)
+ free(globals);
+ globals = 0;
+ nglob = 0;
+ if(txt)
+ free(txt);
+ txt = 0;
+ ntxt = 0;
+ if(fnames)
+ free(fnames);
+ fnames = 0;
+ fmax = 0;
+
+ if(files)
+ free(files);
+ files = 0;
+ nfiles = 0;
+ if(hist)
+ free(hist);
+ hist = 0;
+ nhist = 0;
+ if(autos)
+ free(autos);
+ autos = 0;
+ nauto = 0;
+ isbuilt = 0;
+ if(symbols)
+ free(symbols);
+ symbols = 0;
+ nsym = 0;
+ if(spoff)
+ free(spoff);
+ spoff = 0;
+ if(pcline)
+ free(pcline);
+ pcline = 0;
+ npcl = 0;
+}
+/*
+ * delimit the text segment
+ */
+void
+textseg(ulong base, Fhdr *fp)
+{
+ txtstart = base;
+ txtend = base+fp->txtsz;
+ npcl = 0; /* all pcls must be recomputed */
+}
+/*
+ * symbase: return base and size of raw symbol table
+ * (special hack for high access rate operations)
+ */
+Sym *
+symbase(long *n)
+{
+ *n = nsym;
+ return symbols;
+}
+/*
+ * Get the ith symbol table entry
+ */
+Sym *
+getsym(int index)
+{
+ if(index < nsym)
+ return &symbols[index];
+ return 0;
+}
+
+/*
+ * initialize internal symbol tables
+ */
+static int
+buildtbls(void)
+{
+ int i, j, nh, ng, nt;
+ File *f;
+ Txtsym *tp;
+ Hist *hp;
+ Sym *p, **ap;
+
+ if(isbuilt)
+ return 1;
+ isbuilt = 1;
+ /* allocate the tables */
+ if(nglob) {
+ globals = malloc(nglob*sizeof(*globals));
+ if(!globals) {
+ werrstr("can't malloc global symbol table");
+ return 0;
+ }
+ }
+ if(ntxt) {
+ txt = malloc(ntxt*sizeof(*txt));
+ if (!txt) {
+ werrstr("can't malloc text symbol table");
+ return 0;
+ }
+ }
+ fmax++;
+ fnames = malloc(fmax*sizeof(*fnames));
+ if (!fnames) {
+ werrstr("can't malloc file name table");
+ return 0;
+ }
+ memset(fnames, 0, fmax*sizeof(*fnames));
+ files = malloc(nfiles*sizeof(*files));
+ if(!files) {
+ werrstr("can't malloc file table");
+ return 0;
+ }
+ hist = malloc(nhist*sizeof(Hist));
+ if(hist == 0) {
+ werrstr("can't malloc history stack");
+ return 0;
+ }
+ autos = malloc(nauto*sizeof(Sym*));
+ if(autos == 0) {
+ werrstr("can't malloc auto symbol table");
+ return 0;
+ }
+ /* load the tables */
+ ng = nt = nh = 0;
+ f = 0;
+ tp = 0;
+ i = nsym;
+ hp = hist;
+ ap = autos;
+ for(p = symbols; i-- > 0; p++) {
+ switch(p->type) {
+ case 'D':
+ case 'd':
+ case 'B':
+ case 'b':
+ if(debug)
+ fprint(2,"Global: %s %lux\n", p->name, p->value);
+ globals[ng++] = p;
+ break;
+ case 'z':
+ if(p->value == 1) { /* New file */
+ if(f) {
+ f->n = nh;
+ f->hist[nh].name = 0; /* one extra */
+ hp += nh+1;
+ f++;
+ }
+ else f = files;
+ f->hist = hp;
+ f->u0.fsym = 0;
+ f->addr = 0;
+ nh = 0;
+ }
+ /* alloc one slot extra as terminator */
+ f->hist[nh].name = p->name;
+ f->hist[nh].line = p->value;
+ f->hist[nh].offset = 0;
+ if(debug)
+ printhist("-> ", &f->hist[nh], 1);
+ nh++;
+ break;
+ case 'Z':
+ if(f && nh > 0)
+ f->hist[nh-1].offset = p->value;
+ break;
+ case 'T':
+ case 't': /* Text: terminate history if first in file */
+ case 'L':
+ case 'l':
+ tp = &txt[nt++];
+ tp->n = 0;
+ tp->sym = p;
+ tp->locals = ap;
+ if(debug)
+ fprint(2,"TEXT: %s at %lux\n", p->name, p->value);
+ if(f && !f->u0.fsym) { /* first */
+ f->u0.fsym = p;
+ f->addr = p->value;
+ }
+ break;
+ case 'a':
+ case 'p':
+ case 'm': /* Local Vars */
+ if(!tp)
+ print("Warning: Free floating local var");
+ else {
+ if(debug)
+ fprint(2,"Local: %s %lux\n", p->name, p->value);
+ tp->locals[tp->n] = p;
+ tp->n++;
+ ap++;
+ }
+ break;
+ case 'f': /* File names */
+ if(debug)
+ fprint(2,"Fname: %s\n", p->name);
+ fnames[p->value] = p;
+ break;
+ default:
+ break;
+ }
+ }
+ /* sort global and text tables into ascending address order */
+ qsort(globals, nglob, sizeof(Sym*), symcomp);
+ qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
+ qsort(files, nfiles, sizeof(File), filecomp);
+ tp = txt;
+ for(i = 0, f = files; i < nfiles; i++, f++) {
+ for(j = 0; j < ntxt; j++) {
+ if(f->u0.fsym == tp->sym) {
+ if(debug) {
+ fprint(2,"LINK: %s to at %lux", f->u0.fsym->name, f->addr);
+ printhist("... ", f->hist, 1);
+ }
+ f->u0.ftxt = tp++;
+ break;
+ }
+ if(++tp >= txt+ntxt) /* wrap around */
+ tp = txt;
+ }
+ }
+ return 1;
+}
+
+/*
+ * find symbol function.var by name.
+ * fn != 0 && var != 0 => look for fn in text, var in data
+ * fn != 0 && var == 0 => look for fn in text
+ * fn == 0 && var != 0 => look for var first in text then in data space.
+ */
+int
+lookup(char *fn, char *var, Symbol *s)
+{
+ int found;
+
+ if(buildtbls() == 0)
+ return 0;
+ if(fn) {
+ found = findtext(fn, s);
+ if(var == 0) /* case 2: fn not in text */
+ return found;
+ else if(!found) /* case 1: fn not found */
+ return 0;
+ } else if(var) {
+ found = findtext(var, s);
+ if(found)
+ return 1; /* case 3: var found in text */
+ } else return 0; /* case 4: fn & var == zero */
+
+ if(found)
+ return findlocal(s, var, s); /* case 1: fn found */
+ return findglobal(var, s); /* case 3: var not found */
+
+}
+/*
+ * find a function by name
+ */
+static int
+findtext(char *name, Symbol *s)
+{
+ int i;
+
+ for(i = 0; i < ntxt; i++) {
+ if(strcmp(txt[i].sym->name, name) == 0) {
+ fillsym(txt[i].sym, s);
+ s->handle = (void *) &txt[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+/*
+ * find global variable by name
+ */
+static int
+findglobal(char *name, Symbol *s)
+{
+ int i;
+
+ for(i = 0; i < nglob; i++) {
+ if(strcmp(globals[i]->name, name) == 0) {
+ fillsym(globals[i], s);
+ return 1;
+ }
+ }
+ return 0;
+}
+/*
+ * find the local variable by name within a given function
+ */
+int
+findlocal(Symbol *s1, char *name, Symbol *s2)
+{
+ if(s1 == 0)
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+ return findlocvar(s1, name, s2);
+}
+/*
+ * find the local variable by name within a given function
+ * (internal function - does no parameter validation)
+ */
+static int
+findlocvar(Symbol *s1, char *name, Symbol *s2)
+{
+ Txtsym *tp;
+ int i;
+
+ tp = (Txtsym *)s1->handle;
+ if(tp && tp->locals) {
+ for(i = 0; i < tp->n; i++)
+ if (strcmp(tp->locals[i]->name, name) == 0) {
+ fillsym(tp->locals[i], s2);
+ s2->handle = (void *)tp;
+ return 1;
+ }
+ }
+ return 0;
+}
+/*
+ * Get ith text symbol
+ */
+int
+textsym(Symbol *s, int index)
+{
+
+ if(buildtbls() == 0)
+ return 0;
+ if(index >= ntxt)
+ return 0;
+ fillsym(txt[index].sym, s);
+ s->handle = (void *)&txt[index];
+ return 1;
+}
+/*
+ * Get ith file name
+ */
+int
+filesym(int index, char *buf, int n)
+{
+ Hist *hp;
+
+ if(buildtbls() == 0)
+ return 0;
+ if(index >= nfiles)
+ return 0;
+ hp = files[index].hist;
+ if(!hp || !hp->name)
+ return 0;
+ return fileelem(fnames, (uchar*)hp->name, buf, n);
+}
+/*
+ * Lookup name of local variable located at an offset into the frame.
+ * The type selects either a parameter or automatic.
+ */
+int
+getauto(Symbol *s1, int off, int type, Symbol *s2)
+{
+ Txtsym *tp;
+ Sym *p;
+ int i, t;
+
+ if(s1 == 0)
+ return 0;
+ if(type == CPARAM)
+ t = 'p';
+ else if(type == CAUTO)
+ t = 'a';
+ else
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+ tp = (Txtsym *)s1->handle;
+ if(tp == 0)
+ return 0;
+ for(i = 0; i < tp->n; i++) {
+ p = tp->locals[i];
+ if(p->type == t && p->value == off) {
+ fillsym(p, s2);
+ s2->handle = s1->handle;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Find text symbol containing addr; binary search assumes text array is sorted by addr
+ */
+static int
+srchtext(long addr)
+{
+ ulong val;
+ int top, bot, mid;
+ Sym *sp;
+
+ val = addr;
+ bot = 0;
+ top = ntxt;
+ for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+ sp = txt[mid].sym;
+ if(val < (ulong)sp->value)
+ top = mid;
+ else if(mid != ntxt-1 && val >= (ulong)txt[mid+1].sym->value)
+ bot = mid;
+ else
+ return mid;
+ }
+ return -1;
+}
+
+/*
+ * Find data symbol containing addr; binary search assumes data array is sorted by addr
+ */
+static
+int srchdata(long addr)
+{
+ ulong val;
+ int top, bot, mid;
+ Sym *sp;
+
+ bot = 0;
+ top = nglob;
+ val = addr;
+ for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+ sp = globals[mid];
+ if(val < (ulong)sp->value)
+ top = mid;
+ else if(mid < nglob-1 && val >= (ulong)globals[mid+1]->value)
+ bot = mid;
+ else
+ return mid;
+ }
+ return -1;
+}
+/*
+ * Find symbol containing val in specified search space
+ * There is a special case when a value falls beyond the end
+ * of the text segment; if the search space is CTEXT, that value
+ * (usually etext) is returned. If the search space is CANY, symbols in the
+ * data space are searched for a match.
+ */
+int
+findsym(long w, int type, Symbol *s)
+{
+ int i;
+
+ if(buildtbls() == 0)
+ return 0;
+
+ if(type == CTEXT || type == CANY) {
+ i = srchtext(w);
+ if(i >= 0) {
+ if(type == CTEXT || i != ntxt-1) {
+ fillsym(txt[i].sym, s);
+ s->handle = (void *) &txt[i];
+ return 1;
+ }
+ }
+ }
+ if(type == CDATA || type == CANY) {
+ i = srchdata(w);
+ if(i >= 0) {
+ fillsym(globals[i], s);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Find the start and end address of the function containing addr
+ */
+int
+fnbound(long addr, ulong *bounds)
+{
+ int i;
+
+ if(buildtbls() == 0)
+ return 0;
+
+ i = srchtext(addr);
+ if(0 <= i && i < ntxt-1) {
+ bounds[0] = txt[i].sym->value;
+ bounds[1] = txt[i+1].sym->value;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * get the ith local symbol for a function
+ * the input symbol table is reverse ordered, so we reverse
+ * accesses here to maintain approx. parameter ordering in a stack trace.
+ */
+int
+localsym(Symbol *s, int index)
+{
+ Txtsym *tp;
+
+ if(s == 0)
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+
+ tp = (Txtsym *)s->handle;
+ if(tp && tp->locals && index < tp->n) {
+ fillsym(tp->locals[tp->n-index-1], s); /* reverse */
+ s->handle = (void *)tp;
+ return 1;
+ }
+ return 0;
+}
+/*
+ * get the ith global symbol
+ */
+int
+globalsym(Symbol *s, int index)
+{
+ if(s == 0)
+ return 0;
+ if(buildtbls() == 0)
+ return 0;
+
+ if(index < nglob) {
+ fillsym(globals[index], s);
+ return 1;
+ }
+ return 0;
+}
+/*
+ * find the pc given a file name and line offset into it.
+ */
+long
+file2pc(char *file, ulong line)
+{
+ File *fp;
+ int i;
+ long pc;
+ ulong start, end;
+ short *name;
+
+ if(buildtbls() == 0 || files == 0)
+ return -1;
+ name = encfname(file);
+ if(name == 0) { /* encode the file name */
+ werrstr("file %s not found", file);
+ return -1;
+ }
+ /* find this history stack */
+ for(i = 0, fp = files; i < nfiles; i++, fp++)
+ if (hline(fp, name, &line))
+ break;
+ free(name);
+ if(i >= nfiles) {
+ werrstr("line %ld in file %s not found", line, file);
+ return -1;
+ }
+ start = fp->addr; /* first text addr this file */
+ if(i < nfiles-1)
+ end = (fp+1)->addr; /* first text addr next file */
+ else
+ end = 0; /* last file in load module */
+ /*
+ * At this point, line contains the offset into the file.
+ * run the state machine to locate the pc closest to that value.
+ */
+ if(debug)
+ fprint(2,"find pc for %ld - between: %lux and %lux\n", line, start, end);
+ pc = line2addr(line, start, end);
+ if(pc == -1) {
+ werrstr("line %ld not in file %s", line, file);
+ return -1;
+ }
+ return pc;
+}
+/*
+ * search for a path component index
+ */
+static int
+pathcomp(char *s, int n)
+{
+ int i;
+
+ for(i = 0; i <= fmax; i++)
+ if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0 && fnames[i]->name[n] == 0)
+ return i;
+ return -1;
+}
+/*
+ * Encode a char file name as a sequence of short indices
+ * into the file name dictionary.
+ */
+static short*
+encfname(char *file)
+{
+ int i, j;
+ char *cp, *cp2;
+ short *dest;
+
+ if(*file == '/') /* always check first '/' */
+ cp2 = file+1;
+ else {
+ cp2 = strchr(file, '/');
+ if(!cp2)
+ cp2 = strchr(file, 0);
+ }
+ cp = file;
+ dest = 0;
+ for(i = 0; *cp; i++) {
+ j = pathcomp(cp, cp2-cp);
+ if(j < 0)
+ return 0; /* not found */
+ dest = realloc(dest, (i+1)*sizeof(short));
+ dest[i] = j;
+ cp = cp2;
+ while(*cp == '/') /* skip embedded '/'s */
+ cp++;
+ cp2 = strchr(cp, '/');
+ if(!cp2)
+ cp2 = strchr(cp, 0);
+ }
+ dest = realloc(dest, (i+1)*sizeof(short));
+ dest[i] = 0;
+ return dest;
+}
+/*
+ * Search a history stack for a matching file name accumulating
+ * the size of intervening files in the stack.
+ */
+static int
+hline(File *fp, short *name, ulong *line)
+{
+ Hist *hp;
+ int offset, depth;
+ long ln;
+
+ for(hp = fp->hist; hp->name; hp++) /* find name in stack */
+ if(hp->name[1] || hp->name[2]) {
+ if(hcomp(hp, name))
+ break;
+ }
+ if(!hp->name) /* match not found */
+ return 0;
+ if(debug)
+ printhist("hline found ... ", hp, 1);
+ /*
+ * unwind the stack until empty or we hit an entry beyond our line
+ */
+ ln = *line;
+ offset = hp->line-1;
+ depth = 1;
+ for(hp++; depth && hp->name; hp++) {
+ if(debug)
+ printhist("hline inspect ... ", hp, 1);
+ if(hp->name[1] || hp->name[2]) {
+ if(hp->offset){ /* Z record */
+ offset = 0;
+ if(hcomp(hp, name)) {
+ if(*line <= hp->offset)
+ break;
+ ln = *line+hp->line-hp->offset;
+ depth = 1; /* implicit pop */
+ } else
+ depth = 2; /* implicit push */
+ } else if(depth == 1 && ln < hp->line-offset)
+ break; /* Beyond our line */
+ else if(depth++ == 1) /* push */
+ offset -= hp->line;
+ } else if(--depth == 1) /* pop */
+ offset += hp->line;
+ }
+ *line = ln+offset;
+ return 1;
+}
+/*
+ * compare two encoded file names
+ */
+static int
+hcomp(Hist *hp, short *sp)
+{
+ uchar *cp;
+ int i, j;
+ short *s;
+
+ cp = (uchar *)hp->name;
+ s = sp;
+ if (*s == 0)
+ return 0;
+ for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
+ if(j == 0)
+ break;
+ if(*s == j)
+ s++;
+ else
+ s = sp;
+ }
+ return *s == 0;
+}
+/*
+ * Convert a pc to a "file:line {file:line}" string.
+ */
+int
+fileline(char *str, int n, ulong dot)
+{
+ long line;
+ File *f;
+ int i;
+
+ *str = 0;
+ if(buildtbls() == 0)
+ return 0;
+
+ i = pc2filex(dot);
+ if (i >= 0)
+ {
+ f = &files[i];
+ line = pc2line(dot);
+ if(line >= 0 && fline(str, n, line, f->hist, 0) >= 0)
+ return 1;
+ }
+ return 0;
+}
+/*
+ * Convert a pc to an index to the file table
+ */
+static int
+pc2filex(ulong dot)
+{
+ int top, bot, mid;
+ File *f;
+
+ if(buildtbls() == 0)
+ return -1;
+
+ /* binary search assumes file list is sorted by addr */
+ bot = 0;
+ top = nfiles;
+ for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+ f = &files[mid];
+ if(dot < f->addr)
+ top = mid;
+ else if(mid < nfiles-1 && dot >= (f+1)->addr)
+ bot = mid;
+ else
+ return mid;
+ }
+ return -1;
+}
+
+/*
+ * Convert a line number within a composite file to relative line
+ * number in a source file. A composite file is the source
+ * file with included files inserted in line.
+ */
+static int
+fline(char *str, int n, long line, Hist *base, Hist **ret)
+{
+ Hist *start; /* start of current level */
+ Hist *h; /* current entry */
+ int delta; /* sum of size of files this level */
+ int k;
+
+ start = base;
+ h = base;
+ delta = h->line;
+ while(h && h->name && line > h->line) {
+ if(h->name[1] || h->name[2]) {
+ if(h->offset != 0) { /* #line Directive */
+ delta = h->line-h->offset+1;
+ start = h;
+ base = h++;
+ } else { /* beginning of File */
+ if(start == base)
+ start = h++;
+ else {
+ k = fline(str, n, line, start, &h);
+ if(k <= 0)
+ return k;
+ }
+ }
+ } else {
+ if(start == base) { /* end of recursion level */
+ if(ret)
+ *ret = h;
+ return 1;
+ } else { /* end of included file */
+ delta += h->line-start->line;
+ h++;
+ start = base;
+ }
+ }
+ }
+ if(!h)
+ return -1;
+ if(start != base)
+ line = line-start->line+1;
+ else
+ line = line-delta+1;
+ if(!h->name)
+ strncpy(str, "<eof>", n);
+ else {
+ k = fileelem(fnames, (uchar*)start->name, str, n);
+ if(k+8 < n)
+ sprint(str+k, ":%ld", line);
+ }
+/**********Remove comments for complete back-trace of include sequence
+ * if(start != base) {
+ * k = strlen(str);
+ * if(k+2 < n) {
+ * str[k++] = ' ';
+ * str[k++] = '{';
+ * }
+ * k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
+ * if(k+10 < n)
+ * sprint(str+k, ":%ld}", start->line-delta);
+ * }
+ ********************/
+ return 0;
+}
+/*
+ * convert an encoded file name to a string.
+ */
+int
+fileelem(Sym **fp, uchar *cp, char *buf, int n)
+{
+ int i, j;
+ char *c, *bp, *end;
+
+ bp = buf;
+ end = buf+n-1;
+ for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
+ c = fp[j]->name;
+ if(bp != buf && bp[-1] != '/' && bp < end)
+ *bp++ = '/';
+ while(bp < end && *c)
+ *bp++ = *c++;
+ }
+ *bp = 0;
+ return bp-buf;
+}
+/*
+ * compare the values of two symbol table entries.
+ */
+static int
+symcomp(void *a, void *b)
+{
+ return (*(Sym**)a)->value - (*(Sym**)b)->value;
+}
+/*
+ * compare the values of the symbols referenced by two text table entries
+ */
+static int
+txtcomp(void *a, void *b)
+{
+ return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
+}
+/*
+ * compare the values of the symbols referenced by two file table entries
+ */
+static int
+filecomp(void *a, void *b)
+{
+ return ((File*)a)->addr - ((File*)b)->addr;
+}
+/*
+ * fill an interface Symbol structure from a symbol table entry
+ */
+static void
+fillsym(Sym *sp, Symbol *s)
+{
+ s->type = sp->type;
+ s->value = sp->value;
+ s->name = sp->name;
+ switch(sp->type) {
+ case 'b':
+ case 'B':
+ case 'D':
+ case 'd':
+ s->class = CDATA;
+ break;
+ case 't':
+ case 'T':
+ case 'l':
+ case 'L':
+ s->class = CTEXT;
+ break;
+ case 'a':
+ s->class = CAUTO;
+ break;
+ case 'p':
+ s->class = CPARAM;
+ break;
+ case 'm':
+ s->class = CSTAB;
+ break;
+ default:
+ s->class = CNONE;
+ break;
+ }
+ s->handle = 0;
+}
+/*
+ * find the stack frame, given the pc
+ */
+long
+pc2sp(ulong pc)
+{
+ uchar *c;
+ uchar u;
+ ulong currpc;
+ long currsp;
+
+ if(spoff == 0)
+ return -1;
+ currsp = 0;
+ currpc = txtstart - mach->pcquant;
+
+ if(pc<currpc || pc>txtend)
+ return -1;
+ for(c = spoff; c < spoffend; c++) {
+ if (currpc >= pc)
+ return currsp;
+ u = *c;
+ if (u == 0) {
+ currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+ c += 4;
+ }
+ else if (u < 65)
+ currsp += 4*u;
+ else if (u < 129)
+ currsp -= 4*(u-64);
+ else
+ currpc += mach->pcquant*(u-129);
+ currpc += mach->pcquant;
+ }
+ return -1;
+}
+/*
+ * find the source file line number for a given value of the pc
+ */
+long
+pc2line(ulong pc)
+{
+ File *fp;
+ return pc2fline(pc, &fp);
+}
+/*
+ * Convert a pc into a file table pointer & line offset
+ */
+static long
+pc2fline(ulong pc, File **fpp)
+{
+ File *f;
+ int i;
+
+ i = pc2filex(pc);
+ if (i < 0)
+ return i;
+ if (i >= npcl){
+ /* Precompute starting points by file, else too slow */
+ if (npcl == 0){
+ Pcl pcl;
+
+ /* decode start for pcline machine */
+ pcl.pcline = pcline;
+ pcl.pc = txtstart - mach->pcquant;
+ pcl.line = 0;
+ pcl2line(files->addr, &pcl, &files[0].pcl);
+ npcl = 1;
+ }
+ for (f = &files[npcl]; npcl <= i; npcl++, f++)
+ if (pcl2line(f->addr, &(f-1)->pcl, &f->pcl) < 0)
+ break;
+ }
+ f = &files[i];
+ *fpp = f;
+ return pcl2line(pc, &f->pcl, 0);
+}
+/*
+ * Convert pc to line offset, given Pcl starting point,
+ * saving Pcl result.
+ */
+static long
+pcl2line(ulong pc, Pcl *bp, Pcl *rp)
+{
+ uchar *c;
+ uchar u;
+ ulong currpc;
+ long currline;
+
+ if(bp->pcline == 0)
+ return -1;
+ currpc = bp->pc;
+ currline = bp->line;
+ if(pc<currpc || pc>txtend)
+ return -1;
+ for(c = bp->pcline; c < pclineend; c++) {
+ if (currpc >= pc) {
+ if (rp){
+ rp->pc = currpc;
+ rp->line = currline;
+ rp->pcline = c;
+ }
+ return currline;
+ }
+ u = *c;
+ if(u == 0) {
+ currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+ c += 4;
+ }
+ else if(u < 65)
+ currline += u;
+ else if(u < 129)
+ currline -= (u-64);
+ else
+ currpc += mach->pcquant*(u-129);
+ currpc += mach->pcquant;
+ }
+ return -1;
+}
+/*
+ * find the pc associated with a line number
+ * basepc and endpc are text addresses bounding the search.
+ * if endpc == 0, the end of the table is used (i.e., no upper bound).
+ * usually, basepc and endpc contain the first text address in
+ * a file and the first text address in the following file, respectively.
+ */
+long
+line2addr(ulong line, ulong basepc, ulong endpc)
+{
+ uchar *c;
+ uchar u;
+ ulong currpc;
+ long currline;
+ long delta, d;
+ long pc, found;
+
+ if(pcline == 0 || line == 0)
+ return -1;
+
+ currline = 0;
+ currpc = txtstart-mach->pcquant;
+ pc = -1;
+ found = 0;
+ delta = HUGEINT;
+
+ for(c = pcline; c < pclineend; c++) {
+ if(endpc && currpc >= endpc) /* end of file of interest */
+ break;
+ if(currpc >= basepc) { /* proper file */
+ if(currline >= line) {
+ d = currline-line;
+ found = 1;
+ } else
+ d = line-currline;
+ if(d < delta) {
+ delta = d;
+ pc = currpc;
+ }
+ }
+ u = *c;
+ if(u == 0) {
+ currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+ c += 4;
+ }
+ else if(u < 65)
+ currline += u;
+ else if(u < 129)
+ currline -= (u-64);
+ else
+ currpc += mach->pcquant*(u-129);
+ currpc += mach->pcquant;
+ }
+ if(found)
+ return pc;
+ return -1;
+}
+/*
+ * Print a history stack (debug). if count is 0, prints the whole stack
+ */
+static void
+printhist(char *msg, Hist *hp, int count)
+{
+ int i;
+ uchar *cp;
+ char buf[128];
+
+ i = 0;
+ while(hp->name) {
+ if(count && ++i > count)
+ break;
+ fprint(2,"%s Line: %lx (%ld) Offset: %lx (%ld) Name: ", msg,
+ hp->line, hp->line, hp->offset, hp->offset);
+ for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
+ if (cp != (uchar *)hp->name+1)
+ fprint(2,"/");
+ fprint(2,"%x", (*cp<<8)|cp[1]);
+ }
+ fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
+ fprint(2," (%s)\n", buf);
+ hp++;
+ }
+}
+
+#ifdef DEBUG
+/*
+ * print the history stack for a file. (debug only)
+ * if (name == 0) => print all history stacks.
+ */
+void
+dumphist(char *name)
+{
+ int i;
+ File *f;
+ short *fname;
+
+ if(buildtbls() == 0)
+ return;
+ if(name)
+ fname = encfname(name);
+ for(i = 0, f = files; i < nfiles; i++, f++)
+ if(fname == 0 || hcomp(f->hist, fname))
+ printhist("> ", f->hist, f->n);
+
+ if(fname)
+ free(fname);
+}
+#endif
diff --git a/utils/libmach/t.c b/utils/libmach/t.c
new file mode 100644
index 00000000..adea089b
--- /dev/null
+++ b/utils/libmach/t.c
@@ -0,0 +1,122 @@
+/*
+ * thumb definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "uregt.h"
+#include "mach.h"
+
+
+#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x)
+
+#define SP REGOFF(r13)
+#define PC REGOFF(pc)
+
+#define REGSIZE sizeof(struct Ureg)
+
+Reglist thumbreglist[] =
+{
+ {"LINK", REGOFF(link), RINT|RRDONLY, 'X'},
+ {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'},
+ {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"R15", PC, RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ {"R0", REGOFF(r0), RINT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mthumb =
+{
+ "thumb",
+ MARM, /*MTHUMB,*/ /* machine type */
+ thumbreglist, /* register set */
+ REGSIZE, /* register set size */
+ 0, /* fp register set size */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R15", /* name of link register */
+ "setR12", /* static base register name */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0x80000000, /* kernel base */
+ 0, /* kernel text mask */
+ 2, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
+
+typedef struct pcentry pcentry;
+
+struct pcentry{
+ long start;
+ long stop;
+};
+
+static pcentry *pctab;
+static int npctab;
+
+void
+thumbpctab(Biobuf *b, Fhdr *fp)
+{
+ int n, o, ta;
+ uchar c[8];
+ pcentry *tab;
+
+ Bseek(b, fp->lnpcoff+fp->lnpcsz, 0);
+ o = (int)Boffset(b);
+ Bseek(b, 0, 2);
+ n = (int)Boffset(b)-o;
+ pctab = (pcentry*)malloc(n);
+ if(pctab == 0)
+ return;
+ ta = fp->txtaddr;
+ tab = pctab;
+ Bseek(b, fp->lnpcoff+fp->lnpcsz, 0);
+ while(Bread(b, c, sizeof(c)) == sizeof(c)){
+ tab->start = ta + (c[0]<<24)|(c[1]<<16)|(c[2]<<8)|c[3];
+ tab->stop = ta + (c[4]<<24)|(c[5]<<16)|(c[6]<<8)|c[7];
+ tab++;
+ }
+ npctab = n/sizeof(c);
+}
+
+int
+thumbpclookup(ulong pc)
+{
+ ulong l, u, m;
+ pcentry *tab = pctab;
+
+ l = 0;
+ u = npctab-1;
+ while(l < u){
+ m = (l+u)/2;
+ if(pc < tab[m].start)
+ u = m-1;
+ else if(pc > tab[m].stop)
+ l = m+1;
+ else
+ l = u = m;
+ }
+ if(l == u && u >= 0 && u < npctab && tab[u].start <= pc && pc <= tab[u].stop)
+ return 1; // thumb
+ return 0; // arm
+}
+
diff --git a/utils/libmach/tdb.c b/utils/libmach/tdb.c
new file mode 100644
index 00000000..8eddc43a
--- /dev/null
+++ b/utils/libmach/tdb.c
@@ -0,0 +1,839 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+static int debug = 0;
+
+typedef struct Instr Instr;
+struct Instr
+{
+ Map *map;
+ ulong w;
+ ulong addr;
+ uchar op; /* super opcode */
+
+ uchar rd;
+ uchar rn;
+ uchar rs;
+
+ long imm; /* imm */
+
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+ char* err; /* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+ char* o;
+ void (*fmt)(Opcode*, Instr*);
+ ulong (*foll)(Map*, Rgetter, Instr*, ulong);
+ char* a;
+};
+
+static void format(char*, Instr*, char*);
+static char FRAMENAME[] = ".frame";
+
+/*
+ * Thumb-specific debugger interface
+ */
+
+static char *thumbexcep(Map*, Rgetter);
+static int thumbfoll(Map*, ulong, Rgetter, ulong*);
+static int thumbinst(Map*, ulong, char, char*, int);
+static int thumbdas(Map*, ulong, char*, int);
+static int thumbinstlen(Map*, ulong);
+
+/*
+ * Debugger interface
+ */
+Machdata thumbmach =
+{
+ {0x0, 0xE8}, /* break point */
+ 2, /* break point size */
+
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* long to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ thumbexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ 0, /* single precision float printer */
+ 0, /* double precision float printer */
+ thumbfoll, /* following addresses */
+ thumbinst, /* print instruction */
+ thumbdas, /* dissembler */
+ thumbinstlen, /* instruction size */
+};
+
+static void thumbrrh(Opcode *, Instr *);
+static void thumbbcc(Opcode *, Instr *);
+static void thumbb(Opcode *, Instr *);
+static void thumbbl(Opcode *, Instr *);
+
+static char*
+thumbexcep(Map *map, Rgetter rget)
+{
+ long c;
+
+ c = (*rget)(map, "TYPE");
+ switch (c&0x1f) {
+ case 0x11:
+ return "Fiq interrupt";
+ case 0x12:
+ return "Mirq interrupt";
+ case 0x13:
+ return "SVC/SWI Exception";
+ case 0x17:
+ return "Prefetch Abort/Data Abort";
+ case 0x18:
+ return "Data Abort";
+ case 0x1b:
+ return "Undefined instruction/Breakpoint";
+ case 0x1f:
+ return "Sys trap";
+ default:
+ return "Undefined trap";
+ }
+}
+
+static
+char* cond[16] =
+{
+ "EQ", "NE", "CS", "CC",
+ "MI", "PL", "VS", "VC",
+ "HI", "LS", "GE", "LT",
+ "GT", "LE", "\0", "NV"
+};
+
+#define B(h, l) bits(ins, h, l)
+
+static int
+bits(int i, int h, int l)
+{
+ if(h < l)
+ print("h < l in bits");
+ return (i&(((1<<(h-l+1))-1)<<l))>>l;
+}
+
+int
+thumbclass(long w)
+{
+ int o;
+ int ins = w;
+
+ if(ins&0xffff0000)
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2;
+ o = B(15, 13);
+ switch(o){
+ case 0:
+ o = B(12, 11);
+ switch(o){
+ case 0:
+ case 1:
+ case 2:
+ return B(12, 11);
+ case 3:
+ if(B(10, 10) == 0)
+ return 3+B(9, 9);
+ else
+ return 3+2+B(9, 9);
+ }
+ case 1:
+ return 3+2+2+B(12, 11);
+ case 2:
+ o = B(12, 10);
+ if(o == 0)
+ return 3+2+2+4+B(9, 6);
+ if(o == 1){
+ o = B(9, 8);
+ if(o == 3)
+ return 3+2+2+4+16+B(9, 8);
+ return 3+2+2+4+16+B(9, 8);
+ }
+ if(o == 2 || o == 3)
+ return 3+2+2+4+16+4;
+ return 3+2+2+4+16+4+1+B(11, 9);
+ case 3:
+ return 3+2+2+4+16+4+1+8+B(12, 11);
+ case 4:
+ if(B(12, 12) == 0)
+ return 3+2+2+4+16+4+1+8+4+B(11, 11);
+ return 3+2+2+4+16+4+1+8+6+B(11, 11);
+ case 5:
+ if(B(12, 12) == 0)
+ return 3+2+2+4+16+4+1+8+6+2+B(11, 11);
+ if(B(11, 8) == 0)
+ return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7);
+ return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11);
+ case 6:
+ if(B(12, 12) == 0)
+ return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11);
+ if(B(11, 8) == 0xf)
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4;
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1;
+ case 7:
+ o = B(12, 11);
+ switch(o){
+ case 0:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1;
+ case 1:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2;
+ case 2:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1;
+ case 3:
+ return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1;
+ }
+ }
+ return 0;
+}
+
+static int
+decode(Map *map, ulong pc, Instr *i)
+{
+ ushort w;
+
+ if(get2(map, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->w = w;
+ i->addr = pc;
+ i->op = thumbclass(w);
+ i->map = map;
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+plocal(Instr *i)
+{
+ char *reg;
+ Symbol s;
+ char *fn;
+ int class;
+ int offset;
+
+ if(!findsym(i->addr, CTEXT, &s)) {
+ if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
+ return 0;
+ }
+ fn = s.name;
+ if (!findlocal(&s, FRAMENAME, &s)) {
+ if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
+ return 0;
+ }
+ if(s.value > i->imm) {
+ class = CAUTO;
+ offset = s.value-i->imm;
+ reg = "(SP)";
+ } else {
+ class = CPARAM;
+ offset = i->imm-s.value-4;
+ reg = "(FP)";
+ }
+ if(!getauto(&s, offset, class, &s)) {
+ if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
+ class == CAUTO ? " auto" : "param", offset);
+ return 0;
+ }
+ bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
+ return 1;
+}
+
+/*
+ * Print value v as name[+offset]
+ */
+static int
+gsymoff(char *buf, int n, long v, int space)
+{
+ Symbol s;
+ int r;
+ long delta;
+
+ r = delta = 0; /* to shut compiler up */
+ if (v) {
+ r = findsym(v, space, &s);
+ if (r)
+ delta = v-s.value;
+ if (delta < 0)
+ delta = -delta;
+ }
+ if (v == 0 || r == 0 || delta >= 4096)
+ return snprint(buf, n, "#%lux", v);
+ if (strcmp(s.name, ".string") == 0)
+ return snprint(buf, n, "#%lux", v);
+ if (!delta)
+ return snprint(buf, n, "%s", s.name);
+ if (s.type != 't' && s.type != 'T')
+ return snprint(buf, n, "%s+%lux", s.name, v-s.value);
+ else
+ return snprint(buf, n, "#%lux", v);
+}
+
+static int
+thumbcondpass(Map *map, Rgetter rget, uchar cond)
+{
+ ulong psr;
+ uchar n;
+ uchar z;
+ uchar c;
+ uchar v;
+
+ psr = rget(map, "PSR");
+ n = (psr >> 31) & 1;
+ z = (psr >> 30) & 1;
+ c = (psr >> 29) & 1;
+ v = (psr >> 28) & 1;
+
+ switch(cond) {
+ case 0: return z;
+ case 1: return !z;
+ case 2: return c;
+ case 3: return !c;
+ case 4: return n;
+ case 5: return !n;
+ case 6: return v;
+ case 7: return !v;
+ case 8: return c && !z;
+ case 9: return !c || z;
+ case 10: return n == v;
+ case 11: return n != v;
+ case 12: return !z && (n == v);
+ case 13: return z && (n != v);
+ case 14: return 1;
+ case 15: return 0;
+ }
+ return 0;
+}
+
+static ulong
+thumbfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ char buf[8];
+
+ if(i->op == 30){ // BX
+ thumbrrh(nil, i);
+ sprint(buf, "R%ud", i->rn);
+ return rget(map, buf)&~1; // clear T bit
+ }
+ if(i->op == 57){ // Bcc
+ thumbbcc(nil, i);
+ if(thumbcondpass(map, rget, (i->w >> 8) & 0xf))
+ return i->imm;
+ return pc+2;
+ }
+ if(i->op == 58){ // B
+ thumbb(nil, i);
+ return i->imm;
+ }
+ if(i->op == 60){ // BL
+ thumbbl(nil, i);
+ return i->imm;
+ }
+ print("bad thumbfbranch call");
+ return 0;
+}
+
+static ulong
+thumbfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ char buf[8];
+ ulong rd;
+
+ thumbrrh(nil, i);
+ rd = i->rd;
+ if(rd != 15)
+ return pc+2;
+ sprint(buf, "R%ud", i->rn);
+ return rget(map, buf);
+}
+
+static ulong
+thumbfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
+{
+ char buf[8];
+ ulong rd, v;
+
+ thumbrrh(nil, i);
+ rd = i->rd;
+ if(rd != 15)
+ return pc+2;
+ sprint(buf, "R%ud", i->rn);
+ v = rget(map, buf);
+ sprint(buf, "R15");
+ return rget(map, buf) + v;
+}
+
+static void
+thumbshift(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->imm = B(10, 6);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbrrr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->rs = B(8, 6);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbirr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->imm = B(8, 6);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbir(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(10, 8);
+ i->imm = B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbrr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbrrh(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ if(B(6, 6))
+ i->rn += 8;
+ if(B(7, 7))
+ i->rd += 8;
+ if(o != nil){
+ if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770) // mov r6, pc or mov lr, pc or bx r6 or bx lr
+ format("RET", i, "");
+ else
+ format(o->o, i, o->a);
+ }
+}
+
+static void
+thumbpcrel(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rn = 15;
+ i->rd = B(10, 8);
+ i->imm = 4*(B(7, 0)+1);
+ if(i->addr & 3)
+ i->imm -= 2;
+ format(o->o, i, o->a);
+}
+
+static void
+thumbmovirr(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(2, 0);
+ i->rn = B(5, 3);
+ i->imm = B(10, 6);
+ if(strcmp(o->o, "MOVW") == 0)
+ i->imm *= 4;
+ else if(strncmp(o->o, "MOVH", 4) == 0)
+ i->imm *= 2;
+ format(o->o, i, o->a);
+}
+
+static void
+thumbmovsp(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rn = 13;
+ i->rd = B(10, 8);
+ i->imm = 4*B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbaddsppc(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->rd = B(10, 8);
+ i->imm = 4*B(7, 0);
+ if(i->op == 48)
+ i->imm += 4;
+ format(o->o, i, o->a);
+}
+
+static void
+thumbaddsp(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->imm = 4*B(6, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbswi(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ i->imm = B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbbcc(Opcode *o, Instr *i)
+{
+ int off, ins = i->w;
+
+ off = B(7, 0);
+ if(off & 0x80)
+ off |= 0xffffff00;
+ i->imm = i->addr + 2*off + 4;
+ if(o != nil)
+ format(o->o, i, o->a);
+}
+
+static void
+thumbb(Opcode *o, Instr *i)
+{
+ int off, ins = i->w;
+
+ off = B(10, 0);
+ if(off & 0x400)
+ off |= 0xfffff800;
+ i->imm = i->addr + 2*off + 4;
+ if(o != nil)
+ format(o->o, i, o->a);
+}
+
+static void
+thumbbl(Opcode *o, Instr *i)
+{
+ int off, h, ins = i->w;
+ static int reglink;
+
+ h = B(11, 11);
+ off = B(10, 0);
+ if(h == 0){
+ if(off & 0x400)
+ off |= 0xfffff800;
+ i->imm = i->addr + (off<<12) + 4;
+ reglink = i->imm;
+ }
+ else{
+ i->imm = reglink + 2*off;
+ }
+ if(o != nil)
+ format(o->o, i, o->a);
+}
+
+static void
+thumbregs(Opcode *o, Instr *i)
+{
+ int ins = i->w;
+
+ if(i->op == 52 || i->op == 53)
+ i->rd = 13;
+ else
+ i->rd = B(10, 8);
+ i->imm = B(7, 0);
+ format(o->o, i, o->a);
+}
+
+static void
+thumbunk(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static Opcode opcodes[] =
+{
+ "LSL", thumbshift, 0, "$#%i,R%n,R%d", // 0
+ "LSR", thumbshift, 0, "$#%i,R%n,R%d", // 1
+ "ASR", thumbshift, 0, "$#%i,R%n,R%d", // 2
+ "ADD", thumbrrr, 0, "R%s,R%n,R%d", // 3
+ "SUB", thumbrrr, 0, "R%s,R%n,R%d", // 4
+ "ADD", thumbirr, 0, "$#%i,R%n,R%d", // 5
+ "SUB", thumbirr, 0, "$#%i,R%n,R%d", // 6
+ "MOVW", thumbir, 0, "$#%i,R%d", // 7
+ "CMP", thumbir, 0, "$#%i,R%d", // 8
+ "ADD", thumbir, 0, "$#%i,R%d,R%d", // 9
+ "SUB", thumbir, 0, "$#%i,R%d,R%d", // 10
+ "AND", thumbrr, 0, "R%n,R%d,R%d", // 11
+ "EOR", thumbrr, 0, "R%n,R%d,R%d", // 12
+ "LSL", thumbrr, 0, "R%n,R%d,R%d", // 13
+ "LSR", thumbrr, 0, "R%n,R%d,R%d", // 14
+ "ASR", thumbrr, 0, "R%n,R%d,R%d", // 15
+ "ADC", thumbrr, 0, "R%n,R%d,R%d", // 16
+ "SBC", thumbrr, 0, "R%n,R%d,R%d", // 17
+ "ROR", thumbrr, 0, "R%n,R%d,R%d", // 18
+ "TST", thumbrr, 0, "R%n,R%d", // 19
+ "NEG", thumbrr, 0, "R%n,R%d", // 20
+ "CMP", thumbrr, 0, "R%n,R%d", // 21
+ "CMPN", thumbrr, 0, "R%n,R%d", // 22
+ "OR", thumbrr, 0, "R%n,R%d,R%d", // 23
+ "MUL", thumbrr, 0, "R%n,R%d,R%d", // 24
+ "BITC", thumbrr, 0, "R%n,R%d,R%d", // 25
+ "MOVN", thumbrr, 0, "R%n,R%d", // 26
+ "ADD", thumbrrh, thumbfadd, "R%n,R%d,R%d", // 27
+ "CMP", thumbrrh, 0, "R%n,R%d", // 28
+ "MOVW", thumbrrh, thumbfmov, "R%n,R%d", // 29
+ "BX", thumbrrh, thumbfbranch, "R%n", // 30
+ "MOVW", thumbpcrel, 0, "$%I,R%d", // 31
+ "MOVW", thumbrrr, 0, "R%d, [R%s,R%n]", // 32
+ "MOVH", thumbrrr, 0, "R%d, [R%s,R%n]", // 33
+ "MOVB", thumbrrr, 0, "R%d, [R%s,R%n]", // 34
+ "MOVB", thumbrrr, 0, "[R%s,R%n],R%d", // 35
+ "MOVW", thumbrrr, 0, "[R%s,R%n],R%d", // 36
+ "MOVHU", thumbrrr, 0, "[R%s,R%n],R%d", // 37
+ "MOVBU", thumbrrr, 0, "[R%s,R%n],R%d", // 38
+ "MOVH", thumbrrr, 0, "[R%s,R%n],R%d", // 39
+ "MOVW", thumbmovirr, 0, "R%d,%I", // 40
+ "MOVW", thumbmovirr, 0, "%I,R%d", // 41
+ "MOVB", thumbmovirr, 0, "R%d,%I", // 42
+ "MOVBU", thumbmovirr, 0, "$%I,R%d", // 43
+ "MOVH", thumbmovirr, 0, "R%d,%I", // 44
+ "MOVHU", thumbmovirr, 0, "%I,R%d", // 45
+ "MOVW", thumbmovsp, 0, "R%d,%I", // 46
+ "MOVW", thumbmovsp, 0, "%I,R%d", // 47
+ "ADD", thumbaddsppc,0, "$#%i,PC,R%d", // 48
+ "ADD", thumbaddsppc,0, "$#%i,SP,R%d", // 49
+ "ADD", thumbaddsp, 0, "$#%i,SP,SP", // 50
+ "SUB", thumbaddsp, 0, "$#%i,SP,SP", // 51
+ "PUSH", thumbregs, 0, "R%d, %r", // 52
+ "POP", thumbregs, 0, "R%d, %r", // 53
+ "STMIA", thumbregs, 0, "R%d, %r", // 54
+ "LDMIA", thumbregs, 0, "R%d, %r", // 55
+ "SWI", thumbswi, 0, "$#%i", // 56
+ "B%c", thumbbcc, thumbfbranch, "%b", // 57
+ "B", thumbb, thumbfbranch, "%b", // 58
+ "BL", thumbbl, 0, "", // 59
+ "BL", thumbbl, thumbfbranch, "%b", // 60
+ "UNK", thumbunk, 0, "", // 61
+};
+
+static void
+gaddr(Instr *i)
+{
+ *i->curr++ = '$';
+ i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
+}
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int j, k, m, n;
+ int g;
+ char *fmt;
+ int ins = i->w;
+
+ if(mnemonic)
+ format(0, i, mnemonic);
+ if(f == 0)
+ return;
+ if(mnemonic)
+ if(i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if(*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 'c': /*Bcc */
+ bprint(i, "%s", cond[B(11, 8)]);
+ break;
+
+ case 's':
+ bprint(i, "%d", i->rs);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->rn);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'i':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'b':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ i->imm, CTEXT);
+ break;
+
+ case 'I':
+ if (i->rn == 13) {
+ if (plocal(i))
+ break;
+ }
+ g = 0;
+ fmt = "#%lx(R%d)";
+ if (i->rn == 15) {
+ /* convert load of offset(PC) to a load immediate */
+ if (get4(i->map, i->addr + i->imm, &i->imm) > 0)
+ {
+ g = 1;
+ fmt = "";
+ }
+ }
+ if (mach->sb)
+ {
+ if (i->rn == 12)
+ {
+ i->imm += mach->sb;
+ g = 1;
+ fmt = "-SB(SB)";
+ }
+ }
+ if (g)
+ {
+ gaddr(i);
+ bprint(i, fmt, i->rn);
+ }
+ else
+ bprint(i, fmt, i->imm, i->rn);
+ break;
+
+ case 'r':
+ n = i->imm&0xff;
+ j = 0;
+ k = 0;
+ while(n) {
+ m = j;
+ while(n&0x1) {
+ j++;
+ n >>= 1;
+ }
+ if(j != m) {
+ if(k)
+ bprint(i, ",");
+ if(j == m+1)
+ bprint(i, "R%d", m);
+ else
+ bprint(i, "R%d-R%d", m, j-1);
+ k = 1;
+ }
+ j++;
+ n >>= 1;
+ }
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n-1;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+
+ (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
+ return 2;
+}
+
+static int
+thumbinst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ USED(modifier);
+ return printins(map, pc, buf, n);
+}
+
+static int
+thumbdas(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ if(i.end-i.curr > 8)
+ i.curr = _hexify(buf, i.w, 7);
+ *i.curr = 0;
+ return 2;
+}
+
+static int
+thumbinstlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ return 2;
+}
+
+static int
+thumbfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ ulong d;
+ Instr i;
+
+ if(decode(map, pc, &i) < 0)
+ return -1;
+
+ if(opcodes[i.op].foll) {
+ d = (*opcodes[i.op].foll)(map, rget, &i, pc);
+ if(d == -1)
+ return -1;
+ } else
+ d = pc+2;
+
+ foll[0] = d;
+ return 1;
+}
diff --git a/utils/libmach/tobj.c b/utils/libmach/tobj.c
new file mode 100644
index 00000000..d18de434
--- /dev/null
+++ b/utils/libmach/tobj.c
@@ -0,0 +1,133 @@
+/*
+ * 5obj.c - identify and parse a arm object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "5c/5.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_ist(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_readt(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 6); /* scond(1), reg(1), lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_SHIFT:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/ureg2.h b/utils/libmach/ureg2.h
new file mode 100644
index 00000000..e237cb3d
--- /dev/null
+++ b/utils/libmach/ureg2.h
@@ -0,0 +1,28 @@
+struct Ureg
+{
+ ulong r0;
+ ulong r1;
+ ulong r2;
+ ulong r3;
+ ulong r4;
+ ulong r5;
+ ulong r6;
+ ulong r7;
+ ulong a0;
+ ulong a1;
+ ulong a2;
+ ulong a3;
+ ulong a4;
+ ulong a5;
+ ulong a6;
+ ulong sp;
+ ulong usp;
+ ulong magic; /* for db to find bottom of ureg */
+ ushort sr;
+ ulong pc;
+ ushort vo;
+#ifndef UREGVARSZ
+#define UREGVARSZ 23 /* for 68040; 15 is enough on 68020 */
+#endif
+ uchar microstate[UREGVARSZ]; /* variable-sized portion */
+};
diff --git a/utils/libmach/ureg4.h b/utils/libmach/ureg4.h
new file mode 100644
index 00000000..5f95dcd9
--- /dev/null
+++ b/utils/libmach/ureg4.h
@@ -0,0 +1,46 @@
+struct Ureg
+{
+ ulong status;
+ long pc;
+ union
+ {
+ long sp; /* r29 */
+ long usp; /* r29 */
+ } u0;
+ ulong cause;
+ ulong badvaddr;
+ ulong tlbvirt;
+
+ long hhi; long hi;
+ long hlo; long lo;
+ long hr31; long r31;
+ long hr30; long r30;
+ long hr28; long r28;
+ long hr27; long r27;
+ long hr26; long r26;
+ long hr25; long r25;
+ long hr24; long r24;
+ long hr23; long r23;
+ long hr22; long r22;
+ long hr21; long r21;
+ long hr20; long r20;
+ long hr19; long r19;
+ long hr18; long r18;
+ long hr17; long r17;
+ long hr16; long r16;
+ long hr15; long r15;
+ long hr14; long r14;
+ long hr13; long r13;
+ long hr12; long r12;
+ long hr11; long r11;
+ long hr10; long r10;
+ long hr9; long r9;
+ long hr8; long r8;
+ long hr7; long r7;
+ long hr6; long r6;
+ long hr5; long r5;
+ long hr4; long r4;
+ long hr3; long r3;
+ long hr2; long r2;
+ long hr1; long r1;
+};
diff --git a/utils/libmach/ureg5.h b/utils/libmach/ureg5.h
new file mode 100644
index 00000000..ffdad423
--- /dev/null
+++ b/utils/libmach/ureg5.h
@@ -0,0 +1,21 @@
+struct Ureg {
+ uint r0;
+ uint r1;
+ uint r2;
+ uint r3;
+ uint r4;
+ uint r5;
+ uint r6;
+ uint r7;
+ uint r8;
+ uint r9;
+ uint r10;
+ uint r11;
+ uint r12;
+ uint r13;
+ uint r14;
+ uint link;
+ uint type;
+ uint psr;
+ uint pc;
+};
diff --git a/utils/libmach/ureg6.h b/utils/libmach/ureg6.h
new file mode 100644
index 00000000..46fa1f61
--- /dev/null
+++ b/utils/libmach/ureg6.h
@@ -0,0 +1,30 @@
+struct Ureg
+{
+ uvlong r15; /* general registers */
+ uvlong r14;
+ uvlong r13;
+ uvlong r12;
+ uvlong r11;
+ uvlong r10;
+ uvlong r9;
+ uvlong r8;
+ uvlong di;
+ uvlong si; /* ... */
+ uvlong bp; /* ... */
+ uvlong nsp;
+ uvlong bx; /* ... */
+ uvlong dx; /* ... */
+ uvlong cx; /* ... */
+ uvlong ax; /* ... */
+ uvlong gs; /* data segments */
+ uvlong fs; /* ... */
+ uvlong es; /* ... */
+ uvlong ds; /* ... */
+ uvlong trap; /* trap type */
+ uvlong ecode; /* error code (or zero) */
+ uvlong pc; /* pc */
+ uvlong cs; /* old context */
+ uvlong flags; /* old flags */
+ uvlong sp;
+ uvlong ss; /* old stack segment */
+};
diff --git a/utils/libmach/ureg8.h b/utils/libmach/ureg8.h
new file mode 100644
index 00000000..8bdf178d
--- /dev/null
+++ b/utils/libmach/ureg8.h
@@ -0,0 +1,25 @@
+struct Ureg
+{
+ ulong di; /* general registers */
+ ulong si; /* ... */
+ ulong bp; /* ... */
+ ulong nsp;
+ ulong bx; /* ... */
+ ulong dx; /* ... */
+ ulong cx; /* ... */
+ ulong ax; /* ... */
+ ulong gs; /* data segments */
+ ulong fs; /* ... */
+ ulong es; /* ... */
+ ulong ds; /* ... */
+ ulong trap; /* trap type */
+ ulong ecode; /* error code (or zero) */
+ ulong pc; /* pc */
+ ulong cs; /* old context */
+ ulong flags; /* old flags */
+ union {
+ ulong usp;
+ ulong sp;
+ } u0;
+ ulong ss; /* old stack segment */
+};
diff --git a/utils/libmach/uregk.h b/utils/libmach/uregk.h
new file mode 100644
index 00000000..4ff12edc
--- /dev/null
+++ b/utils/libmach/uregk.h
@@ -0,0 +1,45 @@
+struct Ureg
+{
+ ulong r0; /* unnecessary; just for symmetry */
+ union{
+ ulong sp; /* r1 */
+ ulong usp; /* r1 */
+ ulong r1;
+ } u0;
+ ulong r2;
+ ulong r3;
+ ulong r4;
+ ulong r5;
+ ulong r6;
+ ulong r7;
+ ulong r8;
+ ulong r9;
+ ulong r10;
+ ulong r11;
+ ulong r12;
+ ulong r13;
+ ulong r14;
+ ulong r15;
+ ulong r16;
+ ulong r17;
+ ulong r18;
+ ulong r19;
+ ulong r20;
+ ulong r21;
+ ulong r22;
+ ulong r23;
+ ulong r24;
+ ulong r25;
+ ulong r26;
+ ulong r27;
+ ulong r28;
+ ulong r29;
+ ulong r30;
+ ulong r31;
+ ulong y;
+ ulong tbr;
+ ulong psr;
+ ulong npc;
+ ulong pc;
+ ulong pad; /* so structure is double word aligned */
+};
diff --git a/utils/libmach/uregq.h b/utils/libmach/uregq.h
new file mode 100644
index 00000000..409b13d3
--- /dev/null
+++ b/utils/libmach/uregq.h
@@ -0,0 +1,43 @@
+struct Ureg
+{
+ ulong cause;
+ ulong status;
+ ulong pc; /* SRR0 */
+ ulong pad;
+ ulong lr;
+ ulong cr;
+ ulong xer;
+ ulong ctr;
+ ulong r0;
+ ulong sp;
+ ulong r2;
+ ulong r3;
+ ulong r4;
+ ulong r5;
+ ulong r6;
+ ulong r7;
+ ulong r8;
+ ulong r9;
+ ulong r10;
+ ulong r11;
+ ulong r12;
+ ulong r13;
+ ulong r14;
+ ulong r15;
+ ulong r16;
+ ulong r17;
+ ulong r18;
+ ulong r19;
+ ulong r20;
+ ulong r21;
+ ulong r22;
+ ulong r23;
+ ulong r24;
+ ulong r25;
+ ulong r26;
+ ulong r27;
+ ulong r28;
+ ulong r29;
+ ulong r30;
+ ulong r31;
+};
diff --git a/utils/libmach/uregt.h b/utils/libmach/uregt.h
new file mode 100644
index 00000000..ffdad423
--- /dev/null
+++ b/utils/libmach/uregt.h
@@ -0,0 +1,21 @@
+struct Ureg {
+ uint r0;
+ uint r1;
+ uint r2;
+ uint r3;
+ uint r4;
+ uint r5;
+ uint r6;
+ uint r7;
+ uint r8;
+ uint r9;
+ uint r10;
+ uint r11;
+ uint r12;
+ uint r13;
+ uint r14;
+ uint link;
+ uint type;
+ uint psr;
+ uint pc;
+};
diff --git a/utils/libmach/uregv.h b/utils/libmach/uregv.h
new file mode 100644
index 00000000..def45d2d
--- /dev/null
+++ b/utils/libmach/uregv.h
@@ -0,0 +1,44 @@
+struct Ureg
+{
+ ulong status;
+ ulong pc;
+ union{
+ ulong sp; /* r29 */
+ ulong usp; /* r29 */
+ } u0;
+ ulong cause;
+ ulong badvaddr;
+ ulong tlbvirt;
+ ulong hi;
+ ulong lo;
+ ulong r31;
+ ulong r30;
+ ulong r28;
+ ulong r27; /* unused */
+ ulong r26; /* unused */
+ ulong r25;
+ ulong r24;
+ ulong r23;
+ ulong r22;
+ ulong r21;
+ ulong r20;
+ ulong r19;
+ ulong r18;
+ ulong r17;
+ ulong r16;
+ ulong r15;
+ ulong r14;
+ ulong r13;
+ ulong r12;
+ ulong r11;
+ ulong r10;
+ ulong r9;
+ ulong r8;
+ ulong r7;
+ ulong r6;
+ ulong r5;
+ ulong r4;
+ ulong r3;
+ ulong r2;
+ ulong r1;
+};
diff --git a/utils/libmach/v.c b/utils/libmach/v.c
new file mode 100644
index 00000000..add94113
--- /dev/null
+++ b/utils/libmach/v.c
@@ -0,0 +1,116 @@
+/*
+ * mips definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "uregv.h"
+#include "mach.h"
+
+#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x)
+
+#define SP REGOFF(u0.sp)
+#define PC REGOFF(pc)
+#define R1 REGOFF(r1)
+#define R31 REGOFF(r31)
+#define FP_REG(x) (R1+4+4*(x))
+
+#define REGSIZE sizeof(struct Ureg)
+#define FPREGSIZE (4*33)
+
+Reglist mipsreglist[] = {
+ {"STATUS", REGOFF(status), RINT|RRDONLY, 'X'},
+ {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'},
+ {"BADVADDR", REGOFF(badvaddr), RINT|RRDONLY, 'X'},
+ {"TLBVIRT", REGOFF(tlbvirt), RINT|RRDONLY, 'X'},
+ {"HI", REGOFF(hi), RINT|RRDONLY, 'X'},
+ {"LO", REGOFF(lo), RINT|RRDONLY, 'X'},
+ {"PC", PC, RINT, 'X'},
+ {"SP", SP, RINT, 'X'},
+ {"R31", R31, RINT, 'X'},
+ {"R30", REGOFF(r30), RINT, 'X'},
+ {"R28", REGOFF(r28), RINT, 'X'},
+ {"R27", REGOFF(r27), RINT, 'X'},
+ {"R26", REGOFF(r26), RINT, 'X'},
+ {"R25", REGOFF(r25), RINT, 'X'},
+ {"R24", REGOFF(r24), RINT, 'X'},
+ {"R23", REGOFF(r23), RINT, 'X'},
+ {"R22", REGOFF(r22), RINT, 'X'},
+ {"R21", REGOFF(r21), RINT, 'X'},
+ {"R20", REGOFF(r20), RINT, 'X'},
+ {"R19", REGOFF(r19), RINT, 'X'},
+ {"R18", REGOFF(r18), RINT, 'X'},
+ {"R17", REGOFF(r17), RINT, 'X'},
+ {"R16", REGOFF(r16), RINT, 'X'},
+ {"R15", REGOFF(r15), RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ {"F0", FP_REG(0), RFLT, 'F'},
+ {"F1", FP_REG(1), RFLT, 'f'},
+ {"F2", FP_REG(2), RFLT, 'F'},
+ {"F3", FP_REG(3), RFLT, 'f'},
+ {"F4", FP_REG(4), RFLT, 'F'},
+ {"F5", FP_REG(5), RFLT, 'f'},
+ {"F6", FP_REG(6), RFLT, 'F'},
+ {"F7", FP_REG(7), RFLT, 'f'},
+ {"F8", FP_REG(8), RFLT, 'F'},
+ {"F9", FP_REG(9), RFLT, 'f'},
+ {"F10", FP_REG(10), RFLT, 'F'},
+ {"F11", FP_REG(11), RFLT, 'f'},
+ {"F12", FP_REG(12), RFLT, 'F'},
+ {"F13", FP_REG(13), RFLT, 'f'},
+ {"F14", FP_REG(14), RFLT, 'F'},
+ {"F15", FP_REG(15), RFLT, 'f'},
+ {"F16", FP_REG(16), RFLT, 'F'},
+ {"F17", FP_REG(17), RFLT, 'f'},
+ {"F18", FP_REG(18), RFLT, 'F'},
+ {"F19", FP_REG(19), RFLT, 'f'},
+ {"F20", FP_REG(20), RFLT, 'F'},
+ {"F21", FP_REG(21), RFLT, 'f'},
+ {"F22", FP_REG(22), RFLT, 'F'},
+ {"F23", FP_REG(23), RFLT, 'f'},
+ {"F24", FP_REG(24), RFLT, 'F'},
+ {"F25", FP_REG(25), RFLT, 'f'},
+ {"F26", FP_REG(26), RFLT, 'F'},
+ {"F27", FP_REG(27), RFLT, 'f'},
+ {"F28", FP_REG(28), RFLT, 'F'},
+ {"F29", FP_REG(29), RFLT, 'f'},
+ {"F30", FP_REG(30), RFLT, 'F'},
+ {"F31", FP_REG(31), RFLT, 'f'},
+ {"FPCR", FP_REG(32), RFLT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mmips =
+{
+ "mips",
+ MMIPS, /* machine type */
+ mipsreglist, /* register set */
+ REGSIZE, /* number of bytes in reg set */
+ FPREGSIZE, /* number of bytes in fp reg set */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R31", /* name of link register */
+ "setR30", /* static base register name */
+ 0, /* value */
+ 0x1000, /* page size */
+ 0xC0000000, /* kernel base */
+ 0x40000000, /* kernel text mask */
+ 4, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/vcodas.c b/utils/libmach/vcodas.c
new file mode 100644
index 00000000..ce505ea2
--- /dev/null
+++ b/utils/libmach/vcodas.c
@@ -0,0 +1,553 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+
+ /* mips native disassembler */
+
+typedef struct {
+ long addr; /* pc of instr */
+ uchar op; /* bits 31-26 */
+ uchar rs; /* bits 25-21 */
+ uchar rt; /* bits 20-16 */
+ uchar rd; /* bits 15-11 */
+ uchar sa; /* bits 10-6 */
+ uchar function; /* bits 5-0 */
+ long immediate; /* bits 15-0 */
+ ulong cofun; /* bits 24-0 */
+ ulong target; /* bits 25-0 */
+ long w0;
+ char *curr; /* current fill point */
+ char *end; /* end of buffer */
+ char *err;
+} Instr;
+
+typedef struct {
+ char *mnemonic;
+ char *mipsco;
+} Opcode;
+
+static char mipscoload[] = "r%t,%l";
+static char mipscoalui[] = "r%t,r%s,%i";
+static char mipscoalu3op[] = "r%d,r%s,r%t";
+static char mipscoboc[] = "r%s,r%t,%b";
+static char mipscoboc0[] = "r%s,%b";
+static char mipscorsrt[] = "r%s,r%t";
+static char mipscorsi[] = "r%s,%i";
+static char mipscoxxx[] = "%w";
+static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */
+static char mipscofp2[] = "f%a,f%d"; /* fd,fs */
+static char mipscofpc[] = "f%d,f%t"; /* fs,ft */
+
+static Opcode opcodes[64] = {
+ 0, 0,
+ 0, 0,
+ "j", "%j",
+ "jal", "%j",
+ "beq", mipscoboc,
+ "bne", mipscoboc,
+ "blez", mipscoboc0,
+ "bgtz", mipscoboc0,
+ "addi", mipscoalui,
+ "addiu", mipscoalui,
+ "slti", mipscoalui,
+ "sltiu", mipscoalui,
+ "andi", mipscoalui,
+ "ori", mipscoalui,
+ "xori", mipscoalui,
+ "lui", "r%t,%u",
+ "cop0", 0,
+ "cop1", 0,
+ "cop2", 0,
+ "cop3", 0,
+ "beql", mipscoboc,
+ "bnel", mipscoboc,
+ "blezl", mipscoboc0,
+ "bgtzl", mipscoboc0,
+ "instr18", mipscoxxx,
+ "instr19", mipscoxxx,
+ "instr1A", mipscoxxx,
+ "instr1B", mipscoxxx,
+ "instr1C", mipscoxxx,
+ "instr1D", mipscoxxx,
+ "instr1E", mipscoxxx,
+ "instr1F", mipscoxxx,
+ "lb", mipscoload,
+ "lh", mipscoload,
+ "lwl", mipscoload,
+ "lw", mipscoload,
+ "lbu", mipscoload,
+ "lhu", mipscoload,
+ "lwr", mipscoload,
+ "instr27", mipscoxxx,
+ "sb", mipscoload,
+ "sh", mipscoload,
+ "swl", mipscoload,
+ "sw", mipscoload,
+ "instr2C", mipscoxxx,
+ "instr2D", mipscoxxx,
+ "swr", mipscoload,
+ "cache", "",
+ "ll", mipscoload,
+ "lwc1", mipscoload,
+ "lwc2", mipscoload,
+ "lwc3", mipscoload,
+ "instr34", mipscoxxx,
+ "ld", mipscoload,
+ "ld", mipscoload,
+ "ld", mipscoload,
+ "sc", mipscoload,
+ "swc1", mipscoload,
+ "swc2", mipscoload,
+ "swc3", mipscoload,
+ "instr3C", mipscoxxx,
+ "sd", mipscoload,
+ "sd", mipscoload,
+ "sd", mipscoload,
+};
+
+static Opcode sopcodes[64] = {
+ "sll", "r%d,r%t,$%a",
+ "special01", mipscoxxx,
+ "srl", "r%d,r%t,$%a",
+ "sra", "r%d,r%t,$%a",
+ "sllv", "r%d,r%t,R%s",
+ "special05", mipscoxxx,
+ "srlv", "r%d,r%t,r%s",
+ "srav", "r%d,r%t,r%s",
+ "jr", "r%s",
+ "jalr", "r%d,r%s",
+ "special0A", mipscoxxx,
+ "special0B", mipscoxxx,
+ "syscall", "",
+ "break", "",
+ "special0E", mipscoxxx,
+ "sync", "",
+ "mfhi", "r%d",
+ "mthi", "r%s",
+ "mflo", "r%d",
+ "mtlo", "r%s",
+ "special14", mipscoxxx,
+ "special15", mipscoxxx,
+ "special16", mipscoxxx,
+ "special17", mipscoxxx,
+ "mult", mipscorsrt,
+ "multu", mipscorsrt,
+ "div", mipscorsrt,
+ "divu", mipscorsrt,
+ "special1C", mipscoxxx,
+ "special1D", mipscoxxx,
+ "special1E", mipscoxxx,
+ "special1F", mipscoxxx,
+ "add", mipscoalu3op,
+ "addu", mipscoalu3op,
+ "sub", mipscoalu3op,
+ "subu", mipscoalu3op,
+ "and", mipscoalu3op,
+ "or", mipscoalu3op,
+ "xor", mipscoalu3op,
+ "nor", mipscoalu3op,
+ "special28", mipscoxxx,
+ "special29", mipscoxxx,
+ "slt", mipscoalu3op,
+ "sltu", mipscoalu3op,
+ "special2C", mipscoxxx,
+ "special2D", mipscoxxx,
+ "special2E", mipscoxxx,
+ "special2F", mipscoxxx,
+ "tge", mipscorsrt,
+ "tgeu", mipscorsrt,
+ "tlt", mipscorsrt,
+ "tltu", mipscorsrt,
+ "teq", mipscorsrt,
+ "special35", mipscoxxx,
+ "tne", mipscorsrt,
+ "special37", mipscoxxx,
+ "special38", mipscoxxx,
+ "special39", mipscoxxx,
+ "special3A", mipscoxxx,
+ "special3B", mipscoxxx,
+ "special3C", mipscoxxx,
+ "special3D", mipscoxxx,
+ "special3E", mipscoxxx,
+ "special3F", mipscoxxx,
+};
+
+static Opcode ropcodes[32] = {
+ "bltz", mipscoboc0,
+ "bgez", mipscoboc0,
+ "bltzl", mipscoboc0,
+ "bgezl", mipscoboc0,
+ "regimm04", mipscoxxx,
+ "regimm05", mipscoxxx,
+ "regimm06", mipscoxxx,
+ "regimm07", mipscoxxx,
+ "tgei", mipscorsi,
+ "tgeiu", mipscorsi,
+ "tlti", mipscorsi,
+ "tltiu", mipscorsi,
+ "teqi", mipscorsi,
+ "regimm0D", mipscoxxx,
+ "tnei", mipscorsi,
+ "regimm0F", mipscoxxx,
+ "bltzal", mipscoboc0,
+ "bgezal", mipscoboc0,
+ "bltzall", mipscoboc0,
+ "bgezall", mipscoboc0,
+ "regimm14", mipscoxxx,
+ "regimm15", mipscoxxx,
+ "regimm16", mipscoxxx,
+ "regimm17", mipscoxxx,
+ "regimm18", mipscoxxx,
+ "regimm19", mipscoxxx,
+ "regimm1A", mipscoxxx,
+ "regimm1B", mipscoxxx,
+ "regimm1C", mipscoxxx,
+ "regimm1D", mipscoxxx,
+ "regimm1E", mipscoxxx,
+ "regimm1F", mipscoxxx,
+};
+
+static Opcode fopcodes[64] = {
+ "add.%f", mipscofp3,
+ "sub.%f", mipscofp3,
+ "mul.%f", mipscofp3,
+ "div.%f", mipscofp3,
+ "sqrt.%f", mipscofp2,
+ "abs.%f", mipscofp2,
+ "mov.%f", mipscofp2,
+ "neg.%f", mipscofp2,
+ "finstr08", mipscoxxx,
+ "finstr09", mipscoxxx,
+ "finstr0A", mipscoxxx,
+ "finstr0B", mipscoxxx,
+ "round.w.%f", mipscofp2,
+ "trunc.w%f", mipscofp2,
+ "ceil.w%f", mipscofp2,
+ "floor.w%f", mipscofp2,
+ "finstr10", mipscoxxx,
+ "finstr11", mipscoxxx,
+ "finstr12", mipscoxxx,
+ "finstr13", mipscoxxx,
+ "finstr14", mipscoxxx,
+ "finstr15", mipscoxxx,
+ "finstr16", mipscoxxx,
+ "finstr17", mipscoxxx,
+ "finstr18", mipscoxxx,
+ "finstr19", mipscoxxx,
+ "finstr1A", mipscoxxx,
+ "finstr1B", mipscoxxx,
+ "finstr1C", mipscoxxx,
+ "finstr1D", mipscoxxx,
+ "finstr1E", mipscoxxx,
+ "finstr1F", mipscoxxx,
+ "cvt.s.%f", mipscofp2,
+ "cvt.d.%f", mipscofp2,
+ "cvt.e.%f", mipscofp2,
+ "cvt.q.%f", mipscofp2,
+ "cvt.w.%f", mipscofp2,
+ "finstr25", mipscoxxx,
+ "finstr26", mipscoxxx,
+ "finstr27", mipscoxxx,
+ "finstr28", mipscoxxx,
+ "finstr29", mipscoxxx,
+ "finstr2A", mipscoxxx,
+ "finstr2B", mipscoxxx,
+ "finstr2C", mipscoxxx,
+ "finstr2D", mipscoxxx,
+ "finstr2E", mipscoxxx,
+ "finstr2F", mipscoxxx,
+ "c.f.%f", mipscofpc,
+ "c.un.%f", mipscofpc,
+ "c.eq.%f", mipscofpc,
+ "c.ueq.%f", mipscofpc,
+ "c.olt.%f", mipscofpc,
+ "c.ult.%f", mipscofpc,
+ "c.ole.%f", mipscofpc,
+ "c.ule.%f", mipscofpc,
+ "c.sf.%f", mipscofpc,
+ "c.ngle.%f", mipscofpc,
+ "c.seq.%f", mipscofpc,
+ "c.ngl.%f", mipscofpc,
+ "c.lt.%f", mipscofpc,
+ "c.nge.%f", mipscofpc,
+ "c.le.%f", mipscofpc,
+ "c.ngt.%f", mipscofpc,
+};
+
+static char fsub[16] = {
+ 's', 'd', 'e', 'q', 'w', '?', '?', '?',
+ '?', '?', '?', '?', '?', '?', '?', '?'
+};
+
+
+static int
+mkinstr(Instr *i, Map *map, ulong pc)
+{
+ long w;
+
+ if (get4(map, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->addr = pc;
+ i->op = (w >> 26) & 0x3F;
+ i->rs = (w >> 21) & 0x1F;
+ i->rt = (w >> 16) & 0x1F;
+ i->rd = (w >> 11) & 0x1F;
+ i->sa = (w >> 6) & 0x1F;
+ i->function = w & 0x3F;
+ i->immediate = w & 0x0000FFFF;
+ if (i->immediate & 0x8000)
+ i->immediate |= ~0x0000FFFF;
+ i->cofun = w & 0x01FFFFFF;
+ i->target = w & 0x03FFFFFF;
+ i->w0 = w;
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if (*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 's':
+ bprint(i, "%d", i->rs);
+ break;
+
+ case 't':
+ bprint(i, "%d", i->rt);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->sa);
+ break;
+
+ case 'l':
+ if (i->rs == 30) {
+ i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
+ bprint(i, "(SB)");
+ } else
+ bprint(i, "%lx(r%d)", i->immediate, i->rs);
+ break;
+
+ case 'i':
+ bprint(i, "$%lx", i->immediate);
+ break;
+
+ case 'u':
+ *i->curr++ = '$';
+ i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
+ bprint(i, "(SB)");
+ break;
+
+ case 'j':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ (i->target<<2)|(i->addr & 0xF0000000), CANY);
+ bprint(i, "(SB)");
+ break;
+
+ case 'b':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ (i->immediate<<2)+i->addr+4, CANY);
+ break;
+
+ case 'c':
+ bprint(i, "%lux", i->cofun);
+ break;
+
+ case 'w':
+ bprint(i, "[%lux]", i->w0);
+ break;
+
+ case 'f':
+ *i->curr++ = fsub[i->rs & 0x0F];
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+static void
+copz(int cop, Instr *i)
+{
+ char *f, *m, buf[16];
+
+ m = buf;
+ f = "%t,%d";
+ switch (i->rs) {
+
+ case 0:
+ sprint(buf, "mfc%d", cop);
+ break;
+
+ case 2:
+ sprint(buf, "cfc%d", cop);
+ break;
+
+ case 4:
+ sprint(buf, "mtc%d", cop);
+ break;
+
+ case 6:
+ sprint(buf, "ctc%d", cop);
+ break;
+
+ case 8:
+ f = "%b";
+ switch (i->rt) {
+
+ case 0:
+ sprint(buf, "bc%df", cop);
+ break;
+
+ case 1:
+ sprint(buf, "bc%dt", cop);
+ break;
+
+ case 2:
+ sprint(buf, "bc%dfl", cop);
+ break;
+
+ case 3:
+ sprint(buf, "bc%dtl", cop);
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ f = mipscoxxx;
+ break;
+ }
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ if (i->rs & 0x10)
+ f = "function %c";
+ else
+ f = mipscoxxx;
+ break;
+ }
+ format(m, i, f);
+}
+
+static void
+cop0(Instr *i)
+{
+ char *m = 0;
+
+ if (i->rs >= 0x10) {
+ switch (i->cofun) {
+
+ case 1:
+ m = "tlbr";
+ break;
+
+ case 2:
+ m = "tlbwi";
+ break;
+
+ case 6:
+ m = "tlbwr";
+ break;
+
+ case 8:
+ m = "tlbp";
+ break;
+
+ case 16:
+ m = "rfe";
+ break;
+
+ case 32:
+ m = "eret";
+ break;
+ }
+ if (m) {
+ format(m, i, 0);
+ if (i->curr < i->end)
+ *i->curr++ = 0;
+ return;
+ }
+ }
+ copz(0, i);
+}
+
+int
+_mipscoinst(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+ Opcode *o;
+ uchar op;
+
+ i.curr = buf;
+ i.end = buf+n-1;
+ if (mkinstr(&i, map, pc) < 0)
+ return -1;
+ switch (i.op) {
+
+ case 0x00: /* SPECIAL */
+ o = sopcodes;
+ op = i.function;
+ break;
+
+ case 0x01: /* REGIMM */
+ o = ropcodes;
+ op = i.rt;
+ break;
+
+ case 0x10: /* COP0 */
+ cop0(&i);
+ return 4;
+
+ case 0x11: /* COP1 */
+ if (i.rs & 0x10) {
+ o = fopcodes;
+ op = i.function;
+ break;
+ }
+ /*FALLTHROUGH*/
+ case 0x12: /* COP2 */
+ case 0x13: /* COP3 */
+ copz(i.op-0x10, &i);
+ return 4;
+
+ default:
+ o = opcodes;
+ op = i.op;
+ break;
+ }
+ format(o[op].mnemonic, &i, o[op].mipsco);
+ return 4;
+}
diff --git a/utils/libmach/vdb.c b/utils/libmach/vdb.c
new file mode 100644
index 00000000..0624a106
--- /dev/null
+++ b/utils/libmach/vdb.c
@@ -0,0 +1,1094 @@
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+/*
+ * Mips-specific debugger interface
+ */
+
+extern char *mipsexcep(Map*, Rgetter);
+extern int mipsfoll(Map*, ulong, Rgetter, ulong*);
+extern int mipsinst(Map*, ulong, char, char*, int);
+extern int mipsdas(Map*, ulong, char*, int);
+extern int mipsinstlen(Map*, ulong);
+/*
+ * Debugger interface
+ */
+Machdata mipsmach =
+{
+ {0, 0, 0, 0xD}, /* break point */
+ 4, /* break point size */
+
+ beswab, /* short to local byte order */
+ beswal, /* long to local byte order */
+ beswav, /* vlong to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ mipsexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ beieeesftos, /* single precision float printer */
+ beieeedftos, /* double precisioin float printer */
+ mipsfoll, /* following addresses */
+ mipsinst, /* print instruction */
+ mipsdas, /* dissembler */
+ mipsinstlen, /* instruction size */
+};
+
+static char *excname[] =
+{
+ "external interrupt",
+ "TLB modification",
+ "TLB miss (load or fetch)",
+ "TLB miss (store)",
+ "address error (load or fetch)",
+ "address error (store)",
+ "bus error (fetch)",
+ "bus error (data load or store)",
+ "system call",
+ "breakpoint",
+ "reserved instruction",
+ "coprocessor unusable",
+ "arithmetic overflow",
+ "undefined 13",
+ "undefined 14",
+ "system call",
+ /* the following is made up */
+ "floating point exception" /* FPEXC */
+};
+
+char*
+mipsexcep(Map *map, Rgetter rget)
+{
+ int e;
+ long c;
+
+ c = (*rget)(map, "CAUSE");
+ if(c & 0x00002000) /* INTR3 */
+ e = 16; /* Floating point exception */
+ else
+ e = (c>>2)&0x0F;
+ return excname[e];
+}
+
+ /* mips disassembler and related functions */
+
+static char FRAMENAME[] = ".frame";
+
+typedef struct {
+ ulong addr;
+ uchar op; /* bits 31-26 */
+ uchar rs; /* bits 25-21 */
+ uchar rt; /* bits 20-16 */
+ uchar rd; /* bits 15-11 */
+ uchar sa; /* bits 10-6 */
+ uchar function; /* bits 5-0 */
+ long immediate; /* bits 15-0 */
+ ulong cofun; /* bits 24-0 */
+ ulong target; /* bits 25-0 */
+ long w0;
+ long w1;
+ int size; /* instruction size */
+ char *curr; /* fill point in buffer */
+ char *end; /* end of buffer */
+ char *err; /* error message */
+} Instr;
+
+static Map *mymap;
+
+static int
+decode(ulong pc, Instr *i)
+{
+ long w;
+
+ if (get4(mymap, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->addr = pc;
+ i->size = 1;
+ i->op = (w >> 26) & 0x3F;
+ i->rs = (w >> 21) & 0x1F;
+ i->rt = (w >> 16) & 0x1F;
+ i->rd = (w >> 11) & 0x1F;
+ i->sa = (w >> 6) & 0x1F;
+ i->function = w & 0x3F;
+ i->immediate = w & 0x0000FFFF;
+ if (i->immediate & 0x8000)
+ i->immediate |= ~0x0000FFFF;
+ i->cofun = w & 0x01FFFFFF;
+ i->target = w & 0x03FFFFFF;
+ i->w0 = w;
+ return 1;
+}
+
+static int
+mkinstr(ulong pc, Instr *i)
+{
+ Instr x;
+
+ if (decode(pc, i) < 0)
+ return -1;
+ /*
+ * if it's a LUI followed by an ORI,
+ * it's an immediate load of a large constant.
+ * fix the LUI immediate in any case.
+ */
+ if (i->op == 0x0F) {
+ if (decode(pc+4, &x) < 0)
+ return 0;
+ i->immediate <<= 16;
+ if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
+ i->immediate |= (x.immediate & 0xFFFF);
+ i->w1 = x.w0;
+ i->size++;
+ return 1;
+ }
+ }
+ /*
+ * if it's a LWC1 followed by another LWC1
+ * into an adjacent register, it's a load of
+ * a floating point double.
+ */
+ else if (i->op == 0x31 && (i->rt & 0x01)) {
+ if (decode(pc+4, &x) < 0)
+ return 0;
+ if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
+ i->rt -= 1;
+ i->w1 = x.w0;
+ i->size++;
+ return 1;
+ }
+ }
+ /*
+ * similarly for double stores
+ */
+ else if (i->op == 0x39 && (i->rt & 0x01)) {
+ if (decode(pc+4, &x) < 0)
+ return 0;
+ if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
+ i->rt -= 1;
+ i->w1 = x.w0;
+ i->size++;
+ }
+ }
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+typedef struct Opcode Opcode;
+
+struct Opcode {
+ char *mnemonic;
+ void (*f)(Opcode *, Instr *);
+ char *ken;
+};
+
+static void format(char *, Instr *, char *);
+
+static void
+branch(Opcode *o, Instr *i)
+{
+ if (i->rs == 0 && i->rt == 0)
+ format("JMP", i, "%b");
+ else if (i->rs == 0)
+ format(o->mnemonic, i, "R%t,%b");
+ else if (i->rt < 2)
+ format(o->mnemonic, i, "R%s,%b");
+ else
+ format(o->mnemonic, i, "R%s,R%t,%b");
+}
+
+static void
+addi(Opcode *o, Instr *i)
+{
+ if (i->rs == i->rt)
+ format(o->mnemonic, i, "%i,R%t");
+ else if (i->rs == 0)
+ format("MOVW", i, "%i,R%t");
+ else if (i->rs == 30) {
+ bprint(i, "MOVW\t$");
+ i->curr += symoff(i->curr, i->end-i->curr,
+ i->immediate+mach->sb, CANY);
+ bprint(i, "(SB),R%d", i->rt);
+ }
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+andi(Opcode *o, Instr *i)
+{
+ if (i->rs == i->rt)
+ format(o->mnemonic, i, "%i,R%t");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static int
+plocal(Instr *i, char *m, char r, int store)
+{
+ int offset;
+ char *reg;
+ Symbol s;
+
+ if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
+ return 0;
+ if (s.value > i->immediate) {
+ if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
+ return 0;
+ reg = "(SP)";
+ offset = i->immediate;
+ } else {
+ offset = i->immediate-s.value;
+ if (!getauto(&s, offset-4, CPARAM, &s))
+ return 0;
+ reg = "(FP)";
+ }
+ if (store)
+ bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
+ else
+ bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
+ return 1;
+}
+
+static void
+lw(Opcode *o, Instr *i, char r)
+{
+ char *m;
+
+ if (r == 'F') {
+ if (i->size == 2)
+ m = "MOVD";
+ else
+ m = "MOVF";
+ }
+ else
+ m = o->mnemonic;
+ if (i->rs == 29 && plocal(i, m, r, 0))
+ return;
+
+ if (i->rs == 30 && mach->sb) {
+ bprint(i, "%s\t", m);
+ i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
+ bprint(i, "(SB),%c%d", r, i->rt);
+ return;
+ }
+ if (r == 'F')
+ format(m, i, "%l,F%t");
+ else
+ format(m, i, o->ken);
+}
+
+static void
+load(Opcode *o, Instr *i)
+{
+ lw(o, i, 'R');
+}
+
+static void
+lwc1(Opcode *o, Instr *i)
+{
+ lw(o, i, 'F');
+}
+
+static void
+sw(Opcode *o, Instr *i, char r)
+{
+ char *m;
+
+ if (r == 'F') {
+ if (i->size == 2)
+ m = "MOVD";
+ else
+ m = "MOVF";
+ }
+ else
+ m = o->mnemonic;
+ if (i->rs == 29 && plocal(i, m, r, 1))
+ return;
+
+ if (i->rs == 30 && mach->sb) {
+ bprint(i, "%s\t%c%d,", m, r, i->rt);
+ i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
+ bprint(i, "(SB)");
+ return;
+ }
+ if (r == 'F')
+ format(m, i, "F%t,%l");
+ else
+ format(m, i, o->ken);
+}
+
+static void
+store(Opcode *o, Instr *i)
+{
+ sw(o, i, 'R');
+}
+
+static void
+swc1(Opcode *o, Instr *i)
+{
+ sw(o, i, 'F');
+}
+
+static void
+sll(Opcode *o, Instr *i)
+{
+ if (i->w0 == 0)
+ bprint(i, "NOOP");
+ else if (i->rd == i->rt)
+ format(o->mnemonic, i, "$%a,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+sl32(Opcode *o, Instr *i)
+{
+ i->sa += 32;
+ if (i->rd == i->rt)
+ format(o->mnemonic, i, "$%a,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+sllv(Opcode *o, Instr *i)
+{
+ if (i->rd == i->rt)
+ format(o->mnemonic, i, "R%s,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+jal(Opcode *o, Instr *i)
+{
+ if (i->rd == 31)
+ format("JAL", i, "(R%s)");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+add(Opcode *o, Instr *i)
+{
+ if (i->rd == i->rs)
+ format(o->mnemonic, i, "R%t,R%d");
+ else if (i->rd == i->rt)
+ format(o->mnemonic, i, "R%s,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+sub(Opcode *o, Instr *i)
+{
+ if (i->rd == i->rs)
+ format(o->mnemonic, i, "R%t,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+or(Opcode *o, Instr *i)
+{
+ if (i->rs == 0 && i->rt == 0)
+ format("MOVW", i, "$0,R%d");
+ else if (i->rs == 0)
+ format("MOVW", i, "R%t,R%d");
+ else if (i->rt == 0)
+ format("MOVW", i, "R%s,R%d");
+ else
+ add(o, i);
+}
+
+static void
+nor(Opcode *o, Instr *i)
+{
+ if (i->rs == 0 && i->rt == 0 && i->rd == 0)
+ format("NOP", i, 0);
+ else
+ add(o, i);
+}
+
+static char mipscoload[] = "r%t,%l";
+static char mipsload[] = "%l,R%t";
+static char mipsstore[] = "R%t,%l";
+static char mipsalui[] = "%i,R%s,R%t";
+static char mipsalu3op[] = "R%t,R%s,R%d";
+static char mipsrtrs[] = "R%t,R%s";
+static char mipscorsrt[] = "r%s,r%t";
+static char mipscorsi[] = "r%s,%i";
+static char mipscoxxx[] = "%w";
+static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */
+static char mipsfp3[] = "F%t,F%d,F%a";
+static char mipscofp2[] = "f%a,f%d"; /* fd,fs */
+static char mipsfp2[] = "F%d,F%a";
+static char mipscofpc[] = "f%d,f%t"; /* fs,ft */
+static char mipsfpc[] = "F%t,F%d";
+
+static Opcode opcodes[64] = {
+ 0, 0, 0,
+ 0, 0, 0,
+ "JMP", 0, "%j",
+ "JAL", 0, "%j",
+ "BEQ", branch, 0,
+ "BNE", branch, 0,
+ "BLEZ", branch, 0,
+ "BGTZ", branch, 0,
+ "ADD", addi, mipsalui,
+ "ADDU", addi, mipsalui,
+ "SGT", 0, mipsalui,
+ "SGTU", 0, mipsalui,
+ "AND", andi, mipsalui,
+ "OR", andi, mipsalui,
+ "XOR", andi, mipsalui,
+ "MOVW", 0, "$%u,R%t",
+ "cop0", 0, 0,
+ "cop1", 0, 0,
+ "cop2", 0, 0,
+ "cop3", 0, 0,
+ "BEQL", branch, 0,
+ "BNEL", branch, 0,
+ "BLEZL", branch, 0,
+ "BGTZL", branch, 0,
+ "instr18", 0, mipscoxxx,
+ "instr19", 0, mipscoxxx,
+ "MOVVL", load, mipsload,
+ "MOVVR", load, mipsload,
+ "instr1C", 0, mipscoxxx,
+ "instr1D", 0, mipscoxxx,
+ "instr1E", 0, mipscoxxx,
+ "instr1F", 0, mipscoxxx,
+ "MOVB", load, mipsload,
+ "MOVH", load, mipsload,
+ "lwl", 0, mipscoload,
+ "MOVW", load, mipsload,
+ "MOVBU", load, mipsload,
+ "MOVHU", load, mipsload,
+ "lwr", 0, mipscoload,
+ "instr27", 0, mipscoxxx,
+ "MOVB", store, mipsstore,
+ "MOVH", store, mipsstore,
+ "swl", 0, mipscoload,
+ "MOVW", store, mipsstore,
+ "MOVVL", store, mipsstore,
+ "MOVVR", store, mipsstore,
+ "swr", 0, mipscoload,
+ "CACHE", 0, "%C,%l",
+ "ll", 0, mipscoload,
+ "MOVW", lwc1, mipscoload,
+ "lwc2", 0, mipscoload,
+ "lwc3", 0, mipscoload,
+ "instr34", 0, mipscoxxx,
+ "ldc1", 0, mipscoload,
+ "ldc2", 0, mipscoload,
+ "MOVV", load, mipsload,
+ "sc", 0, mipscoload,
+ "swc1", swc1, mipscoload,
+ "swc2", 0, mipscoload,
+ "swc3", 0, mipscoload,
+ "instr3C", 0, mipscoxxx,
+ "sdc1", 0, mipscoload,
+ "sdc2", 0, mipscoload,
+ "MOVV", store, mipsstore,
+};
+
+static Opcode sopcodes[64] = {
+ "SLL", sll, "$%a,R%t,R%d",
+ "special01", 0, mipscoxxx,
+ "SRL", sll, "$%a,R%t,R%d",
+ "SRA", sll, "$%a,R%t,R%d",
+ "SLL", sllv, "R%s,R%t,R%d",
+ "special05", 0, mipscoxxx,
+ "SRL", sllv, "R%s,R%t,R%d",
+ "SRA", sllv, "R%s,R%t,R%d",
+ "JMP", 0, "(R%s)",
+ "jal", jal, "r%d,r%s",
+ "special0A", 0, mipscoxxx,
+ "special0B", 0, mipscoxxx,
+ "SYSCALL", 0, 0,
+ "BREAK", 0, 0,
+ "special0E", 0, mipscoxxx,
+ "SYNC", 0, 0,
+ "MOVW", 0, "HI,R%d",
+ "MOVW", 0, "R%s,HI",
+ "MOVW", 0, "LO,R%d",
+ "MOVW", 0, "R%s,LO",
+ "SLLV", sllv, "R%s,R%t,R%d",
+ "special15", 0, mipscoxxx,
+ "SRLV", sllv, "R%s,R%t,R%d",
+ "SRAV", sllv, "R%s,R%t,R%d",
+ "MUL", 0, mipsrtrs,
+ "MULU", 0, mipsrtrs,
+ "DIV", 0, mipsrtrs,
+ "DIVU", 0, mipsrtrs,
+ "special1C", 0, mipscoxxx,
+ "special1D", 0, mipscoxxx,
+ "DDIV", 0, "R%s,R%t",
+ "special1F", 0, mipscoxxx,
+ "ADD", add, mipsalu3op,
+ "ADDU", add, mipsalu3op,
+ "SUB", sub, mipsalu3op,
+ "SUBU", sub, mipsalu3op,
+ "AND", add, mipsalu3op,
+ "OR", or, mipsalu3op,
+ "XOR", add, mipsalu3op,
+ "NOR", nor, mipsalu3op,
+ "special28", 0, mipscoxxx,
+ "special29", 0, mipscoxxx,
+ "SGT", 0, mipsalu3op,
+ "SGTU", 0, mipsalu3op,
+ "special2C", 0, mipscoxxx,
+ "special2D", 0, mipscoxxx,
+ "special2E", 0, mipscoxxx,
+ "DSUBU", 0, "R%s,R%t,R%d",
+ "tge", 0, mipscorsrt,
+ "tgeu", 0, mipscorsrt,
+ "tlt", 0, mipscorsrt,
+ "tltu", 0, mipscorsrt,
+ "teq", 0, mipscorsrt,
+ "special35", 0, mipscoxxx,
+ "tne", 0, mipscorsrt,
+ "special37", 0, mipscoxxx,
+ "SLLV", sll, "$%a,R%t,R%d",
+ "special39", 0, mipscoxxx,
+ "SRLV", sll, "$%a,R%t,R%d",
+ "SRAV", sll, "$%a,R%t,R%d",
+ "SLLV", sl32, "$%a,R%t,R%d",
+ "special3D", 0, mipscoxxx,
+ "SRLV", sl32, "$%a,R%t,R%d",
+ "SRAV", sl32, "$%a,R%t,R%d",
+};
+
+static Opcode ropcodes[32] = {
+ "BLTZ", branch, 0,
+ "BGEZ", branch, 0,
+ "BLTZL", branch, 0,
+ "BGEZL", branch, 0,
+ "regimm04", 0, mipscoxxx,
+ "regimm05", 0, mipscoxxx,
+ "regimm06", 0, mipscoxxx,
+ "regimm07", 0, mipscoxxx,
+ "tgei", 0, mipscorsi,
+ "tgeiu", 0, mipscorsi,
+ "tlti", 0, mipscorsi,
+ "tltiu", 0, mipscorsi,
+ "teqi", 0, mipscorsi,
+ "regimm0D", 0, mipscoxxx,
+ "tnei", 0, mipscorsi,
+ "regimm0F", 0, mipscoxxx,
+ "BLTZAL", branch, 0,
+ "BGEZAL", branch, 0,
+ "BLTZALL", branch, 0,
+ "BGEZALL", branch, 0,
+ "regimm14", 0, mipscoxxx,
+ "regimm15", 0, mipscoxxx,
+ "regimm16", 0, mipscoxxx,
+ "regimm17", 0, mipscoxxx,
+ "regimm18", 0, mipscoxxx,
+ "regimm19", 0, mipscoxxx,
+ "regimm1A", 0, mipscoxxx,
+ "regimm1B", 0, mipscoxxx,
+ "regimm1C", 0, mipscoxxx,
+ "regimm1D", 0, mipscoxxx,
+ "regimm1E", 0, mipscoxxx,
+ "regimm1F", 0, mipscoxxx,
+};
+
+static Opcode fopcodes[64] = {
+ "ADD%f", 0, mipsfp3,
+ "SUB%f", 0, mipsfp3,
+ "MUL%f", 0, mipsfp3,
+ "DIV%f", 0, mipsfp3,
+ "sqrt.%f", 0, mipscofp2,
+ "ABS%f", 0, mipsfp2,
+ "MOV%f", 0, mipsfp2,
+ "NEG%f", 0, mipsfp2,
+ "finstr08", 0, mipscoxxx,
+ "finstr09", 0, mipscoxxx,
+ "finstr0A", 0, mipscoxxx,
+ "finstr0B", 0, mipscoxxx,
+ "round.w.%f", 0, mipscofp2,
+ "trunc.w%f", 0, mipscofp2,
+ "ceil.w%f", 0, mipscofp2,
+ "floor.w%f", 0, mipscofp2,
+ "finstr10", 0, mipscoxxx,
+ "finstr11", 0, mipscoxxx,
+ "finstr12", 0, mipscoxxx,
+ "finstr13", 0, mipscoxxx,
+ "finstr14", 0, mipscoxxx,
+ "finstr15", 0, mipscoxxx,
+ "finstr16", 0, mipscoxxx,
+ "finstr17", 0, mipscoxxx,
+ "finstr18", 0, mipscoxxx,
+ "finstr19", 0, mipscoxxx,
+ "finstr1A", 0, mipscoxxx,
+ "finstr1B", 0, mipscoxxx,
+ "finstr1C", 0, mipscoxxx,
+ "finstr1D", 0, mipscoxxx,
+ "finstr1E", 0, mipscoxxx,
+ "finstr1F", 0, mipscoxxx,
+ "cvt.s.%f", 0, mipscofp2,
+ "cvt.d.%f", 0, mipscofp2,
+ "cvt.e.%f", 0, mipscofp2,
+ "cvt.q.%f", 0, mipscofp2,
+ "cvt.w.%f", 0, mipscofp2,
+ "finstr25", 0, mipscoxxx,
+ "finstr26", 0, mipscoxxx,
+ "finstr27", 0, mipscoxxx,
+ "finstr28", 0, mipscoxxx,
+ "finstr29", 0, mipscoxxx,
+ "finstr2A", 0, mipscoxxx,
+ "finstr2B", 0, mipscoxxx,
+ "finstr2C", 0, mipscoxxx,
+ "finstr2D", 0, mipscoxxx,
+ "finstr2E", 0, mipscoxxx,
+ "finstr2F", 0, mipscoxxx,
+ "c.f.%f", 0, mipscofpc,
+ "c.un.%f", 0, mipscofpc,
+ "CMPEQ%f", 0, mipsfpc,
+ "c.ueq.%f", 0, mipscofpc,
+ "c.olt.%f", 0, mipscofpc,
+ "c.ult.%f", 0, mipscofpc,
+ "c.ole.%f", 0, mipscofpc,
+ "c.ule.%f", 0, mipscofpc,
+ "c.sf.%f", 0, mipscofpc,
+ "c.ngle.%f", 0, mipscofpc,
+ "c.seq.%f", 0, mipscofpc,
+ "c.ngl.%f", 0, mipscofpc,
+ "CMPGT%f", 0, mipsfpc,
+ "c.nge.%f", 0, mipscofpc,
+ "CMPGE%f", 0, mipsfpc,
+ "c.ngt.%f", 0, mipscofpc,
+};
+
+static char *cop0regs[32] = {
+ "INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
+ "CONTEXT", "PageMask", "Wired", "Error",
+ "BADVADDR", "Count", "TLBVIRT", "Compare",
+ "STATUS", "CAUSE", "EPC", "PRID",
+ "Config", "LLadr", "WatchLo", "WatchHi",
+ "20", "21", "22", "23",
+ "24", "25", "26", "CacheErr",
+ "TagLo", "TagHi", "ErrorEPC", "31"
+};
+
+static char fsub[16] = {
+ 'F', 'D', 'e', 'q', 'W', '?', '?', '?',
+ '?', '?', '?', '?', '?', '?', '?', '?'
+};
+
+static char *cacheps[] = {
+ "I", "D", "SI", "SD"
+};
+
+static char *cacheop[] = {
+ "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
+};
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (mnemonic)
+ if (i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if (*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 's':
+ bprint(i, "%d", i->rs);
+ break;
+
+ case 't':
+ bprint(i, "%d", i->rt);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->sa);
+ break;
+
+ case 'l':
+ bprint(i, "%lx(R%d)",i->immediate, i->rs);
+ break;
+
+ case 'i':
+ bprint(i, "$%lx", i->immediate);
+ break;
+
+ case 'u':
+ i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
+ bprint(i, "(SB)");
+ break;
+
+ case 'j':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ (i->target<<2)|(i->addr & 0xF0000000), CANY);
+ bprint(i, "(SB)");
+ break;
+
+ case 'b':
+ i->curr += symoff(i->curr, i->end-i->curr,
+ (i->immediate<<2)+i->addr+4, CANY);
+ break;
+
+ case 'c':
+ bprint(i, "$%lx", i->cofun);
+ break;
+
+ case 'w':
+ bprint(i, "[%lux]", i->w0);
+ break;
+
+ case 'm':
+ bprint(i, "M(%s)", cop0regs[i->rd]);
+ break;
+
+ case 'f':
+ *i->curr++ = fsub[i->rs & 0x0F];
+ break;
+
+ case 'C':
+ bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+static void
+copz(int cop, Instr *i)
+{
+ char *f, *m, buf[16];
+
+ m = buf;
+ f = "%t,%d";
+ switch (i->rs) {
+
+ case 0:
+ sprint(buf, "mfc%d", cop);
+ break;
+
+ case 2:
+ sprint(buf, "cfc%d", cop);
+ break;
+
+ case 4:
+ sprint(buf, "mtc%d", cop);
+ break;
+
+ case 6:
+ sprint(buf, "ctc%d", cop);
+ break;
+
+ case 8:
+ f = "%b";
+ switch (i->rt) {
+
+ case 0:
+ sprint(buf, "bc%df", cop);
+ break;
+
+ case 1:
+ sprint(buf, "bc%dt", cop);
+ break;
+
+ case 2:
+ sprint(buf, "bc%dfl", cop);
+ break;
+
+ case 3:
+ sprint(buf, "bc%dtl", cop);
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ f = mipscoxxx;
+ break;
+ }
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ if (i->rs & 0x10)
+ f = "function %c";
+ else
+ f = mipscoxxx;
+ break;
+ }
+ format(m, i, f);
+}
+
+static void
+cop0(Instr *i)
+{
+ char *m = 0;
+
+ if (i->rs < 8) {
+ switch (i->rs) {
+
+ case 0:
+ case 1:
+ format("MOVW", i, "%m,R%t");
+ return;
+
+ case 4:
+ case 5:
+ format("MOVW", i, "R%t,%m");
+ return;
+ }
+ }
+ else if (i->rs >= 0x10) {
+ switch (i->cofun) {
+
+ case 1:
+ m = "TLBR";
+ break;
+
+ case 2:
+ m = "TLBWI";
+ break;
+
+ case 6:
+ m = "TLBWR";
+ break;
+
+ case 8:
+ m = "TLBP";
+ break;
+
+ case 16:
+ m = "RFE";
+ break;
+
+ case 32:
+ m = "ERET";
+ break;
+ }
+ if (m) {
+ format(m, i, 0);
+ return;
+ }
+ }
+ copz(0, i);
+}
+
+static void
+cop1(Instr *i)
+{
+ char *m = "MOVW";
+
+ switch (i->rs) {
+
+ case 0:
+ format(m, i, "F%d,R%t");
+ return;
+
+ case 2:
+ format(m, i, "FCR%d,R%t");
+ return;
+
+ case 4:
+ format(m, i, "R%t,F%d");
+ return;
+
+ case 6:
+ format(m, i, "R%t,FCR%d");
+ return;
+
+ case 8:
+ switch (i->rt) {
+
+ case 0:
+ format("BFPF", i, "%b");
+ return;
+
+ case 1:
+ format("BFPT", i, "%b");
+ return;
+ }
+ break;
+ }
+ copz(1, i);
+}
+
+static int
+printins(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+ Opcode *o;
+ uchar op;
+
+ i.curr = buf;
+ i.end = buf+n-1;
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ switch (i.op) {
+
+ case 0x00: /* SPECIAL */
+ o = sopcodes;
+ op = i.function;
+ break;
+
+ case 0x01: /* REGIMM */
+ o = ropcodes;
+ op = i.rt;
+ break;
+
+ case 0x10: /* COP0 */
+ cop0(&i);
+ return i.size*4;
+
+ case 0x11: /* COP1 */
+ if (i.rs & 0x10) {
+ o = fopcodes;
+ op = i.function;
+ break;
+ }
+ cop1(&i);
+ return i.size*4;
+
+ case 0x12: /* COP2 */
+ case 0x13: /* COP3 */
+ copz(i.op-0x10, &i);
+ return i.size*4;
+
+ default:
+ o = opcodes;
+ op = i.op;
+ break;
+ }
+ if (o[op].f)
+ (*o[op].f)(&o[op], &i);
+ else
+ format(o[op].mnemonic, &i, o[op].ken);
+ return i.size*4;
+}
+
+extern int _mipscoinst(Map *, ulong, char*, int);
+
+ /* modifier 'I' toggles the default disassembler type */
+int
+mipsinst(Map *map, ulong pc, char modifier, char *buf, int n)
+{
+ if ((asstype == AMIPSCO && modifier == 'i')
+ || (asstype == AMIPS && modifier == 'I'))
+ return _mipscoinst(map, pc, buf, n);
+ else
+ return printins(map, pc, buf, n);
+}
+
+int
+mipsdas(Map *map, ulong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n;
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ if (i.end-i.curr > 8)
+ i.curr = _hexify(buf, i.w0, 7);
+ if (i.size == 2 && i.end-i.curr > 9) {
+ *i.curr++ = ' ';
+ i.curr = _hexify(i.curr, i.w1, 7);
+ }
+ *i.curr = 0;
+ return i.size*4;
+}
+
+int
+mipsinstlen(Map *map, ulong pc)
+{
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ return i.size*4;
+}
+
+int
+mipsfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
+{
+ ulong w, l;
+ char buf[8];
+ Instr i;
+
+ mymap = map;
+ if (mkinstr(pc, &i) < 0)
+ return -1;
+ w = i.w0;
+ if((w&0xF3600000) == 0x41000000){ /* branch on coprocessor */
+ Conditional:
+ foll[0] = pc+8;
+ l = ((w&0xFFFF)<<2);
+ if(w & 0x8000)
+ l |= 0xFFFC0000;
+ foll[1] = pc+4 + l;
+ return 2;
+ }
+
+ l = (w&0xFC000000)>>26;
+ switch(l){
+ case 0: /* SPECIAL */
+ if((w&0x3E) == 0x08){ /* JR, JALR */
+ sprint(buf, "R%ld", (w>>21)&0x1F);
+ foll[0] = (*rget)(map, buf);
+ return 1;
+ }
+ foll[0] = pc+i.size*4;
+ return 1;
+ case 0x30: /* Load-Linked followed by NOP, STC */
+ foll[0] = pc+12;
+ return 1;
+ case 1: /* BCOND */
+ case 4: /* BEQ */
+ case 20: /* BEQL */
+ case 5: /* BNE */
+ case 21: /* BNEL */
+ case 6: /* BLEZ */
+ case 22: /* BLEZL */
+ case 7: /* BGTZ */
+ case 23: /* BGTZL */
+ goto Conditional;
+ case 2: /* J */
+ case 3: /* JAL */
+ foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
+ return 1;
+ }
+
+ foll[0] = pc+i.size*4;
+ return 1;
+}
diff --git a/utils/libmach/vobj.c b/utils/libmach/vobj.c
new file mode 100644
index 00000000..f676d219
--- /dev/null
+++ b/utils/libmach/vobj.c
@@ -0,0 +1,129 @@
+/*
+ * vobj.c - identify and parse a mips object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "vc/v.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_isv(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_readv(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME)
+ skip(bp, 4); /* signature */
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 5); /* reg(1), lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE: case D_REG: case D_FREG: case D_MREG:
+ case D_FCREG: case D_LO: case D_HI:
+ break;
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libregexp/NOTICE b/utils/libregexp/NOTICE
new file mode 100644
index 00000000..50e574e2
--- /dev/null
+++ b/utils/libregexp/NOTICE
@@ -0,0 +1,28 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1994-1999 Lucent Technologies Inc.
+ Revisions Copyright © 2000-2003 Vita Nuova Holdings Limited (www.vitanuova.com).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/utils/libregexp/mkfile b/utils/libregexp/mkfile
new file mode 100644
index 00000000..3f6bc47a
--- /dev/null
+++ b/utils/libregexp/mkfile
@@ -0,0 +1,22 @@
+<../../mkconfig
+
+#XXX
+<$ROOT/mkfiles/mkhost-$SYSHOST # variables appropriate for host system
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE # variables used to build target object type
+
+LIB=libregexp.a
+CFLAGS= $CFLAGS -I../include
+
+OFILES=\
+ regcomp.$O\
+ regerror.$O\
+ regexec.$O\
+ regsub.$O\
+ regaux.$O\
+ rregexec.$O\
+ rregsub.$O\
+
+HFILES= ../include/regexp.h\
+ regcomp.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
diff --git a/utils/libregexp/regaux.c b/utils/libregexp/regaux.c
new file mode 100644
index 00000000..90298ddc
--- /dev/null
+++ b/utils/libregexp/regaux.c
@@ -0,0 +1,98 @@
+#include <lib9.h>
+#include "regexp.h"
+#include "regcomp.h"
+
+
+/*
+ * save a new match in mp
+ */
+extern void
+_renewmatch(Resub *mp, int ms, Resublist *sp)
+{
+ int i;
+
+ if(mp==0 || ms<=0)
+ return;
+ if(mp[0].s.sp==0 || sp->m[0].s.sp<mp[0].s.sp ||
+ (sp->m[0].s.sp==mp[0].s.sp && sp->m[0].e.ep>mp[0].e.ep)){
+ for(i=0; i<ms && i<NSUBEXP; i++)
+ mp[i] = sp->m[i];
+ for(; i<ms; i++)
+ mp[i].s.sp = mp[i].e.ep = 0;
+ }
+}
+
+/*
+ * Note optimization in _renewthread:
+ * *lp must be pending when _renewthread called; if *l has been looked
+ * at already, the optimization is a bug.
+ */
+extern Relist*
+_renewthread(Relist *lp, /* _relist to add to */
+ Reinst *ip, /* instruction to add */
+ Resublist *sep) /* pointers to subexpressions */
+{
+ Relist *p;
+
+ for(p=lp; p->inst; p++){
+ if(p->inst == ip){
+ if((sep)->m[0].s.sp < p->se.m[0].s.sp)
+ p->se = *sep;
+ return 0;
+ }
+ }
+ p->inst = ip;
+ p->se = *sep;
+ (++p)->inst = 0;
+ return p;
+}
+
+/*
+ * same as renewthread, but called with
+ * initial empty start pointer.
+ */
+extern Relist*
+_renewemptythread(Relist *lp, /* _relist to add to */
+ Reinst *ip, /* instruction to add */
+ char *sp) /* pointers to subexpressions */
+{
+ Relist *p;
+
+ for(p=lp; p->inst; p++){
+ if(p->inst == ip){
+ if(sp < p->se.m[0].s.sp) {
+ memset((void *)&p->se, 0, sizeof(p->se));
+ p->se.m[0].s.sp = sp;
+ }
+ return 0;
+ }
+ }
+ p->inst = ip;
+ memset((void *)&p->se, 0, sizeof(p->se));
+ p->se.m[0].s.sp = sp;
+ (++p)->inst = 0;
+ return p;
+}
+
+extern Relist*
+_rrenewemptythread(Relist *lp, /* _relist to add to */
+ Reinst *ip, /* instruction to add */
+ Rune *rsp) /* pointers to subexpressions */
+{
+ Relist *p;
+
+ for(p=lp; p->inst; p++){
+ if(p->inst == ip){
+ if(rsp < p->se.m[0].s.rsp) {
+ memset((void *)&p->se, 0, sizeof(p->se));
+ p->se.m[0].s.rsp = rsp;
+ }
+ return 0;
+ }
+ }
+ p->inst = ip;
+ memset((void *)&p->se, 0, sizeof(p->se));
+ p->se.m[0].s.rsp = rsp;
+ (++p)->inst = 0;
+ return p;
+}
diff --git a/utils/libregexp/regcomp.c b/utils/libregexp/regcomp.c
new file mode 100644
index 00000000..da677046
--- /dev/null
+++ b/utils/libregexp/regcomp.c
@@ -0,0 +1,557 @@
+#include <lib9.h>
+#include "regexp.h"
+#include "regcomp.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Parser Information
+ */
+typedef
+struct Node
+{
+ Reinst* first;
+ Reinst* last;
+}Node;
+
+Reprog RePrOg;
+
+#define NSTACK 20
+static Node andstack[NSTACK];
+static Node *andp;
+static int atorstack[NSTACK];
+static int* atorp;
+static int cursubid; /* id of current subexpression */
+static int subidstack[NSTACK]; /* parallel to atorstack */
+static int* subidp;
+static int lastwasand; /* Last token was operand */
+static int nbra;
+static char* exprp; /* pointer to next character in source expression */
+static int lexdone;
+static int nclass;
+static Reclass*classp;
+static Reinst* freep;
+static int errors;
+static Rune yyrune; /* last lex'd rune */
+static Reclass*yyclassp; /* last lex'd class */
+
+/* predeclared crap */
+static void operator(int);
+static void pushand(Reinst*, Reinst*);
+static void pushator(int);
+static void evaluntil(int);
+static int bldcclass(void);
+
+static jmp_buf regkaboom;
+
+static void
+rcerror(char *s)
+{
+ errors++;
+ regerror(s);
+ longjmp(regkaboom, 1);
+}
+
+static Reinst*
+newinst(int t)
+{
+ freep->type = t;
+ freep->u2.left = 0;
+ freep->u1.right = 0;
+ return freep++;
+}
+
+static void
+operand(int t)
+{
+ Reinst *i;
+
+ if(lastwasand)
+ operator(CAT); /* catenate is implicit */
+ i = newinst(t);
+
+ if(t == CCLASS || t == NCCLASS)
+ i->u1.cp = yyclassp;
+ if(t == RUNE)
+ i->u1.r = yyrune;
+
+ pushand(i, i);
+ lastwasand = TRUE;
+}
+
+static void
+operator(int t)
+{
+ if(t==RBRA && --nbra<0)
+ rcerror("unmatched right paren");
+ if(t==LBRA){
+ if(++cursubid >= NSUBEXP)
+ rcerror ("too many subexpressions");
+ nbra++;
+ if(lastwasand)
+ operator(CAT);
+ } else
+ evaluntil(t);
+ if(t != RBRA)
+ pushator(t);
+ lastwasand = FALSE;
+ if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
+ lastwasand = TRUE; /* these look like operands */
+}
+
+static void
+regerr2(char *s, int c)
+{
+ char buf[100];
+ char *cp = buf;
+ while(*s)
+ *cp++ = *s++;
+ *cp++ = c;
+ *cp = '\0';
+ rcerror(buf);
+}
+
+static void
+cant(char *s)
+{
+ char buf[100];
+ strcpy(buf, "can't happen: ");
+ strcat(buf, s);
+ rcerror(buf);
+}
+
+static void
+pushand(Reinst *f, Reinst *l)
+{
+ if(andp >= &andstack[NSTACK])
+ cant("operand stack overflow");
+ andp->first = f;
+ andp->last = l;
+ andp++;
+}
+
+static void
+pushator(int t)
+{
+ if(atorp >= &atorstack[NSTACK])
+ cant("operator stack overflow");
+ *atorp++ = t;
+ *subidp++ = cursubid;
+}
+
+static Node*
+popand(int op)
+{
+ Reinst *inst;
+
+ if(andp <= &andstack[0]){
+ regerr2("missing operand for ", op);
+ inst = newinst(NOP);
+ pushand(inst,inst);
+ }
+ return --andp;
+}
+
+static int
+popator(void)
+{
+ if(atorp <= &atorstack[0])
+ cant("operator stack underflow");
+ --subidp;
+ return *--atorp;
+}
+
+static void
+evaluntil(int pri)
+{
+ Node *op1, *op2;
+ Reinst *inst1, *inst2;
+
+ while(pri==RBRA || atorp[-1]>=pri){
+ switch(popator()){
+ default:
+ rcerror("unknown operator in evaluntil");
+ break;
+ case LBRA: /* must have been RBRA */
+ op1 = popand('(');
+ inst2 = newinst(RBRA);
+ inst2->u1.subid = *subidp;
+ op1->last->u2.next = inst2;
+ inst1 = newinst(LBRA);
+ inst1->u1.subid = *subidp;
+ inst1->u2.next = op1->first;
+ pushand(inst1, inst2);
+ return;
+ case OR:
+ op2 = popand('|');
+ op1 = popand('|');
+ inst2 = newinst(NOP);
+ op2->last->u2.next = inst2;
+ op1->last->u2.next = inst2;
+ inst1 = newinst(OR);
+ inst1->u1.right = op1->first;
+ inst1->u2.left = op2->first;
+ pushand(inst1, inst2);
+ break;
+ case CAT:
+ op2 = popand(0);
+ op1 = popand(0);
+ op1->last->u2.next = op2->first;
+ pushand(op1->first, op2->last);
+ break;
+ case STAR:
+ op2 = popand('*');
+ inst1 = newinst(OR);
+ op2->last->u2.next = inst1;
+ inst1->u1.right = op2->first;
+ pushand(inst1, inst1);
+ break;
+ case PLUS:
+ op2 = popand('+');
+ inst1 = newinst(OR);
+ op2->last->u2.next = inst1;
+ inst1->u1.right = op2->first;
+ pushand(op2->first, inst1);
+ break;
+ case QUEST:
+ op2 = popand('?');
+ inst1 = newinst(OR);
+ inst2 = newinst(NOP);
+ inst1->u2.left = inst2;
+ inst1->u1.right = op2->first;
+ op2->last->u2.next = inst2;
+ pushand(inst1, inst2);
+ break;
+ }
+ }
+}
+
+static Reprog*
+optimize(Reprog *pp)
+{
+ Reinst *inst, *target;
+ int size;
+ Reprog *npp;
+ Reclass *cl;
+ int diff;
+
+ /*
+ * get rid of NOOP chains
+ */
+ for(inst=pp->firstinst; inst->type!=END; inst++){
+ target = inst->u2.next;
+ while(target->type == NOP)
+ target = target->u2.next;
+ inst->u2.next = target;
+ }
+
+ /*
+ * The original allocation is for an area larger than
+ * necessary. Reallocate to the actual space used
+ * and then relocate the code.
+ */
+ size = sizeof(Reprog) + (freep - pp->firstinst)*sizeof(Reinst);
+ npp = (Reprog *)realloc(pp, size);
+ if(npp==0 || npp==pp)
+ return pp;
+ diff = (char *)npp - (char *)pp;
+ freep = (Reinst *)((char *)freep + diff);
+ for(inst=npp->firstinst; inst<freep; inst++){
+ switch(inst->type){
+ case OR:
+ case STAR:
+ case PLUS:
+ case QUEST:
+ *(char **)&inst->u1.right += diff;
+ break;
+ case CCLASS:
+ case NCCLASS:
+ *(char **)&inst->u1.right += diff;
+ cl = inst->u1.cp;
+ *(char **)&cl->end += diff;
+ break;
+ }
+ *(char **)&inst->u2.left += diff;
+ }
+ *(char **)&npp->startinst += diff;
+ return npp;
+}
+
+#ifdef DEBUG
+static void
+dumpstack(void){
+ Node *stk;
+ int *ip;
+
+ print("operators\n");
+ for(ip=atorstack; ip<atorp; ip++)
+ print("0%o\n", *ip);
+ print("operands\n");
+ for(stk=andstack; stk<andp; stk++)
+ print("0%o\t0%o\n", stk->first->type, stk->last->type);
+}
+
+static void
+dump(Reprog *pp)
+{
+ Reinst *l;
+ Rune *p;
+
+ l = pp->firstinst;
+ do{
+ print("%d:\t0%o\t%d\t%d", l-pp->firstinst, l->type,
+ l->u2.left-pp->firstinst, l->u1.right-pp->firstinst);
+ if(l->type == RUNE)
+ print("\t%C\n", l->r);
+ else if(l->type == CCLASS || l->type == NCCLASS){
+ print("\t[");
+ if(l->type == NCCLASS)
+ print("^");
+ for(p = l->cp->spans; p < l->cp->end; p += 2)
+ if(p[0] == p[1])
+ print("%C", p[0]);
+ else
+ print("%C-%C", p[0], p[1]);
+ print("]\n");
+ } else
+ print("\n");
+ }while(l++->type);
+}
+#endif
+
+static Reclass*
+newclass(void)
+{
+ if(nclass >= NCLASS)
+ regerr2("too many character classes; limit", NCLASS+'0');
+ return &(classp[nclass++]);
+}
+
+static int
+nextc(Rune *rp)
+{
+ if(lexdone){
+ *rp = 0;
+ return 1;
+ }
+ exprp += chartorune(rp, exprp);
+ if(*rp == L'\\'){
+ exprp += chartorune(rp, exprp);
+ return 1;
+ }
+ if(*rp == 0)
+ lexdone = 1;
+ return 0;
+}
+
+static int
+lex(int literal, int dot_type)
+{
+ int quoted;
+
+ quoted = nextc(&yyrune);
+ if(literal || quoted){
+ if(yyrune == 0)
+ return END;
+ return RUNE;
+ }
+
+ switch(yyrune){
+ case 0:
+ return END;
+ case L'*':
+ return STAR;
+ case L'?':
+ return QUEST;
+ case L'+':
+ return PLUS;
+ case L'|':
+ return OR;
+ case L'.':
+ return dot_type;
+ case L'(':
+ return LBRA;
+ case L')':
+ return RBRA;
+ case L'^':
+ return BOL;
+ case L'$':
+ return EOL;
+ case L'[':
+ return bldcclass();
+ }
+ return RUNE;
+}
+
+static int
+bldcclass(void)
+{
+ int type;
+ Rune r[NCCRUNE];
+ Rune *p, *ep, *np;
+ Rune rune;
+ int quoted;
+
+ /* we have already seen the '[' */
+ type = CCLASS;
+ yyclassp = newclass();
+
+ /* look ahead for negation */
+ /* SPECIAL CASE!!! negated classes don't match \n */
+ ep = r;
+ quoted = nextc(&rune);
+ if(!quoted && rune == L'^'){
+ type = NCCLASS;
+ quoted = nextc(&rune);
+ *ep++ = L'\n';
+ *ep++ = L'\n';
+ }
+
+ /* parse class into a set of spans */
+ for(; ep<&r[NCCRUNE];){
+ if(rune == 0){
+ rcerror("malformed '[]'");
+ return 0;
+ }
+ if(!quoted && rune == L']')
+ break;
+ if(!quoted && rune == L'-'){
+ if(ep == r){
+ rcerror("malformed '[]'");
+ return 0;
+ }
+ quoted = nextc(&rune);
+ if((!quoted && rune == L']') || rune == 0){
+ rcerror("malformed '[]'");
+ return 0;
+ }
+ *(ep-1) = rune;
+ } else {
+ *ep++ = rune;
+ *ep++ = rune;
+ }
+ quoted = nextc(&rune);
+ }
+
+ /* sort on span start */
+ for(p = r; p < ep; p += 2){
+ for(np = p; np < ep; np += 2)
+ if(*np < *p){
+ rune = np[0];
+ np[0] = p[0];
+ p[0] = rune;
+ rune = np[1];
+ np[1] = p[1];
+ p[1] = rune;
+ }
+ }
+
+ /* merge spans */
+ np = yyclassp->spans;
+ p = r;
+ if(r == ep)
+ yyclassp->end = np;
+ else {
+ np[0] = *p++;
+ np[1] = *p++;
+ for(; p < ep; p += 2)
+ if(p[0] <= np[1]){
+ if(p[1] > np[1])
+ np[1] = p[1];
+ } else {
+ np += 2;
+ np[0] = p[0];
+ np[1] = p[1];
+ }
+ yyclassp->end = np+2;
+ }
+
+ return type;
+}
+
+static Reprog*
+regcomp1(char *s, int literal, int dot_type)
+{
+ int token;
+ Reprog *pp;
+
+ /* get memory for the program */
+ pp = (Reprog *)malloc(sizeof(Reprog) + 6*sizeof(Reinst)*strlen(s));
+ if(pp == 0){
+ regerror("out of memory");
+ return 0;
+ }
+ freep = pp->firstinst;
+ classp = pp->class;
+ errors = 0;
+
+ if(setjmp(regkaboom))
+ goto out;
+
+ /* go compile the sucker */
+ lexdone = 0;
+ exprp = s;
+ nclass = 0;
+ nbra = 0;
+ atorp = atorstack;
+ andp = andstack;
+ subidp = subidstack;
+ lastwasand = FALSE;
+ cursubid = 0;
+
+ /* Start with a low priority operator to prime parser */
+ pushator(START-1);
+ while((token = lex(literal, dot_type)) != END){
+ if((token&0300) == OPERATOR)
+ operator(token);
+ else
+ operand(token);
+ }
+
+ /* Close with a low priority operator */
+ evaluntil(START);
+
+ /* Force END */
+ operand(END);
+ evaluntil(START);
+#ifdef DEBUG
+ dumpstack();
+#endif
+ if(nbra)
+ rcerror("unmatched left paren");
+ --andp; /* points to first and only operand */
+ pp->startinst = andp->first;
+#ifdef DEBUG
+ dump(pp);
+#endif
+ pp = optimize(pp);
+#ifdef DEBUG
+ print("start: %d\n", andp->first-pp->firstinst);
+ dump(pp);
+#endif
+out:
+ if(errors){
+ free(pp);
+ pp = 0;
+ }
+ return pp;
+}
+
+extern Reprog*
+regcomp(char *s)
+{
+ return regcomp1(s, 0, ANY);
+}
+
+extern Reprog*
+regcomplit(char *s)
+{
+ return regcomp1(s, 1, ANY);
+}
+
+extern Reprog*
+regcompnl(char *s)
+{
+ return regcomp1(s, 0, ANYNL);
+}
diff --git a/utils/libregexp/regcomp.h b/utils/libregexp/regcomp.h
new file mode 100644
index 00000000..1261b051
--- /dev/null
+++ b/utils/libregexp/regcomp.h
@@ -0,0 +1,70 @@
+/*
+ * substitution list
+ */
+#define NSUBEXP 32
+typedef struct Resublist Resublist;
+struct Resublist
+{
+ Resub m[NSUBEXP];
+};
+
+/* max character classes per program */
+extern Reprog RePrOg;
+#define NCLASS (sizeof(RePrOg.class)/sizeof(Reclass))
+
+/* max rune ranges per character class */
+#define NCCRUNE (sizeof(Reclass)/sizeof(Rune))
+
+/*
+ * Actions and Tokens (Reinst types)
+ *
+ * 02xx are operators, value == precedence
+ * 03xx are tokens, i.e. operands for operators
+ */
+#define RUNE 0177
+#define OPERATOR 0200 /* Bitmask of all operators */
+#define START 0200 /* Start, used for marker on stack */
+#define RBRA 0201 /* Right bracket, ) */
+#define LBRA 0202 /* Left bracket, ( */
+#define OR 0203 /* Alternation, | */
+#define CAT 0204 /* Concatentation, implicit operator */
+#define STAR 0205 /* Closure, * */
+#define PLUS 0206 /* a+ == aa* */
+#define QUEST 0207 /* a? == a|nothing, i.e. 0 or 1 a's */
+#define ANY 0300 /* Any character except newline, . */
+#define ANYNL 0301 /* Any character including newline, . */
+#define NOP 0302 /* No operation, internal use only */
+#define BOL 0303 /* Beginning of line, ^ */
+#define EOL 0304 /* End of line, $ */
+#define CCLASS 0305 /* Character class, [] */
+#define NCCLASS 0306 /* Negated character class, [] */
+#define END 0377 /* Terminate: match found */
+
+/*
+ * regexec execution lists
+ */
+#define LISTSIZE 10
+#define BIGLISTSIZE (10*LISTSIZE)
+typedef struct Relist Relist;
+struct Relist
+{
+ Reinst* inst; /* Reinstruction of the thread */
+ Resublist se; /* matched subexpressions in this thread */
+};
+typedef struct Reljunk Reljunk;
+struct Reljunk
+{
+ Relist* relist[2];
+ Relist* reliste[2];
+ int starttype;
+ Rune startchar;
+ char* starts;
+ char* eol;
+ Rune* rstarts;
+ Rune* reol;
+};
+
+extern Relist* _renewthread(Relist*, Reinst*, Resublist*);
+extern void _renewmatch(Resub*, int, Resublist*);
+extern Relist* _renewemptythread(Relist*, Reinst*, char*);
+extern Relist* _rrenewemptythread(Relist*, Reinst*, Rune*);
diff --git a/utils/libregexp/regerror.c b/utils/libregexp/regerror.c
new file mode 100644
index 00000000..09b0b994
--- /dev/null
+++ b/utils/libregexp/regerror.c
@@ -0,0 +1,14 @@
+#include <lib9.h>
+#include "regexp.h"
+
+void
+regerror(char *s)
+{
+ char buf[132];
+
+ strcpy(buf, "regerror: ");
+ strcat(buf, s);
+ strcat(buf, "\n");
+ write(2, buf, strlen(buf));
+ exits("regerr");
+}
diff --git a/utils/libregexp/regexec.c b/utils/libregexp/regexec.c
new file mode 100644
index 00000000..ccb96f58
--- /dev/null
+++ b/utils/libregexp/regexec.c
@@ -0,0 +1,219 @@
+#include <lib9.h>
+#include "regexp.h"
+#include "regcomp.h"
+
+
+/*
+ * return 0 if no match
+ * >0 if a match
+ * <0 if we ran out of _relist space
+ */
+static int
+regexec1(Reprog *progp, /* program to run */
+ char *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms, /* number of elements at mp */
+ Reljunk *j
+)
+{
+ int flag=0;
+ Reinst *inst;
+ Relist *tlp;
+ char *s;
+ int i, checkstart;
+ Rune r, *rp, *ep;
+ int n;
+ Relist* tl; /* This list, next list */
+ Relist* nl;
+ Relist* tle; /* ends of this and next list */
+ Relist* nle;
+ int match;
+ char *p;
+
+ match = 0;
+ checkstart = j->starttype;
+ if(mp)
+ for(i=0; i<ms; i++) {
+ mp[i].s.sp = 0;
+ mp[i].e.ep = 0;
+ }
+ j->relist[0][0].inst = 0;
+ j->relist[1][0].inst = 0;
+
+ /* Execute machine once for each character, including terminal NUL */
+ s = j->starts;
+ do{
+ /* fast check for first char */
+ if(checkstart) {
+ switch(j->starttype) {
+ case RUNE:
+ p = utfrune(s, j->startchar);
+ if(p == 0 || s == j->eol)
+ return match;
+ s = p;
+ break;
+ case BOL:
+ if(s == bol)
+ break;
+ p = utfrune(s, '\n');
+ if(p == 0 || s == j->eol)
+ return match;
+ s = p;
+ break;
+ }
+ }
+ r = *(uchar*)s;
+ if(r < (Rune)Runeself)
+ n = 1;
+ else
+ n = chartorune(&r, s);
+
+ /* switch run lists */
+ tl = j->relist[flag];
+ tle = j->reliste[flag];
+ nl = j->relist[flag^=1];
+ nle = j->reliste[flag];
+ nl->inst = 0;
+
+ /* Add first instruction to current list */
+ if(match == 0)
+ _renewemptythread(tl, progp->startinst, s);
+
+ /* Execute machine until current list is empty */
+ for(tlp=tl; tlp->inst; tlp++){ /* assignment = */
+ for(inst = tlp->inst; ; inst = inst->u2.next){
+ switch(inst->type){
+ case RUNE: /* regular character */
+ if(inst->u1.r == r){
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ }
+ break;
+ case LBRA:
+ tlp->se.m[inst->u1.subid].s.sp = s;
+ continue;
+ case RBRA:
+ tlp->se.m[inst->u1.subid].e.ep = s;
+ continue;
+ case ANY:
+ if(r != '\n')
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case ANYNL:
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case BOL:
+ if(s == bol || *(s-1) == '\n')
+ continue;
+ break;
+ case EOL:
+ if(s == j->eol || r == 0 || r == '\n')
+ continue;
+ break;
+ case CCLASS:
+ ep = inst->u1.cp->end;
+ for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+ if(r >= rp[0] && r <= rp[1]){
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ }
+ break;
+ case NCCLASS:
+ ep = inst->u1.cp->end;
+ for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+ if(r >= rp[0] && r <= rp[1])
+ break;
+ if(rp == ep)
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case OR:
+ /* evaluate right choice later */
+ if(_renewthread(tlp, inst->u1.right, &tlp->se) == tle)
+ return -1;
+ /* efficiency: advance and re-evaluate */
+ continue;
+ case END: /* Match! */
+ match = 1;
+ tlp->se.m[0].e.ep = s;
+ if(mp != 0)
+ _renewmatch(mp, ms, &tlp->se);
+ break;
+ }
+ break;
+ }
+ }
+ if(s == j->eol)
+ break;
+ checkstart = j->starttype && nl->inst==0;
+ s += n;
+ }while(r);
+ return match;
+}
+
+static int
+regexec2(Reprog *progp, /* program to run */
+ char *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms, /* number of elements at mp */
+ Reljunk *j
+)
+{
+ Relist relist0[BIGLISTSIZE], relist1[BIGLISTSIZE];
+
+ /* mark space */
+ j->relist[0] = relist0;
+ j->relist[1] = relist1;
+ j->reliste[0] = relist0 + nelem(relist0) - 2;
+ j->reliste[1] = relist1 + nelem(relist1) - 2;
+
+ return regexec1(progp, bol, mp, ms, j);
+}
+
+extern int
+regexec(Reprog *progp, /* program to run */
+ char *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms) /* number of elements at mp */
+{
+ Reljunk j;
+ Relist relist0[LISTSIZE], relist1[LISTSIZE];
+ int rv;
+
+ /*
+ * use user-specified starting/ending location if specified
+ */
+ j.starts = bol;
+ j.eol = 0;
+ if(mp && ms>0){
+ if(mp->s.sp)
+ j.starts = mp->s.sp;
+ if(mp->e.ep)
+ j.eol = mp->e.ep;
+ }
+ j.starttype = 0;
+ j.startchar = 0;
+ if(progp->startinst->type == RUNE && progp->startinst->u1.r < (Rune)Runeself) {
+ j.starttype = RUNE;
+ j.startchar = progp->startinst->u1.r;
+ }
+ if(progp->startinst->type == BOL)
+ j.starttype = BOL;
+
+ /* mark space */
+ j.relist[0] = relist0;
+ j.relist[1] = relist1;
+ j.reliste[0] = relist0 + nelem(relist0) - 2;
+ j.reliste[1] = relist1 + nelem(relist1) - 2;
+
+ rv = regexec1(progp, bol, mp, ms, &j);
+ if(rv >= 0)
+ return rv;
+ rv = regexec2(progp, bol, mp, ms, &j);
+ if(rv >= 0)
+ return rv;
+ return -1;
+}
diff --git a/utils/libregexp/regsub.c b/utils/libregexp/regsub.c
new file mode 100644
index 00000000..f789dd97
--- /dev/null
+++ b/utils/libregexp/regsub.c
@@ -0,0 +1,55 @@
+#include <lib9.h>
+#include "regexp.h"
+
+/* substitute into one string using the matches from the last regexec() */
+extern void
+regsub(char *sp, /* source string */
+ char *dp, /* destination string */
+ Resub *mp, /* subexpression elements */
+ int ms) /* number of elements pointed to by mp */
+{
+ char *ssp;
+ int i;
+
+ while(*sp != '\0'){
+ if(*sp == '\\'){
+ switch(*++sp){
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i = *sp-'0';
+ if(mp[i].s.sp != 0 && mp!=0 && ms>i)
+ for(ssp = mp[i].s.sp;
+ ssp < mp[i].e.ep;
+ ssp++)
+ *dp++ = *ssp;
+ break;
+ case '\\':
+ *dp++ = '\\';
+ break;
+ case '\0':
+ sp--;
+ break;
+ default:
+ *dp++ = *sp;
+ break;
+ }
+ }else if(*sp == '&'){
+ if(mp[0].s.sp != 0 && mp!=0 && ms>0)
+ if(mp[0].s.sp != 0)
+ for(ssp = mp[0].s.sp;
+ ssp < mp[0].e.ep; ssp++)
+ *dp++ = *ssp;
+ }else
+ *dp++ = *sp;
+ sp++;
+ }
+ *dp = '\0';
+}
diff --git a/utils/libregexp/rregexec.c b/utils/libregexp/rregexec.c
new file mode 100644
index 00000000..6a4f85e2
--- /dev/null
+++ b/utils/libregexp/rregexec.c
@@ -0,0 +1,213 @@
+#include <lib9.h>
+#include "regexp.h"
+#include "regcomp.h"
+
+/*
+ * return 0 if no match
+ * >0 if a match
+ * <0 if we ran out of _relist space
+ */
+static int
+rregexec1(Reprog *progp, /* program to run */
+ Rune *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms, /* number of elements at mp */
+ Reljunk *j)
+{
+ int flag=0;
+ Reinst *inst;
+ Relist *tlp;
+ Rune *s;
+ int i, checkstart;
+ Rune r, *rp, *ep;
+ Relist* tl; /* This list, next list */
+ Relist* nl;
+ Relist* tle; /* ends of this and next list */
+ Relist* nle;
+ int match;
+
+ match = 0;
+ checkstart = j->startchar;
+ if(mp)
+ for(i=0; i<ms; i++) {
+ mp[i].s.rsp = 0;
+ mp[i].e.rep = 0;
+ }
+ j->relist[0][0].inst = 0;
+ j->relist[1][0].inst = 0;
+
+ /* Execute machine once for each character, including terminal NUL */
+ s = j->rstarts;
+ do{
+
+ /* fast check for first char */
+ if(checkstart) {
+ switch(j->starttype) {
+ case RUNE:
+ while(*s != j->startchar) {
+ if(*s == 0 || s == j->reol)
+ return match;
+ s++;
+ }
+ break;
+ case BOL:
+ if(s == bol)
+ break;
+ while(*s != '\n') {
+ if(*s == 0 || s == j->reol)
+ return match;
+ s++;
+ }
+ break;
+ }
+ }
+
+ r = *s;
+
+ /* switch run lists */
+ tl = j->relist[flag];
+ tle = j->reliste[flag];
+ nl = j->relist[flag^=1];
+ nle = j->reliste[flag];
+ nl->inst = 0;
+
+ /* Add first instruction to current list */
+ _rrenewemptythread(tl, progp->startinst, s);
+
+ /* Execute machine until current list is empty */
+ for(tlp=tl; tlp->inst; tlp++){
+ for(inst=tlp->inst; ; inst = inst->u2.next){
+ switch(inst->type){
+ case RUNE: /* regular character */
+ if(inst->u1.r == r)
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case LBRA:
+ tlp->se.m[inst->u1.subid].s.rsp = s;
+ continue;
+ case RBRA:
+ tlp->se.m[inst->u1.subid].e.rep = s;
+ continue;
+ case ANY:
+ if(r != '\n')
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case ANYNL:
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case BOL:
+ if(s == bol || *(s-1) == '\n')
+ continue;
+ break;
+ case EOL:
+ if(s == j->reol || r == 0 || r == '\n')
+ continue;
+ break;
+ case CCLASS:
+ ep = inst->u1.cp->end;
+ for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+ if(r >= rp[0] && r <= rp[1]){
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ }
+ break;
+ case NCCLASS:
+ ep = inst->u1.cp->end;
+ for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+ if(r >= rp[0] && r <= rp[1])
+ break;
+ if(rp == ep)
+ if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+ return -1;
+ break;
+ case OR:
+ /* evaluate right choice later */
+ if(_renewthread(tlp, inst->u1.right, &tlp->se) == tle)
+ return -1;
+ /* efficiency: advance and re-evaluate */
+ continue;
+ case END: /* Match! */
+ match = 1;
+ tlp->se.m[0].e.rep = s;
+ if(mp != 0)
+ _renewmatch(mp, ms, &tlp->se);
+ break;
+ }
+ break;
+ }
+ }
+ if(s == j->reol)
+ break;
+ checkstart = j->startchar && nl->inst==0;
+ s++;
+ }while(r);
+ return match;
+}
+
+static int
+rregexec2(Reprog *progp, /* program to run */
+ Rune *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms, /* number of elements at mp */
+ Reljunk *j
+)
+{
+ Relist relist0[5*LISTSIZE], relist1[5*LISTSIZE];
+
+ /* mark space */
+ j->relist[0] = relist0;
+ j->relist[1] = relist1;
+ j->reliste[0] = relist0 + nelem(relist0) - 2;
+ j->reliste[1] = relist1 + nelem(relist1) - 2;
+
+ return rregexec1(progp, bol, mp, ms, j);
+}
+
+extern int
+rregexec(Reprog *progp, /* program to run */
+ Rune *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms) /* number of elements at mp */
+{
+ Reljunk j;
+ Relist relist0[LISTSIZE], relist1[LISTSIZE];
+ int rv;
+
+ /*
+ * use user-specified starting/ending location if specified
+ */
+ j.rstarts = bol;
+ j.reol = 0;
+ if(mp && ms>0){
+ if(mp->s.sp)
+ j.rstarts = mp->s.rsp;
+ if(mp->e.ep)
+ j.reol = mp->e.rep;
+ }
+ j.starttype = 0;
+ j.startchar = 0;
+ if(progp->startinst->type == RUNE && progp->startinst->u1.r < (Rune)Runeself) {
+ j.starttype = RUNE;
+ j.startchar = progp->startinst->u1.r;
+ }
+ if(progp->startinst->type == BOL)
+ j.starttype = BOL;
+
+ /* mark space */
+ j.relist[0] = relist0;
+ j.relist[1] = relist1;
+ j.reliste[0] = relist0 + nelem(relist0) - 2;
+ j.reliste[1] = relist1 + nelem(relist1) - 2;
+
+ rv = rregexec1(progp, bol, mp, ms, &j);
+ if(rv >= 0)
+ return rv;
+ rv = rregexec2(progp, bol, mp, ms, &j);
+ if(rv >= 0)
+ return rv;
+ return -1;
+}
diff --git a/utils/libregexp/rregsub.c b/utils/libregexp/rregsub.c
new file mode 100644
index 00000000..d6251a14
--- /dev/null
+++ b/utils/libregexp/rregsub.c
@@ -0,0 +1,55 @@
+#include <lib9.h>
+#include "regexp.h"
+
+/* substitute into one string using the matches from the last regexec() */
+extern void
+rregsub(Rune *sp, /* source string */
+ Rune *dp, /* destination string */
+ Resub *mp, /* subexpression elements */
+ int ms) /* number of elements pointed to by mp */
+{
+ Rune *ssp;
+ int i;
+
+ while(*sp != '\0'){
+ if(*sp == '\\'){
+ switch(*++sp){
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i = *sp-'0';
+ if(mp[i].s.rsp != 0 && mp!=0 && ms>i)
+ for(ssp = mp[i].s.rsp;
+ ssp < mp[i].e.rep;
+ ssp++)
+ *dp++ = *ssp;
+ break;
+ case '\\':
+ *dp++ = '\\';
+ break;
+ case '\0':
+ sp--;
+ break;
+ default:
+ *dp++ = *sp;
+ break;
+ }
+ }else if(*sp == '&'){
+ if(mp[0].s.rsp != 0 && mp!=0 && ms>0)
+ if(mp[0].s.rsp != 0)
+ for(ssp = mp[0].s.rsp;
+ ssp < mp[0].e.rep; ssp++)
+ *dp++ = *ssp;
+ }else
+ *dp++ = *sp;
+ sp++;
+ }
+ *dp = '\0';
+}
diff --git a/utils/libregexp/test.c b/utils/libregexp/test.c
new file mode 100644
index 00000000..49afd9bb
--- /dev/null
+++ b/utils/libregexp/test.c
@@ -0,0 +1,46 @@
+#include <lib9.h>
+#include <regexp.h>
+
+struct x
+{
+ char *re;
+ char *s;
+ Reprog *p;
+};
+
+struct x t[] = {
+ { "^[^!@]+$", "/bin/upas/aliasmail '&'", 0 },
+ { "^local!(.*)$", "/mail/box/\\1/mbox", 0 },
+ { "^plan9!(.*)$", "\\1", 0 },
+ { "^helix!(.*)$", "\\1", 0 },
+ { "^([^!]+)@([^!@]+)$", "\\2!\\1", 0 },
+ { "^(uk\\.[^!]*)(!.*)$", "/bin/upas/uk2uk '\\1' '\\2'", 0 },
+ { "^[^!]*\\.[^!]*!.*$", "inet!&", 0 },
+ { "^(coma|research|pipe|pyxis|inet|hunny|gauss)!(.*)$", "/mail/lib/qmail '\s' 'net!\\1' '\\2'", 0 },
+ { "^.*$", "/mail/lib/qmail '\s' 'net!research' '&'", 0 },
+ { 0, 0, 0 },
+};
+
+
+
+main(int ac, char **av)
+{
+ Resub rs[10];
+ char dst[128];
+ int n;
+ struct x *tp;
+
+ for(tp = t; tp->re; tp++)
+ tp->p = regcomp(tp->re);
+
+
+ for(tp = t; tp->re; tp++){
+ print("%s VIA %s", av[1], tp->re);
+ if(regexec(tp->p, av[1], rs, 10)){
+ regsub(tp->s, dst, rs, 10);
+ print(" sub %s -> %s", tp->s, dst);
+ }
+ print("\n");
+ }
+ exits(0);
+}
diff --git a/utils/libregexp/test2.c b/utils/libregexp/test2.c
new file mode 100644
index 00000000..e6ec8aa5
--- /dev/null
+++ b/utils/libregexp/test2.c
@@ -0,0 +1,20 @@
+#include <lib9.h>
+#include <regexp.h>
+
+
+main(int ac, char **av)
+{
+ Resub rs[10];
+ Reprog *p;
+ char *s;
+ int i;
+
+ p = regcomp("[^a-z]");
+ s = "\n";
+ if(regexec(p, s, rs, 10))
+ print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep);
+ s = "0";
+ if(regexec(p, s, rs, 10))
+ print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep);
+ exits(0);
+}
diff --git a/utils/md5sum/md5sum.c b/utils/md5sum/md5sum.c
new file mode 100644
index 00000000..11c373d9
--- /dev/null
+++ b/utils/md5sum/md5sum.c
@@ -0,0 +1,61 @@
+#include <lib9.h>
+#include <libsec.h>
+
+#pragma varargck type "M" uchar*
+
+static int
+digestfmt(Fmt *fmt)
+{
+ char buf[MD5dlen*2+1];
+ uchar *p;
+ int i;
+
+ p = va_arg(fmt->args, uchar*);
+ for(i=0; i<MD5dlen; i++)
+ sprint(buf+2*i, "%.2ux", p[i]);
+ return fmtstrcpy(fmt, buf);
+}
+
+static void
+sum(int fd, char *name)
+{
+ int n;
+ uchar buf[8192], digest[MD5dlen];
+ DigestState *s;
+
+ s = md5(nil, 0, nil, nil);
+ while((n = read(fd, buf, sizeof buf)) > 0)
+ md5(buf, n, nil, s);
+ md5(nil, 0, digest, s);
+ if(name == nil)
+ print("%M\n", digest);
+ else
+ print("%M\t%s\n", digest, name);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, fd;
+
+ ARGBEGIN{
+ default:
+ fprint(2, "usage: md5sum [file...]\n");
+ exits("usage");
+ }ARGEND
+
+ fmtinstall('M', digestfmt);
+
+ if(argc == 0)
+ sum(0, nil);
+ else for(i = 0; i < argc; i++){
+ fd = open(argv[i], OREAD);
+ if(fd < 0){
+ fprint(2, "md5sum: can't open %s: %r\n", argv[i]);
+ continue;
+ }
+ sum(fd, argv[i]);
+ close(fd);
+ }
+ exits(nil);
+}
diff --git a/utils/md5sum/mkfile b/utils/md5sum/mkfile
new file mode 100644
index 00000000..462a91ee
--- /dev/null
+++ b/utils/md5sum/mkfile
@@ -0,0 +1,19 @@
+<../../mkconfig
+
+#
+# the md5sum command is needed for the test suite
+#
+
+TARG=md5sum
+
+OFILES= md5sum.$O\
+
+
+HFILES=
+
+LIBS=9 sec
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
diff --git a/utils/mk/Nt.c b/utils/mk/Nt.c
new file mode 100644
index 00000000..002807bb
--- /dev/null
+++ b/utils/mk/Nt.c
@@ -0,0 +1,442 @@
+#include "mk.h"
+#include <signal.h>
+#include <sys/utime.h>
+
+#define Arc My_Arc /* avoid name conflicts */
+#undef DELETE
+
+#include <windows.h>
+
+enum {
+ Nchild = 100,
+};
+
+char *rootdir = "c:\\users\\inferno";
+char *shell = "Nt\\386\\bin\\rcsh.exe"; /* Path relative to root */
+
+typedef struct Child Child;
+
+struct Child {
+ int pid;
+ HANDLE handle;
+};
+
+static Child child[Nchild];
+
+extern char **environ;
+
+DWORD WINAPI writecmd(LPVOID a);
+
+void
+readenv(void)
+{
+ char **p, *s;
+ Word *w;
+
+ for(p = environ; *p; p++){
+ s = shname(*p);
+ if(*s == '=') {
+ *s = 0;
+ w = newword(s+1);
+ } else
+ w = newword("");
+ if (symlook(*p, S_INTERNAL, 0))
+ continue;
+ s = strdup(*p);
+ setvar(s, (void *)w);
+ symlook(s, S_EXPORTED, (void *)"")->value = "";
+ }
+}
+
+char *
+exportenv(Envy *e)
+{
+ int i, n;
+ char *buf, *v;
+
+ buf = 0;
+ n = 0;
+ for(i = 0; e->name; e++, i++) {
+ /* word separator is shell-dependent */
+ if(e->values)
+ v = wtos(e->values, IWS);
+ else
+ v = "";
+ buf = Realloc(buf, n+strlen(e->name)+1+strlen(v)+1);
+
+ n += sprint(buf+n, "%s=%s", e->name, v);
+ n++; /* skip over null */
+ if(e->values)
+ free(v);
+ }
+ /* final null */
+ buf = Realloc(buf, n+1);
+ buf[n] = 0;
+
+ return buf;
+}
+
+int
+waitfor(char *msg)
+{
+ int pid, n, i, r, code;
+ HANDLE tab[Nchild];
+
+ for(i=0,n=0; i<Nchild; i++)
+ if(child[i].handle != 0)
+ tab[n++] = child[i].handle;
+
+ if(n == 0)
+ return -1;
+
+ r = WaitForMultipleObjects(n, tab, 0, INFINITE);
+
+ r -= WAIT_OBJECT_0;
+ if(r<0 || r>=n) {
+ perror("wait failed");
+ exits("wait failed");
+ }
+
+ for(i=0; i<Nchild; i++)
+ if(child[i].handle == tab[r])
+ break;
+ if(i == Nchild){
+ snprint(msg, ERRMAX, "unknown child (%lux)", tab[r]);
+ return -1;
+ }
+
+ if(msg) {
+ *msg = 0;
+ if(GetExitCodeProcess(child[i].handle, &code) == FALSE)
+ snprint(msg, ERRMAX, "unknown exit code");
+ else if(code != 0)
+ snprint(msg, ERRMAX, "exit(%d)", code);
+ }
+
+ CloseHandle(child[i].handle);
+ child[i].handle = 0;
+ pid = child[i].pid;
+ child[i].pid = 0;
+
+ return pid;
+}
+
+void
+expunge(int pid, char *msg)
+{
+/*
+ if(strcmp(msg, "interrupt"))
+ kill(pid, SIGINT);
+ else
+ kill(pid, SIGHUP);
+*/
+}
+
+HANDLE
+duphandle(HANDLE h)
+{
+ HANDLE r;
+
+ if(DuplicateHandle(GetCurrentProcess(), h,
+ GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS,
+ 1, DUPLICATE_SAME_ACCESS) == FALSE) {
+ perror("dup handle");
+ Exit();
+ }
+
+ return r;
+}
+
+void
+childadd(HANDLE h, int pid)
+{
+ int i;
+
+ for(i=0; i<Nchild; i++) {
+ if(child[i].handle == 0) {
+ child[i].handle = h;
+ child[i].pid = pid;
+ return;
+ }
+ }
+ perror("child table full");
+ Exit();
+}
+
+static DWORD WINAPI
+spinoff(HANDLE in, HANDLE out, char *args, char *cmd, Envy *e)
+{
+ char args2[4096], path[MAX_PATH], *s, *eb;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ Symtab *sym;
+
+
+ /* set up the full path of the shell */
+ sym = symlook("MKSH", S_VAR, 0);
+ if(sym){
+ strncpy(path, ((Word*)(sym->value))->s, sizeof(path));
+ path[MAX_PATH-1] = 0;
+ }else{
+ sym = symlook("ROOT", S_VAR, 0);
+ if(sym)
+ rootdir = ((Word*)(sym->value))->s;
+ snprint(path, sizeof(path), "%s\\%s", rootdir, shell);
+ }
+ /* convert to backslash notation */
+ for(s = strchr(path,'/'); s; s = strchr(s+1, '/'))
+ *s = '\\';
+
+ s = args2;
+ s += snprint(args2, sizeof(args2)-1, "%s", path);
+ if(shflags)
+ s += snprint(s, args2+sizeof(args2)-s-1, " %s", shflags);
+ if(args)
+ s += snprint(s, args2+sizeof(args2)-s-1, " %s", args);
+ if(cmd)
+ s += snprint(s, args2+sizeof(args2)-s-1, " \"%s\"", cmd);
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
+ si.wShowWindow = SW_SHOW;
+
+ if (e)
+ eb = exportenv(e);
+ else
+ eb = 0;
+ si.hStdInput = duphandle(in);
+ si.hStdOutput = duphandle(out);
+ si.hStdError = duphandle(GetStdHandle(STD_ERROR_HANDLE));
+ if(CreateProcess(path, args2, 0, 0, 1, 0, eb, 0, &si, &pi) == FALSE) {
+ perror("can't find shell");
+ Exit();
+ }
+
+ free(eb);
+
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+
+ childadd(pi.hProcess, pi.dwProcessId);
+ return pi.dwProcessId;
+}
+
+int
+execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
+{
+ int tot, n, tid, pid;
+ HANDLE outin, outout, inout, inin;
+ struct { char *cmd; HANDLE handle; } *arg;
+
+ if(buf == 0)
+ outout = GetStdHandle(STD_OUTPUT_HANDLE);
+ else
+ if(CreatePipe(&outin, &outout, 0, 0) == FALSE){
+ perror("pipe");
+ Exit();
+ }
+
+ if(CreatePipe(&inin, &inout, 0, 0) == FALSE){
+ perror("pipe");
+ Exit();
+ }
+
+ arg = malloc(sizeof(*arg));
+ arg->cmd = strdup(cmd);
+ arg->handle = inout;
+ if(CreateThread(0, 0, writecmd, arg, 0, &tid) == FALSE) {
+ perror("spawn writecmd");
+ Exit();
+ }
+
+ pid = spinoff(inin, outout, args, 0, e);
+ CloseHandle(inin);
+
+ if(DEBUG(D_EXEC))
+ fprint(1, "starting: %s\n", cmd);
+
+ if(buf){
+ CloseHandle(outout);
+ tot = 0;
+ for(;;){
+ if (buf->current >= buf->end)
+ growbuf(buf);
+ if(ReadFile(outin, buf->current, buf->end-buf->current, &n, 0) == FALSE)
+ break;
+ buf->current += n;
+ tot += n;
+ }
+ if (tot && buf->current[-1] == '\n')
+ buf->current--;
+ CloseHandle(outin);
+ }
+
+ return pid;
+}
+
+static DWORD WINAPI
+writecmd(LPVOID a)
+{
+ struct {char *cmd; HANDLE handle;} *arg;
+ char *cmd, *p;
+ int n;
+
+ arg = a;
+ cmd = arg->cmd;
+ p = cmd+strlen(cmd);
+ while(cmd < p){
+ if(WriteFile(arg->handle, cmd, p-cmd, &n, 0) == FALSE)
+ break;
+ cmd += n;
+ }
+
+ free(arg->cmd);
+ CloseHandle(arg->handle);
+ free(arg);
+ ExitThread(0);
+ return 0;
+}
+
+int
+pipecmd(char *cmd, Envy *e, int *fd)
+{
+ int pid;
+ HANDLE pipein, pipeout;
+
+ if(fd){
+ if(CreatePipe(&pipein, &pipeout, 0, 0) == FALSE){
+ perror("pipe");
+ Exit();
+ }
+ } else
+ pipeout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+
+ pid = spinoff(GetStdHandle(STD_INPUT_HANDLE), pipeout, "-c", cmd, e);
+
+ if(fd){
+ CloseHandle(pipeout);
+ *fd = _open_osfhandle((long)pipein, 0);
+ }
+ return pid;
+}
+
+void
+Exit(void)
+{
+ while(waitfor(0) != -1)
+ ;
+ exits("error");
+}
+
+void
+catchnotes()
+{
+}
+
+char*
+maketmp(void)
+{
+ static char temp[] = "mkargXXX.XXX";
+
+ mktemp(temp);
+ return temp;
+}
+
+Dir*
+mkdirstat(char *name)
+{
+ int c, n, ret;
+ Dir *buf;
+
+ n = strlen(name)-1;
+ c = name[n];
+ if(c == '/' || c == '\\')
+ name[n] = 0;
+ buf = dirstat(name);
+ name[n] = c;
+ return buf;
+}
+
+int
+chgtime(char *name)
+{
+ Dir *sbuf;
+ struct utimbuf u;
+
+ if((sbuf = mkdirstat(name)) != nil){
+ u.actime = sbuf->atime;
+ u.modtime = time(0);
+ free(sbuf);
+ return utime(name, &u);
+ }
+ return close(create(name, OWRITE, 0666));
+}
+
+void
+rcopy(char **to, Resub *match, int n)
+{
+ int c;
+ char *p;
+
+ *to = match->s.sp; /* stem0 matches complete target */
+ for(to++, match++; --n > 0; to++, match++){
+ if(match->s.sp && match->e.ep){
+ p = match->e.ep;
+ c = *p;
+ *p = 0;
+ *to = strdup(match->s.sp);
+ *p = c;
+ } else
+ *to = 0;
+ }
+}
+
+ulong
+mkmtime(char *name)
+{
+ Dir *buf;
+ ulong t;
+ int n;
+ char *s;
+
+ n = strlen(name)-1;
+ if(n >= 0 && (name[n] == '/' || name[n] == '\\')){
+ s = strdup(name);
+ s[n] = 0;
+ }else
+ s = name;
+ buf = dirstat(s);
+ if(buf == nil){
+ if(s != name)
+ free(s);
+ return 0;
+ }
+ t = buf->mtime;
+ free(buf);
+ if(s != name)
+ free(s);
+ return t;
+}
+
+char *stab;
+
+char *
+membername(char *s, int fd, char *sz)
+{
+ long t;
+
+ if(s[0] == '/' && s[1] == '\0'){ /* long file name string table */
+ t = atol(sz);
+ if(t&01) t++;
+ stab = malloc(t);
+ read(fd, stab, t);
+ return nil;
+ }
+ else if(s[0] == '/' && stab != nil) /* index into string table */
+ return stab+atol(s+1);
+ else
+ return s;
+}
diff --git a/utils/mk/Plan9.c b/utils/mk/Plan9.c
new file mode 100644
index 00000000..66c4d925
--- /dev/null
+++ b/utils/mk/Plan9.c
@@ -0,0 +1,363 @@
+#include "mk.h"
+
+char *shell = "/bin/rc";
+char *shellname = "rc";
+
+static Word *encodenulls(char*, int);
+
+void
+readenv(void)
+{
+ char *p;
+ int envf, f;
+ Dir *e;
+ char nam[1024];
+ int i, n, len;
+ Word *w;
+
+ rfork(RFENVG); /* use copy of the current environment variables */
+
+ envf = open("/env", OREAD);
+ if(envf < 0)
+ return;
+ while((n = dirread(envf, &e)) > 0){
+ for(i = 0; i < n; i++){
+ len = e[i].length;
+ /* don't import funny names, NULL values,
+ * or internal mk variables
+ */
+ if(len <= 0 || *shname(e[i].name) != '\0')
+ continue;
+ if (symlook(e[i].name, S_INTERNAL, 0))
+ continue;
+ sprint(nam, "/env/%s", e[i].name);
+ f = open(nam, OREAD);
+ if(f < 0)
+ continue;
+ p = Malloc(len+1);
+ if(read(f, p, len) != len){
+ perror(nam);
+ close(f);
+ continue;
+ }
+ close(f);
+ if (p[len-1] == 0)
+ len--;
+ else
+ p[len] = 0;
+ w = encodenulls(p, len);
+ free(p);
+ p = strdup(e[i].name);
+ setvar(p, (void *) w);
+ symlook(p, S_EXPORTED, (void*)"")->value = (void*)"";
+ }
+ free(e);
+ }
+ close(envf);
+}
+
+/* break string of values into words at 01's or nulls*/
+static Word *
+encodenulls(char *s, int n)
+{
+ Word *w, *head;
+ char *cp;
+
+ head = w = 0;
+ while (n-- > 0) {
+ for (cp = s; *cp && *cp != '\0'; cp++)
+ n--;
+ *cp = 0;
+ if (w) {
+ w->next = newword(s);
+ w = w->next;
+ } else
+ head = w = newword(s);
+ s = cp+1;
+ }
+ if (!head)
+ head = newword("");
+ return head;
+}
+
+/* as well as 01's, change blanks to nulls, so that rc will
+ * treat the words as separate arguments
+ */
+void
+exportenv(Envy *e)
+{
+ int f, n, hasvalue, first;
+ Word *w;
+ Symtab *sy;
+ char nam[256];
+
+ for(;e->name; e++){
+ sy = symlook(e->name, S_VAR, 0);
+ if (e->values == 0 || e->values->s == 0 || e->values->s[0] == 0)
+ hasvalue = 0;
+ else
+ hasvalue = 1;
+ if(sy == 0 && !hasvalue) /* non-existant null symbol */
+ continue;
+ sprint(nam, "/env/%s", e->name);
+ if (sy != 0 && !hasvalue) { /* Remove from environment */
+ /* we could remove it from the symbol table
+ * too, but we're in the child copy, and it
+ * would still remain in the parent's table.
+ */
+ remove(nam);
+ delword(e->values);
+ e->values = 0; /* memory leak */
+ continue;
+ }
+
+ f = create(nam, OWRITE, 0666L);
+ if(f < 0) {
+ fprint(2, "can't create %s, f=%d\n", nam, f);
+ perror(nam);
+ continue;
+ }
+ first = 1;
+ for (w = e->values; w; w = w->next) {
+ n = strlen(w->s);
+ if (n) {
+ if(first)
+ first = 0;
+ else{
+ if (write (f, "\0", 1) != 1)
+ perror(nam);
+ }
+ if (write(f, w->s, n) != n)
+ perror(nam);
+ }
+ }
+ close(f);
+ }
+}
+
+int
+waitfor(char *msg)
+{
+ Waitmsg *w;
+ int pid;
+
+ if((w=wait()) == nil)
+ return -1;
+ strecpy(msg, msg+ERRMAX, w->msg);
+ pid = w->pid;
+ free(w);
+ return pid;
+}
+
+void
+expunge(int pid, char *msg)
+{
+ postnote(PNPROC, pid, msg);
+}
+
+int
+execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
+{
+ char *p;
+ int tot, n, pid, in[2], out[2];
+
+ if(buf && pipe(out) < 0){
+ perror("pipe");
+ Exit();
+ }
+ pid = rfork(RFPROC|RFFDG|RFENVG);
+ if(pid < 0){
+ perror("mk rfork");
+ Exit();
+ }
+ if(pid == 0){
+ if(buf)
+ close(out[0]);
+ if(pipe(in) < 0){
+ perror("pipe");
+ Exit();
+ }
+ pid = fork();
+ if(pid < 0){
+ perror("mk fork");
+ Exit();
+ }
+ if(pid != 0){
+ dup(in[0], 0);
+ if(buf){
+ dup(out[1], 1);
+ close(out[1]);
+ }
+ close(in[0]);
+ close(in[1]);
+ if (e)
+ exportenv(e);
+ if(shflags)
+ execl(shell, shellname, shflags, args, nil);
+ else
+ execl(shell, shellname, args, nil);
+ perror(shell);
+ _exits("exec");
+ }
+ close(out[1]);
+ close(in[0]);
+ p = cmd+strlen(cmd);
+ while(cmd < p){
+ n = write(in[1], cmd, p-cmd);
+ if(n < 0)
+ break;
+ cmd += n;
+ }
+ close(in[1]);
+ _exits(0);
+ }
+ if(buf){
+ close(out[1]);
+ tot = 0;
+ for(;;){
+ if (buf->current >= buf->end)
+ growbuf(buf);
+ n = read(out[0], buf->current, buf->end-buf->current);
+ if(n <= 0)
+ break;
+ buf->current += n;
+ tot += n;
+ }
+ if (tot && buf->current[-1] == '\n')
+ buf->current--;
+ close(out[0]);
+ }
+ return pid;
+}
+
+int
+pipecmd(char *cmd, Envy *e, int *fd)
+{
+ int pid, pfd[2];
+
+ if(DEBUG(D_EXEC))
+ fprint(1, "pipecmd='%s'\n", cmd);/**/
+
+ if(fd && pipe(pfd) < 0){
+ perror("pipe");
+ Exit();
+ }
+ pid = rfork(RFPROC|RFFDG|RFENVG);
+ if(pid < 0){
+ perror("mk fork");
+ Exit();
+ }
+ if(pid == 0){
+ if(fd){
+ close(pfd[0]);
+ dup(pfd[1], 1);
+ close(pfd[1]);
+ }
+ if(e)
+ exportenv(e);
+ if(shflags)
+ execl(shell, shellname, shflags, "-c", cmd, nil);
+ else
+ execl(shell, shellname, "-c", cmd, nil);
+ perror(shell);
+ _exits("exec");
+ }
+ if(fd){
+ close(pfd[1]);
+ *fd = pfd[0];
+ }
+ return pid;
+}
+
+void
+Exit(void)
+{
+ while(waitpid() >= 0)
+ ;
+ exits("error");
+}
+
+int
+notifyf(void *a, char *msg)
+{
+ static int nnote;
+
+ USED(a);
+ if(++nnote > 100){ /* until andrew fixes his program */
+ fprint(2, "mk: too many notes\n");
+ notify(0);
+ abort();
+ }
+ if(strcmp(msg, "interrupt")!=0 && strcmp(msg, "hangup")!=0)
+ return 0;
+ killchildren(msg);
+ return -1;
+}
+
+void
+catchnotes()
+{
+ atnotify(notifyf, 1);
+}
+
+char*
+maketmp(void)
+{
+ static char temp[] = "/tmp/mkargXXXXXX";
+
+ mktemp(temp);
+ return temp;
+}
+
+int
+chgtime(char *name)
+{
+ Dir sbuf;
+
+ if(access(name, AEXIST) >= 0) {
+ nulldir(&sbuf);
+ sbuf.mtime = time((long *)0);
+ return dirwstat(name, &sbuf);
+ }
+ return close(create(name, OWRITE, 0666));
+}
+
+void
+rcopy(char **to, Resub *match, int n)
+{
+ int c;
+ char *p;
+
+ *to = match->s.sp; /* stem0 matches complete target */
+ for(to++, match++; --n > 0; to++, match++){
+ if(match->s.sp && match->e.ep){
+ p = match->e.ep;
+ c = *p;
+ *p = 0;
+ *to = strdup(match->s.sp);
+ *p = c;
+ }
+ else
+ *to = 0;
+ }
+}
+
+ulong
+mkmtime(char *name)
+{
+ Dir *buf;
+ ulong t;
+
+ buf = dirstat(name);
+ if(buf == nil)
+ return 0;
+ t = buf->mtime;
+ free(buf);
+ return t;
+}
+
+char *
+membername(char *s, int, char*)
+{
+ return s;
+}
diff --git a/utils/mk/Posix.c b/utils/mk/Posix.c
new file mode 100644
index 00000000..63ad17f5
--- /dev/null
+++ b/utils/mk/Posix.c
@@ -0,0 +1,331 @@
+#include "mk.h"
+#include <dirent.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <utime.h>
+#include <stdio.h>
+
+char *shell = "/bin/sh";
+char *shellname = "sh";
+
+extern char **environ;
+
+void
+readenv(void)
+{
+ char **p, *s;
+ Word *w;
+
+ for(p = environ; *p; p++){
+ s = shname(*p);
+ if(*s == '=') {
+ *s = 0;
+ w = newword(s+1);
+ } else
+ w = newword("");
+ if (symlook(*p, S_INTERNAL, 0))
+ continue;
+ s = strdup(*p);
+ setvar(s, (void *)w);
+ symlook(s, S_EXPORTED, (void*)"")->value = (void*)"";
+ }
+}
+
+/*
+ * done on child side of fork, so parent's env is not affected
+ * and we don't care about freeing memory because we're going
+ * to exec immediately after this.
+ */
+void
+exportenv(Envy *e)
+{
+ int i;
+ char **p;
+ char *values;
+
+ p = 0;
+ for(i = 0; e->name; e++, i++) {
+ p = (char**) Realloc(p, (i+2)*sizeof(char*));
+ if (e->values)
+ values = wtos(e->values, IWS);
+ else
+ values = "";
+ p[i] = malloc(strlen(e->name) + strlen(values) + 2);
+ sprint(p[i], "%s=%s", e->name, values);
+ }
+ p[i] = 0;
+ environ = p;
+}
+
+int
+waitfor(char *msg)
+{
+ int status;
+ int pid;
+
+ *msg = 0;
+ pid = wait(&status);
+ if(pid > 0) {
+ if(status&0x7f) {
+ if(status&0x80)
+ snprint(msg, ERRMAX, "signal %d, core dumped", status&0x7f);
+ else
+ snprint(msg, ERRMAX, "signal %d", status&0x7f);
+ } else if(status&0xff00)
+ snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff);
+ }
+ return pid;
+}
+
+void
+expunge(int pid, char *msg)
+{
+ if(strcmp(msg, "interrupt"))
+ kill(pid, SIGINT);
+ else
+ kill(pid, SIGHUP);
+}
+
+int
+execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
+{
+ char *p;
+ int tot, n, pid, in[2], out[2];
+
+ if(buf && pipe(out) < 0){
+ perror("pipe");
+ Exit();
+ }
+ pid = fork();
+ if(pid < 0){
+ perror("mk fork");
+ Exit();
+ }
+ if(pid == 0){
+ if(buf)
+ close(out[0]);
+ if(pipe(in) < 0){
+ perror("pipe");
+ Exit();
+ }
+ pid = fork();
+ if(pid < 0){
+ perror("mk fork");
+ Exit();
+ }
+ if(pid != 0){
+ dup2(in[0], 0);
+ if(buf){
+ dup2(out[1], 1);
+ close(out[1]);
+ }
+ close(in[0]);
+ close(in[1]);
+ if (e)
+ exportenv(e);
+ if(shflags)
+ execl(shell, shellname, shflags, args, nil);
+ else
+ execl(shell, shellname, args, nil);
+ perror(shell);
+ _exits("exec");
+ }
+ close(out[1]);
+ close(in[0]);
+ if(DEBUG(D_EXEC))
+ fprint(1, "starting: %s\n", cmd);
+ p = cmd+strlen(cmd);
+ while(cmd < p){
+ n = write(in[1], cmd, p-cmd);
+ if(n < 0)
+ break;
+ cmd += n;
+ }
+ close(in[1]);
+ _exits(0);
+ }
+ if(buf){
+ close(out[1]);
+ tot = 0;
+ for(;;){
+ if (buf->current >= buf->end)
+ growbuf(buf);
+ n = read(out[0], buf->current, buf->end-buf->current);
+ if(n <= 0)
+ break;
+ buf->current += n;
+ tot += n;
+ }
+ if (tot && buf->current[-1] == '\n')
+ buf->current--;
+ close(out[0]);
+ }
+ return pid;
+}
+
+int
+pipecmd(char *cmd, Envy *e, int *fd)
+{
+ int pid, pfd[2];
+
+ if(DEBUG(D_EXEC))
+ fprint(1, "pipecmd='%s'\n", cmd);/**/
+
+ if(fd && pipe(pfd) < 0){
+ perror("pipe");
+ Exit();
+ }
+ pid = fork();
+ if(pid < 0){
+ perror("mk fork");
+ Exit();
+ }
+ if(pid == 0){
+ if(fd){
+ close(pfd[0]);
+ dup2(pfd[1], 1);
+ close(pfd[1]);
+ }
+ if(e)
+ exportenv(e);
+ if(shflags)
+ execl(shell, shellname, shflags, "-c", cmd, nil);
+ else
+ execl(shell, shellname, "-c", cmd, nil);
+ perror(shell);
+ _exits("exec");
+ }
+ if(fd){
+ close(pfd[1]);
+ *fd = pfd[0];
+ }
+ return pid;
+}
+
+void
+Exit(void)
+{
+ while(wait(0) >= 0)
+ ;
+ exits("error");
+}
+
+static struct
+{
+ int sig;
+ char *msg;
+} sigmsgs[] =
+{
+ SIGALRM, "alarm",
+ SIGFPE, "sys: fp: fptrap",
+ SIGPIPE, "sys: write on closed pipe",
+ SIGILL, "sys: trap: illegal instruction",
+ SIGSEGV, "sys: segmentation violation",
+ 0, 0
+};
+
+static void
+notifyf(int sig)
+{
+ int i;
+
+ for(i = 0; sigmsgs[i].msg; i++)
+ if(sigmsgs[i].sig == sig)
+ killchildren(sigmsgs[i].msg);
+
+ /* should never happen */
+ signal(sig, SIG_DFL);
+ kill(getpid(), sig);
+}
+
+void
+catchnotes()
+{
+ int i;
+
+ for(i = 0; sigmsgs[i].msg; i++)
+ signal(sigmsgs[i].sig, notifyf);
+}
+
+char*
+maketmp(void)
+{
+ static char temp[L_tmpnam];
+
+ return tmpnam(temp);
+}
+
+int
+chgtime(char *name)
+{
+ Dir *sbuf;
+ struct utimbuf u;
+
+ if((sbuf = dirstat(name)) != nil) {
+ u.actime = sbuf->atime;
+ free(sbuf);
+ u.modtime = time(0);
+ return utime(name, &u);
+ }
+ return close(create(name, OWRITE, 0666));
+}
+
+void
+rcopy(char **to, Resub *match, int n)
+{
+ int c;
+ char *p;
+
+ *to = match->s.sp; /* stem0 matches complete target */
+ for(to++, match++; --n > 0; to++, match++){
+ if(match->s.sp && match->e.ep){
+ p = match->e.ep;
+ c = *p;
+ *p = 0;
+ *to = strdup(match->s.sp);
+ *p = c;
+ }
+ else
+ *to = 0;
+ }
+}
+
+ulong
+mkmtime(char *name)
+{
+ Dir *buf;
+ ulong t;
+
+ buf = dirstat(name);
+ if(buf == nil)
+ return 0;
+ t = buf->mtime;
+ free(buf);
+ return t;
+}
+
+
+char *stab;
+
+char *
+membername(char *s, int fd, char *sz)
+{
+ long t;
+ char *p, *q;
+
+ if(s[0] == '/' && s[1] == '\0'){ /* long file name string table */
+ t = atol(sz);
+ if(t&01) t++;
+ stab = malloc(t);
+ read(fd, stab, t);
+ return nil;
+ }
+ else if(s[0] == '/' && stab != nil) { /* index into string table */
+ p = stab+atol(s+1);
+ q = strchr(p, '/');
+ if (q)
+ *q = 0; /* terminate string here */
+ return p;
+ }else
+ return s;
+}
diff --git a/utils/mk/README b/utils/mk/README
new file mode 100644
index 00000000..092c96a4
--- /dev/null
+++ b/utils/mk/README
@@ -0,0 +1,26 @@
+Using the delivered mk to rebuild mk.
+
+You should be able to use the delivered executable of mk to
+build a new executable. This may be of particular interest
+on Windows NT/Win95 where the path of the shell program
+can be hard-coded by changing the variable named "shell"
+near the beginning of source file Nt.c.
+
+Mk uses the regular expression library, so build
+the program as follows:
+
+1. ensure that ../../mkconfig contains the proper system definitions
+
+2. ensure that the system libraries lib9, libbio, and libregexp have
+ been built. you can do this by hand by changing to ../lib9,
+ ../libbio, and ../libregexp and doing "mk nuke" and a "mk install"
+ in each.
+
+3. in this directory
+ mk nuke
+ mk install
+
+4. on NT/Win95 the executable must be installed by hand because the current
+ executable is locked down while it is executing:
+
+ mv obj.out ../../Nt/386/bin/mk.exe
diff --git a/utils/mk/arc.c b/utils/mk/arc.c
new file mode 100644
index 00000000..521ef7a7
--- /dev/null
+++ b/utils/mk/arc.c
@@ -0,0 +1,52 @@
+#include "mk.h"
+
+Arc *
+newarc(Node *n, Rule *r, char *stem, Resub *match)
+{
+ Arc *a;
+
+ a = (Arc *)Malloc(sizeof(Arc));
+ a->n = n;
+ a->r = r;
+ a->stem = strdup(stem);
+ rcopy(a->match, match, NREGEXP);
+ a->next = 0;
+ a->flag = 0;
+ a->prog = r->prog;
+ return(a);
+}
+
+void
+dumpa(char *s, Arc *a)
+{
+ char buf[1024];
+
+ Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'",
+ s, a, a->n, a->r, a->flag, a->stem);
+ if(a->prog)
+ Bprint(&bout, " prog='%s'", a->prog);
+ Bprint(&bout, "\n");
+
+ if(a->n){
+ snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:"");
+ dumpn(buf, a->n);
+ }
+}
+
+void
+nrep(void)
+{
+ Symtab *sym;
+ Word *w;
+
+ sym = symlook("NREP", S_VAR, 0);
+ if(sym){
+ w = (Word *) sym->value;
+ if (w && w->s && *w->s)
+ nreps = atoi(w->s);
+ }
+ if(nreps < 1)
+ nreps = 1;
+ if(DEBUG(D_GRAPH))
+ Bprint(&bout, "nreps = %d\n", nreps);
+}
diff --git a/utils/mk/archive.c b/utils/mk/archive.c
new file mode 100644
index 00000000..92ed947c
--- /dev/null
+++ b/utils/mk/archive.c
@@ -0,0 +1,169 @@
+#include "mk.h"
+#include <ar.h>
+
+static int dolong;
+
+static void atimes(char *);
+static char *split(char*, char**);
+
+long
+atimeof(int force, char *name)
+{
+ Symtab *sym;
+ long t;
+ char *archive, *member, buf[512];
+
+ archive = split(name, &member);
+ if(archive == 0)
+ Exit();
+
+ t = mtime(archive);
+ sym = symlook(archive, S_AGG, 0);
+ if(sym){
+ if(force || (t > (long)sym->value)){
+ atimes(archive);
+ sym->value = (void *)t;
+ }
+ }
+ else{
+ atimes(archive);
+ /* mark the aggegate as having been done */
+ symlook(strdup(archive), S_AGG, "")->value = (void *)t;
+ }
+ /* truncate long member name to sizeof of name field in archive header */
+ if(dolong)
+ snprint(buf, sizeof(buf), "%s(%s)", archive, member);
+ else
+ snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member);
+ sym = symlook(buf, S_TIME, 0);
+ if (sym)
+ return (long)sym->value; /* uggh */
+ return 0;
+}
+
+void
+atouch(char *name)
+{
+ char *archive, *member;
+ int fd, i;
+ struct ar_hdr h;
+ long t;
+
+ archive = split(name, &member);
+ if(archive == 0)
+ Exit();
+
+ fd = open(archive, ORDWR);
+ if(fd < 0){
+ fd = create(archive, OWRITE, 0666);
+ if(fd < 0){
+ perror(archive);
+ Exit();
+ }
+ write(fd, ARMAG, SARMAG);
+ }
+ if(symlook(name, S_TIME, 0)){
+ /* hoon off and change it in situ */
+ LSEEK(fd, SARMAG, 0);
+ while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
+ for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
+ ;
+ h.name[i+1]=0;
+ if(strcmp(member, h.name) == 0){
+ t = SARNAME-sizeof(h); /* ughgghh */
+ LSEEK(fd, t, 1);
+ fprint(fd, "%-12ld", time(0));
+ break;
+ }
+ t = atol(h.size);
+ if(t&01) t++;
+ LSEEK(fd, t, 1);
+ }
+ }
+ close(fd);
+}
+
+static void
+atimes(char *ar)
+{
+ struct ar_hdr h;
+ long t;
+ int fd, i;
+ char buf[BIGBLOCK];
+ char *n, name[sizeof(h.name)+1];
+
+ fd = open(ar, OREAD);
+ if(fd < 0)
+ return;
+
+ if(read(fd, buf, SARMAG) != SARMAG){
+ close(fd);
+ return;
+ }
+ while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
+ t = atol(h.date);
+ if(t == 0) /* as it sometimes happens; thanks ken */
+ t = 1;
+ strncpy(name, h.name, sizeof(h.name));
+ for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
+ ;
+ if(name[i] == '/') /* system V bug */
+ i--;
+ name[i+1]=0;
+ n = membername(name, fd, h.size);
+ if(n == nil){
+ dolong = 1;
+ continue;
+ }
+ sprint(buf, "%s(%s)", ar, n);
+ symlook(strdup(buf), S_TIME, (void *)t)->value = (void *)t;
+ t = atol(h.size);
+ if(t&01) t++;
+ LSEEK(fd, t, 1);
+ }
+ close(fd);
+}
+
+static int
+type(char *file)
+{
+ int fd;
+ char buf[SARMAG];
+
+ fd = open(file, OREAD);
+ if(fd < 0){
+ if(symlook(file, S_BITCH, 0) == 0){
+ Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
+ symlook(file, S_BITCH, (void *)file);
+ }
+ return 1;
+ }
+ if(read(fd, buf, SARMAG) != SARMAG){
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ return !strncmp(ARMAG, buf, SARMAG);
+}
+
+static char*
+split(char *name, char **member)
+{
+ char *p, *q;
+
+ p = strdup(name);
+ q = utfrune(p, '(');
+ if(q){
+ *q++ = 0;
+ if(member)
+ *member = q;
+ q = utfrune(q, ')');
+ if (q)
+ *q = 0;
+ if(type(p))
+ return p;
+ free(p);
+ fprint(2, "mk: '%s' is not an archive\n", name);
+ }
+ return 0;
+}
diff --git a/utils/mk/bufblock.c b/utils/mk/bufblock.c
new file mode 100644
index 00000000..979403bc
--- /dev/null
+++ b/utils/mk/bufblock.c
@@ -0,0 +1,88 @@
+#include "mk.h"
+
+static Bufblock *freelist;
+#define QUANTA 4096
+
+Bufblock *
+newbuf(void)
+{
+ Bufblock *p;
+
+ if (freelist) {
+ p = freelist;
+ freelist = freelist->next;
+ } else {
+ p = (Bufblock *) Malloc(sizeof(Bufblock));
+ p->start = Malloc(QUANTA*sizeof(*p->start));
+ p->end = p->start+QUANTA;
+ }
+ p->current = p->start;
+ *p->start = 0;
+ p->next = 0;
+ return p;
+}
+
+void
+freebuf(Bufblock *p)
+{
+ p->next = freelist;
+ freelist = p;
+}
+
+void
+growbuf(Bufblock *p)
+{
+ int n;
+ Bufblock *f;
+ char *cp;
+
+ n = p->end-p->start+QUANTA;
+ /* search the free list for a big buffer */
+ for (f = freelist; f; f = f->next) {
+ if (f->end-f->start >= n) {
+ memcpy(f->start, p->start, p->end-p->start);
+ cp = f->start;
+ f->start = p->start;
+ p->start = cp;
+ cp = f->end;
+ f->end = p->end;
+ p->end = cp;
+ f->current = f->start;
+ break;
+ }
+ }
+ if (!f) { /* not found - grow it */
+ p->start = Realloc(p->start, n);
+ p->end = p->start+n;
+ }
+ p->current = p->start+n-QUANTA;
+}
+
+void
+bufcpy(Bufblock *buf, char *cp, int n)
+{
+
+ while (n--)
+ insert(buf, *cp++);
+}
+
+void
+insert(Bufblock *buf, int c)
+{
+
+ if (buf->current >= buf->end)
+ growbuf(buf);
+ *buf->current++ = c;
+}
+
+void
+rinsert(Bufblock *buf, Rune r)
+{
+ int n;
+
+ n = runelen(r);
+ if (buf->current+n > buf->end)
+ growbuf(buf);
+ runetochar(buf->current, &r);
+ buf->current += n;
+}
diff --git a/utils/mk/env.c b/utils/mk/env.c
new file mode 100644
index 00000000..c040db58
--- /dev/null
+++ b/utils/mk/env.c
@@ -0,0 +1,149 @@
+#include "mk.h"
+
+enum {
+ ENVQUANTA=10
+};
+
+Envy *envy;
+static int nextv;
+
+static char *myenv[] =
+{
+ "target",
+ "stem",
+ "prereq",
+ "pid",
+ "nproc",
+ "newprereq",
+ "alltarget",
+ "newmember",
+ "stem0", /* must be in order from here */
+ "stem1",
+ "stem2",
+ "stem3",
+ "stem4",
+ "stem5",
+ "stem6",
+ "stem7",
+ "stem8",
+ "stem9",
+ 0,
+};
+
+void
+initenv(void)
+{
+ char **p;
+
+ for(p = myenv; *p; p++)
+ symlook(*p, S_INTERNAL, (void *)"");
+ readenv(); /* o.s. dependent */
+}
+
+static void
+envinsert(char *name, Word *value)
+{
+ static int envsize;
+
+ if (nextv >= envsize) {
+ envsize += ENVQUANTA;
+ envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy));
+ }
+ envy[nextv].name = name;
+ envy[nextv++].values = value;
+}
+
+static void
+envupd(char *name, Word *value)
+{
+ Envy *e;
+
+ for(e = envy; e->name; e++)
+ if(strcmp(name, e->name) == 0){
+ delword(e->values);
+ e->values = value;
+ return;
+ }
+ e->name = name;
+ e->values = value;
+ envinsert(0,0);
+}
+
+static void
+ecopy(Symtab *s)
+{
+ char **p;
+
+ if(symlook(s->name, S_NOEXPORT, 0))
+ return;
+ for(p = myenv; *p; p++)
+ if(strcmp(*p, s->name) == 0)
+ return;
+ envinsert(s->name, (Word *) s->value);
+}
+
+void
+execinit(void)
+{
+ char **p;
+
+ nextv = 0;
+ for(p = myenv; *p; p++)
+ envinsert(*p, stow(""));
+
+ symtraverse(S_VAR, ecopy);
+ envinsert(0, 0);
+}
+
+Envy*
+buildenv(Job *j, int slot)
+{
+ char **p, *cp, *qp;
+ Word *w, *v, **l;
+ int i;
+ char buf[256];
+
+ envupd("target", wdup(j->t));
+ if(j->r->attr&REGEXP)
+ envupd("stem",newword(""));
+ else
+ envupd("stem", newword(j->stem));
+ envupd("prereq", wdup(j->p));
+ sprint(buf, "%d", getpid());
+ envupd("pid", newword(buf));
+ sprint(buf, "%d", slot);
+ envupd("nproc", newword(buf));
+ envupd("newprereq", wdup(j->np));
+ envupd("alltarget", wdup(j->at));
+ l = &v;
+ v = w = wdup(j->np);
+ while(w){
+ cp = strchr(w->s, '(');
+ if(cp){
+ qp = strchr(cp+1, ')');
+ if(qp){
+ *qp = 0;
+ strcpy(w->s, cp+1);
+ l = &w->next;
+ w = w->next;
+ continue;
+ }
+ }
+ *l = w->next;
+ free(w->s);
+ free(w);
+ w = *l;
+ }
+ envupd("newmember", v);
+ /* update stem0 -> stem9 */
+ for(p = myenv; *p; p++)
+ if(strcmp(*p, "stem0") == 0)
+ break;
+ for(i = 0; *p; i++, p++){
+ if((j->r->attr&REGEXP) && j->match[i])
+ envupd(*p, newword(j->match[i]));
+ else
+ envupd(*p, newword(""));
+ }
+ return envy;
+}
diff --git a/utils/mk/file.c b/utils/mk/file.c
new file mode 100644
index 00000000..1ff6623e
--- /dev/null
+++ b/utils/mk/file.c
@@ -0,0 +1,90 @@
+#include "mk.h"
+
+/* table-driven version in bootes dump of 12/31/96 */
+
+long
+mtime(char *name)
+{
+ return mkmtime(name);
+}
+
+long
+timeof(char *name, int force)
+{
+ Symtab *sym;
+ long t;
+
+ if(utfrune(name, '('))
+ return atimeof(force, name); /* archive */
+
+ if(force)
+ return mtime(name);
+
+
+ sym = symlook(name, S_TIME, 0);
+ if (sym)
+ return (long) sym->value; /* uggh */
+
+ t = mtime(name);
+ if(t == 0)
+ return 0;
+
+ symlook(name, S_TIME, (void*)t); /* install time in cache */
+ return t;
+}
+
+void
+touch(char *name)
+{
+ Bprint(&bout, "touch(%s)\n", name);
+ if(nflag)
+ return;
+
+ if(utfrune(name, '('))
+ atouch(name); /* archive */
+ else if(chgtime(name) < 0) {
+ perror(name);
+ Exit();
+ }
+}
+
+void
+delete(char *name)
+{
+ if(utfrune(name, '(') == 0) { /* file */
+ if(remove(name) < 0)
+ perror(name);
+ } else
+ fprint(2, "hoon off; mk can'tdelete archive members\n");
+}
+
+void
+timeinit(char *s)
+{
+ long t;
+ char *cp;
+ Rune r;
+ int c, n;
+
+ t = time(0);
+ while (*s) {
+ cp = s;
+ do{
+ n = chartorune(&r, s);
+ if (r == ' ' || r == ',' || r == '\n')
+ break;
+ s += n;
+ } while(*s);
+ c = *s;
+ *s = 0;
+ symlook(strdup(cp), S_TIME, (void *)t)->value = (void *)t;
+ if (c)
+ *s++ = c;
+ while(*s){
+ n = chartorune(&r, s);
+ if(r != ' ' && r != ',' && r != '\n')
+ break;
+ s += n;
+ }
+ }
+}
diff --git a/utils/mk/fns.h b/utils/mk/fns.h
new file mode 100644
index 00000000..01ee98a1
--- /dev/null
+++ b/utils/mk/fns.h
@@ -0,0 +1,84 @@
+void addrule(char*, Word*, char*, Word*, int, int, char*);
+void addrules(Word*, Word*, char*, int, int, char*);
+void addw(Word*, char*);
+void assert(char*, int);
+int assline(Biobuf *, Bufblock *);
+long atimeof(int,char*);
+void atouch(char*);
+void bufcpy(Bufblock *, char *, int);
+Envy *buildenv(Job*, int);
+void catchnotes(void);
+char *charin(char *, char *);
+int chgtime(char*);
+void clrmade(Node*);
+char *copyq(char*, Rune, Bufblock*);
+void delete(char*);
+void delword(Word*);
+int dorecipe(Node*);
+void dumpa(char*, Arc*);
+void dumpj(char*, Job*, int);
+void dumpn(char*, Node*);
+void dumpr(char*, Rule*);
+void dumpv(char*);
+void dumpw(char*, Word*);
+int escapetoken(Biobuf*, Bufblock*, int, int);
+void execinit(void);
+int execsh(char*, char*, Bufblock*, Envy*);
+void Exit(void);
+char *expandquote(char*, Rune, Bufblock*);
+void expunge(int, char*);
+void freebuf(Bufblock*);
+void front(char*);
+Node *graph(char*);
+void growbuf(Bufblock *);
+void initenv(void);
+void insert(Bufblock *, int);
+void ipop(void);
+void ipush(void);
+void killchildren(char*);
+void *Malloc(int);
+char *maketmp(void);
+int match(char*, char*, char*);
+char *membername(char*, int, char*);
+void mk(char*);
+ulong mkmtime(char*);
+long mtime(char*);
+Arc *newarc(Node*, Rule*, char*, Resub*);
+Bufblock *newbuf(void);
+Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*);
+Word *newword(char*);
+int nextrune(Biobuf*, int);
+int nextslot(void);
+void nproc(void);
+void nrep(void);
+int outofdate(Node*, Arc*, int);
+void parse(char*, int, int);
+int pipecmd(char*, Envy*, int*);
+void prusage(void);
+void rcopy(char**, Resub*, int);
+void readenv(void);
+void *Realloc(void*, int);
+void rinsert(Bufblock *, Rune);
+char *rulecnt(void);
+void run(Job*);
+void setvar(char*, void*);
+char *shname(char*);
+void shprint(char*, Envy*, Bufblock*);
+Word *stow(char*);
+void subst(char*, char*, char*);
+void symdel(char*, int);
+void syminit(void);
+Symtab *symlook(char*, int, void*);
+void symstat(void);
+void symtraverse(int, void(*)(Symtab*));
+void timeinit(char*);
+long timeof(char*, int);
+void touch(char*);
+void update(int, Node*);
+void usage(void);
+Word *varsub(char**);
+int waitfor(char*);
+int waitup(int, int*);
+Word *wdup(Word*);
+int work(Node*, Node*, Arc*);
+char *wtos(Word*, int);
diff --git a/utils/mk/graph.c b/utils/mk/graph.c
new file mode 100644
index 00000000..018e4aea
--- /dev/null
+++ b/utils/mk/graph.c
@@ -0,0 +1,279 @@
+#include "mk.h"
+
+static Node *applyrules(char *, char *);
+static void togo(Node *);
+static int vacuous(Node *);
+static Node *newnode(char *);
+static void trace(char *, Arc *);
+static void cyclechk(Node *);
+static void ambiguous(Node *);
+static void attribute(Node *);
+
+Node *
+graph(char *target)
+{
+ Node *node;
+ char *cnt;
+
+ cnt = rulecnt();
+ node = applyrules(target, cnt);
+ free(cnt);
+ cyclechk(node);
+ node->flags |= PROBABLE; /* make sure it doesn't get deleted */
+ vacuous(node);
+ ambiguous(node);
+ attribute(node);
+ return(node);
+}
+
+static Node *
+applyrules(char *target, char *cnt)
+{
+ Symtab *sym;
+ Node *node;
+ Rule *r;
+ Arc head, *a = &head;
+ Word *w;
+ char stem[NAMEBLOCK], buf[NAMEBLOCK];
+ Resub rmatch[NREGEXP];
+
+/* print("applyrules(%lux='%s')\n", target, target);/**/
+ sym = symlook(target, S_NODE, 0);
+ if(sym)
+ return (Node *)(sym->value);
+ target = strdup(target);
+ node = newnode(target);
+ head.n = 0;
+ head.next = 0;
+ sym = symlook(target, S_TARGET, 0);
+ memset((char*)rmatch, 0, sizeof(rmatch));
+ for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){
+ if(r->attr&META) continue;
+ if(strcmp(target, r->target)) continue;
+ if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
+ if(cnt[r->rule] >= nreps) continue;
+ cnt[r->rule]++;
+ node->flags |= PROBABLE;
+
+/* if(r->attr&VIR)
+ * node->flags |= VIRTUAL;
+ * if(r->attr&NOREC)
+ * node->flags |= NORECIPE;
+ * if(r->attr&DEL)
+ * node->flags |= DELETE;
+ */
+ if(!r->tail || !r->tail->s || !*r->tail->s) {
+ a->next = newarc((Node *)0, r, "", rmatch);
+ a = a->next;
+ } else
+ for(w = r->tail; w; w = w->next){
+ a->next = newarc(applyrules(w->s, cnt), r, "", rmatch);
+ a = a->next;
+ }
+ cnt[r->rule]--;
+ head.n = node;
+ }
+ for(r = metarules; r; r = r->next){
+ if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
+ if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
+ continue;
+ if(r->attr&REGEXP){
+ stem[0] = 0;
+ patrule = r;
+ memset((char*)rmatch, 0, sizeof(rmatch));
+ if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
+ continue;
+ } else {
+ if(!match(node->name, r->target, stem)) continue;
+ }
+ if(cnt[r->rule] >= nreps) continue;
+ cnt[r->rule]++;
+
+/* if(r->attr&VIR)
+ * node->flags |= VIRTUAL;
+ * if(r->attr&NOREC)
+ * node->flags |= NORECIPE;
+ * if(r->attr&DEL)
+ * node->flags |= DELETE;
+ */
+
+ if(!r->tail || !r->tail->s || !*r->tail->s) {
+ a->next = newarc((Node *)0, r, stem, rmatch);
+ a = a->next;
+ } else
+ for(w = r->tail; w; w = w->next){
+ if(r->attr&REGEXP)
+ regsub(w->s, buf, rmatch, NREGEXP);
+ else
+ subst(stem, w->s, buf);
+ a->next = newarc(applyrules(buf, cnt), r, stem, rmatch);
+ a = a->next;
+ }
+ cnt[r->rule]--;
+ }
+ a->next = node->prereqs;
+ node->prereqs = head.next;
+ return(node);
+}
+
+static void
+togo(Node *node)
+{
+ Arc *la, *a;
+
+ /* delete them now */
+ la = 0;
+ for(a = node->prereqs; a; la = a, a = a->next)
+ if(a->flag&TOGO){
+ if(a == node->prereqs)
+ node->prereqs = a->next;
+ else
+ la->next = a->next, a = la;
+ }
+}
+
+static
+vacuous(Node *node)
+{
+ Arc *la, *a;
+ int vac = !(node->flags&PROBABLE);
+
+ if(node->flags&READY)
+ return(node->flags&VACUOUS);
+ node->flags |= READY;
+ for(a = node->prereqs; a; a = a->next)
+ if(a->n && vacuous(a->n) && (a->r->attr&META))
+ a->flag |= TOGO;
+ else
+ vac = 0;
+ /* if a rule generated arcs that DON'T go; no others from that rule go */
+ for(a = node->prereqs; a; a = a->next)
+ if((a->flag&TOGO) == 0)
+ for(la = node->prereqs; la; la = la->next)
+ if((la->flag&TOGO) && (la->r == a->r)){
+ la->flag &= ~TOGO;
+ }
+ togo(node);
+ if(vac)
+ node->flags |= VACUOUS;
+ return(vac);
+}
+
+static Node *
+newnode(char *name)
+{
+ register Node *node;
+
+ node = (Node *)Malloc(sizeof(Node));
+ symlook(name, S_NODE, (void *)node);
+ node->name = name;
+ node->time = timeof(name, 0);
+ node->prereqs = 0;
+ node->flags = node->time? PROBABLE : 0;
+ node->next = 0;
+ return(node);
+}
+
+void
+dumpn(char *s, Node *n)
+{
+ char buf[1024];
+ Arc *a;
+
+ sprint(buf, "%s ", (*s == ' ')? s:"");
+ Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n",
+ s, n->name, n, n->time, n->flags, n->next);
+ for(a = n->prereqs; a; a = a->next)
+ dumpa(buf, a);
+}
+
+static void
+trace(char *s, Arc *a)
+{
+ fprint(2, "\t%s", s);
+ while(a){
+ fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line,
+ a->n? a->n->name:"");
+ if(a->n){
+ for(a = a->n->prereqs; a; a = a->next)
+ if(*a->r->recipe) break;
+ } else
+ a = 0;
+ }
+ fprint(2, "\n");
+}
+
+static void
+cyclechk(Node *n)
+{
+ Arc *a;
+
+ if((n->flags&CYCLE) && n->prereqs){
+ fprint(2, "mk: cycle in graph detected at target %s\n", n->name);
+ Exit();
+ }
+ n->flags |= CYCLE;
+ for(a = n->prereqs; a; a = a->next)
+ if(a->n)
+ cyclechk(a->n);
+ n->flags &= ~CYCLE;
+}
+
+static void
+ambiguous(Node *n)
+{
+ Arc *a;
+ Rule *r = 0;
+ Arc *la;
+ int bad = 0;
+
+ la = 0;
+ for(a = n->prereqs; a; a = a->next){
+ if(a->n)
+ ambiguous(a->n);
+ if(*a->r->recipe == 0) continue;
+ if(r == 0)
+ r = a->r, la = a;
+ else{
+ if(r->recipe != a->r->recipe){
+ if((r->attr&META) && !(a->r->attr&META)){
+ la->flag |= TOGO;
+ r = a->r, la = a;
+ } else if(!(r->attr&META) && (a->r->attr&META)){
+ a->flag |= TOGO;
+ continue;
+ }
+ }
+ if(r->recipe != a->r->recipe){
+ if(bad == 0){
+ fprint(2, "mk: ambiguous recipes for %s:\n", n->name);
+ bad = 1;
+ trace(n->name, la);
+ }
+ trace(n->name, a);
+ }
+ }
+ }
+ if(bad)
+ Exit();
+ togo(n);
+}
+
+static void
+attribute(Node *n)
+{
+ register Arc *a;
+
+ for(a = n->prereqs; a; a = a->next){
+ if(a->r->attr&VIR)
+ n->flags |= VIRTUAL;
+ if(a->r->attr&NOREC)
+ n->flags |= NORECIPE;
+ if(a->r->attr&DEL)
+ n->flags |= DELETE;
+ if(a->n)
+ attribute(a->n);
+ }
+ if(n->flags&VIRTUAL)
+ n->time = 0;
+}
diff --git a/utils/mk/job.c b/utils/mk/job.c
new file mode 100644
index 00000000..cee93760
--- /dev/null
+++ b/utils/mk/job.c
@@ -0,0 +1,33 @@
+#include "mk.h"
+
+Job *
+newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar)
+{
+ register Job *j;
+
+ j = (Job *)Malloc(sizeof(Job));
+ j->r = r;
+ j->n = nlist;
+ j->stem = stem;
+ j->match = match;
+ j->p = pre;
+ j->np = npre;
+ j->t = tar;
+ j->at = atar;
+ j->nproc = -1;
+ j->next = 0;
+ return(j);
+}
+
+void
+dumpj(char *s, Job *j, int all)
+{
+ Bprint(&bout, "%s\n", s);
+ while(j){
+ Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n",
+ j, j->r, j->n, j->stem, j->nproc);
+ Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n",
+ wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' '));
+ j = all? j->next : 0;
+ }
+}
diff --git a/utils/mk/lex.c b/utils/mk/lex.c
new file mode 100644
index 00000000..3ee244f1
--- /dev/null
+++ b/utils/mk/lex.c
@@ -0,0 +1,147 @@
+#include "mk.h"
+
+static int bquote(Biobuf*, Bufblock*);
+
+/*
+ * Assemble a line skipping blank lines, comments, and eliding
+ * escaped newlines
+ */
+int
+assline(Biobuf *bp, Bufblock *buf)
+{
+ int c;
+ int lastc;
+
+ buf->current=buf->start;
+ while ((c = nextrune(bp, 1)) >= 0){
+ switch(c)
+ {
+ case '\r': /* consumes CRs for Win95 */
+ continue;
+ case '\n':
+ if (buf->current != buf->start) {
+ insert(buf, 0);
+ return 1;
+ }
+ break; /* skip empty lines */
+ case '\\':
+ case '\'':
+ case '"':
+ rinsert(buf, c);
+ if (escapetoken(bp, buf, 1, c) == 0)
+ Exit();
+ break;
+ case '`':
+ if (bquote(bp, buf) == 0)
+ Exit();
+ break;
+ case '#':
+ lastc = '#';
+ while ((c = Bgetc(bp)) != '\n') {
+ if (c < 0)
+ goto eof;
+ if(c != '\r')
+ lastc = c;
+ }
+ mkinline++;
+ if (lastc == '\\')
+ break; /* propagate escaped newlines??*/
+ if (buf->current != buf->start) {
+ insert(buf, 0);
+ return 1;
+ }
+ break;
+ default:
+ rinsert(buf, c);
+ break;
+ }
+ }
+eof:
+ insert(buf, 0);
+ return *buf->start != 0;
+}
+
+/*
+ * assemble a back-quoted shell command into a buffer
+ */
+static int
+bquote(Biobuf *bp, Bufblock *buf)
+{
+ int c, line, term;
+ int start;
+
+ line = mkinline;
+ while((c = Bgetrune(bp)) == ' ' || c == '\t')
+ ;
+ if(c == '{'){
+ term = '}'; /* rc style */
+ while((c = Bgetrune(bp)) == ' ' || c == '\t')
+ ;
+ } else
+ term = '`'; /* sh style */
+
+ start = buf->current-buf->start;
+ for(;c > 0; c = nextrune(bp, 0)){
+ if(c == term){
+ insert(buf, '\n');
+ insert(buf,0);
+ buf->current = buf->start+start;
+ execinit();
+ execsh(0, buf->current, buf, envy);
+ return 1;
+ }
+ if(c == '\n')
+ break;
+ if(c == '\'' || c == '"' || c == '\\'){
+ insert(buf, c);
+ if(!escapetoken(bp, buf, 1, c))
+ return 0;
+ continue;
+ }
+ rinsert(buf, c);
+ }
+ SYNERR(line);
+ fprint(2, "missing closing %c after `\n", term);
+ return 0;
+}
+
+/*
+ * get next character stripping escaped newlines
+ * the flag specifies whether escaped newlines are to be elided or
+ * replaced with a blank.
+ */
+int
+nextrune(Biobuf *bp, int elide)
+{
+ int c, c2;
+ static int savec;
+
+ if(savec){
+ c = savec;
+ savec = 0;
+ return c;
+ }
+
+ for (;;) {
+ c = Bgetrune(bp);
+ if (c == '\\') {
+ c2 = Bgetrune(bp);
+ if(c2 == '\r'){
+ savec = c2;
+ c2 = Bgetrune(bp);
+ }
+ if (c2 == '\n') {
+ savec = 0;
+ mkinline++;
+ if (elide)
+ continue;
+ return ' ';
+ }
+ Bungetrune(bp);
+ }
+ if (c == '\n')
+ mkinline++;
+ return c;
+ }
+ return 0;
+}
diff --git a/utils/mk/main.c b/utils/mk/main.c
new file mode 100644
index 00000000..43e34559
--- /dev/null
+++ b/utils/mk/main.c
@@ -0,0 +1,291 @@
+#include "mk.h"
+
+#define MKFILE "mkfile"
+
+static char *version = "@(#)mk general release 4 (plan 9)";
+int debug;
+Rule *rules, *metarules;
+int nflag = 0;
+int tflag = 0;
+int iflag = 0;
+int kflag = 0;
+int aflag = 0;
+int uflag = 0;
+char *explain = 0;
+Word *target1;
+int nreps = 1;
+Job *jobs;
+Biobuf bout;
+Rule *patrule;
+void badusage(void);
+#ifdef PROF
+short buf[10000];
+#endif
+
+void
+main(int argc, char **argv)
+{
+ Word *w;
+ char *s, *temp;
+ char *files[256], **f = files, **ff;
+ int sflag = 0;
+ int i;
+ int tfd = -1;
+ Biobuf tb;
+ Bufblock *buf;
+ Bufblock *whatif;
+
+ /*
+ * start with a copy of the current environment variables
+ * instead of sharing them
+ */
+
+ Binit(&bout, 1, OWRITE);
+ buf = newbuf();
+ whatif = 0;
+ USED(argc);
+ for(argv++; *argv && (**argv == '-'); argv++)
+ {
+ bufcpy(buf, argv[0], strlen(argv[0]));
+ insert(buf, ' ');
+ switch(argv[0][1])
+ {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ if(*(s = &argv[0][2]))
+ while(*s) switch(*s++)
+ {
+ case 'p': debug |= D_PARSE; break;
+ case 'g': debug |= D_GRAPH; break;
+ case 'e': debug |= D_EXEC; break;
+ }
+ else
+ debug = 0xFFFF;
+ break;
+ case 'e':
+ explain = &argv[0][2];
+ break;
+ case 'f':
+ if(*++argv == 0)
+ badusage();
+ *f++ = *argv;
+ bufcpy(buf, argv[0], strlen(argv[0]));
+ insert(buf, ' ');
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'k':
+ kflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ uflag = 1;
+ break;
+ case 'w':
+ if(whatif == 0)
+ whatif = newbuf();
+ else
+ insert(whatif, ' ');
+ if(argv[0][2])
+ bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]));
+ else {
+ if(*++argv == 0)
+ badusage();
+ bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]));
+ }
+ break;
+ default:
+ badusage();
+ }
+ }
+#ifdef PROF
+ {
+ extern etext();
+ monitor(main, etext, buf, sizeof buf, 300);
+ }
+#endif
+
+ if(aflag)
+ iflag = 1;
+ usage();
+ syminit();
+ initenv();
+ usage();
+
+ /*
+ assignment args become null strings
+ */
+ temp = 0;
+ for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){
+ bufcpy(buf, argv[i], strlen(argv[i]));
+ insert(buf, ' ');
+ if(tfd < 0){
+ temp = maketmp();
+ if(temp == 0) {
+ perror("temp file");
+ Exit();
+ }
+ close(create(temp, OWRITE, 0600));
+ if((tfd = open(temp, 2)) < 0){
+ perror(temp);
+ Exit();
+ }
+ Binit(&tb, tfd, OWRITE);
+ }
+ Bprint(&tb, "%s\n", argv[i]);
+ *argv[i] = 0;
+ }
+ if(tfd >= 0){
+ Bflush(&tb);
+ LSEEK(tfd, 0L, 0);
+ parse("command line args", tfd, 1);
+ remove(temp);
+ }
+
+ if (buf->current != buf->start) {
+ buf->current--;
+ insert(buf, 0);
+ }
+ symlook("MKFLAGS", S_VAR, (void *) stow(buf->start));
+ buf->current = buf->start;
+ for(i = 0; argv[i]; i++){
+ if(*argv[i] == 0) continue;
+ if(i)
+ insert(buf, ' ');
+ bufcpy(buf, argv[i], strlen(argv[i]));
+ }
+ insert(buf, 0);
+ symlook("MKARGS", S_VAR, (void *) stow(buf->start));
+ freebuf(buf);
+
+ if(f == files){
+ if(access(MKFILE, 4) == 0)
+ parse(MKFILE, open(MKFILE, 0), 0);
+ } else
+ for(ff = files; ff < f; ff++)
+ parse(*ff, open(*ff, 0), 0);
+ if(DEBUG(D_PARSE)){
+ dumpw("default targets", target1);
+ dumpr("rules", rules);
+ dumpr("metarules", metarules);
+ dumpv("variables");
+ }
+ if(whatif){
+ insert(whatif, 0);
+ timeinit(whatif->start);
+ freebuf(whatif);
+ }
+ execinit();
+ /* skip assignment args */
+ while(*argv && (**argv == 0))
+ argv++;
+
+ catchnotes();
+ if(*argv == 0){
+ if(target1)
+ for(w = target1; w; w = w->next)
+ mk(w->s);
+ else {
+ fprint(2, "mk: nothing to mk\n");
+ Exit();
+ }
+ } else {
+ if(sflag){
+ for(; *argv; argv++)
+ if(**argv)
+ mk(*argv);
+ } else {
+ Word *head, *tail, *t;
+
+ /* fake a new rule with all the args as prereqs */
+ tail = 0;
+ t = 0;
+ for(; *argv; argv++)
+ if(**argv){
+ if(tail == 0)
+ tail = t = newword(*argv);
+ else {
+ t->next = newword(*argv);
+ t = t->next;
+ }
+ }
+ if(tail->next == 0)
+ mk(tail->s);
+ else {
+ head = newword("command line arguments");
+ addrules(head, tail, strdup(""), VIR, mkinline, 0);
+ mk(head->s);
+ }
+ }
+ }
+ if(uflag)
+ prusage();
+ exits(0);
+}
+
+void
+badusage(void)
+{
+
+ fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n");
+ Exit();
+}
+
+void *
+Malloc(int n)
+{
+ register void *s;
+
+ s = malloc(n);
+ if(!s) {
+ fprint(2, "mk: cannot alloc %d bytes\n", n);
+ Exit();
+ }
+ return(s);
+}
+
+void *
+Realloc(void *s, int n)
+{
+ if(s)
+ s = realloc(s, n);
+ else
+ s = malloc(n);
+ if(!s) {
+ fprint(2, "mk: cannot alloc %d bytes\n", n);
+ Exit();
+ }
+ return(s);
+}
+
+void
+assert(char *s, int n)
+{
+ if(!n){
+ fprint(2, "mk: Assertion ``%s'' failed.\n", s);
+ Exit();
+ }
+}
+
+void
+regerror(char *s)
+{
+ if(patrule)
+ fprint(2, "mk: %s:%d: regular expression error; %s\n",
+ patrule->file, patrule->line, s);
+ else
+ fprint(2, "mk: %s:%d: regular expression error; %s\n",
+ infile, mkinline, s);
+ Exit();
+}
diff --git a/utils/mk/match.c b/utils/mk/match.c
new file mode 100644
index 00000000..2a96394a
--- /dev/null
+++ b/utils/mk/match.c
@@ -0,0 +1,49 @@
+#include "mk.h"
+
+int
+match(char *name, char *template, char *stem)
+{
+ Rune r;
+ int n;
+
+ while(*name && *template){
+ n = chartorune(&r, template);
+ if (PERCENT(r))
+ break;
+ while (n--)
+ if(*name++ != *template++)
+ return 0;
+ }
+ if(!PERCENT(*template))
+ return 0;
+ n = strlen(name)-strlen(template+1);
+ if (n < 0)
+ return 0;
+ if (strcmp(template+1, name+n))
+ return 0;
+ strncpy(stem, name, n);
+ stem[n] = 0;
+ if(*template == '&')
+ return !charin(stem, "./");
+ return 1;
+}
+
+void
+subst(char *stem, char *template, char *dest)
+{
+ Rune r;
+ char *s;
+ int n;
+
+ while(*template){
+ n = chartorune(&r, template);
+ if (PERCENT(r)) {
+ template += n;
+ for (s = stem; *s; s++)
+ *dest++ = *s;
+ } else
+ while (n--)
+ *dest++ = *template++;
+ }
+ *dest = 0;
+}
diff --git a/utils/mk/mk.c b/utils/mk/mk.c
new file mode 100644
index 00000000..98d76623
--- /dev/null
+++ b/utils/mk/mk.c
@@ -0,0 +1,226 @@
+#include "mk.h"
+
+int runerrs;
+
+void
+mk(char *target)
+{
+ Node *node;
+ int did = 0;
+
+ nproc(); /* it can be updated dynamically */
+ nrep(); /* it can be updated dynamically */
+ runerrs = 0;
+ node = graph(target);
+ if(DEBUG(D_GRAPH)){
+ dumpn("new target\n", node);
+ Bflush(&bout);
+ }
+ clrmade(node);
+ while(node->flags&NOTMADE){
+ if(work(node, (Node *)0, (Arc *)0))
+ did = 1; /* found something to do */
+ else {
+ if(waitup(1, (int *)0) > 0){
+ if(node->flags&(NOTMADE|BEINGMADE)){
+ assert("must be run errors", runerrs);
+ break; /* nothing more waiting */
+ }
+ }
+ }
+ }
+ if(node->flags&BEINGMADE)
+ waitup(-1, (int *)0);
+ while(jobs)
+ waitup(-2, (int *)0);
+ assert("target didn't get done", runerrs || (node->flags&MADE));
+ if(did == 0)
+ Bprint(&bout, "mk: '%s' is up to date\n", node->name);
+}
+
+void
+clrmade(Node *n)
+{
+ Arc *a;
+
+ n->flags &= ~(CANPRETEND|PRETENDING);
+ if(strchr(n->name, '(') ==0 || n->time)
+ n->flags |= CANPRETEND;
+ MADESET(n, NOTMADE);
+ for(a = n->prereqs; a; a = a->next)
+ if(a->n)
+ clrmade(a->n);
+}
+
+static void
+unpretend(Node *n)
+{
+ MADESET(n, NOTMADE);
+ n->flags &= ~(CANPRETEND|PRETENDING);
+ n->time = 0;
+}
+
+int
+work(Node *node, Node *p, Arc *parc)
+{
+ Arc *a, *ra;
+ int weoutofdate;
+ int ready;
+ int did = 0;
+
+ /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, node->time);/**/
+ if(node->flags&BEINGMADE)
+ return(did);
+ if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){
+ if(explain)
+ fprint(1, "unpretending %s(%ld) because %s is out of date(%ld)\n",
+ node->name, node->time, p->name, p->time);
+ unpretend(node);
+ }
+ /*
+ have a look if we are pretending in case
+ someone has been unpretended out from underneath us
+ */
+ if(node->flags&MADE){
+ if(node->flags&PRETENDING){
+ node->time = 0;
+ }else
+ return(did);
+ }
+ /* consider no prerequsite case */
+ if(node->prereqs == 0){
+ if(node->time == 0){
+ fprint(2, "mk: don't know how to make '%s'\n", node->name);
+ if(kflag){
+ node->flags |= BEINGMADE;
+ runerrs++;
+ } else
+ Exit();
+ } else
+ MADESET(node, MADE);
+ return(did);
+ }
+ /*
+ now see if we are out of date or what
+ */
+ ready = 1;
+ weoutofdate = aflag;
+ ra = 0;
+ for(a = node->prereqs; a; a = a->next)
+ if(a->n){
+ did = work(a->n, node, a) || did;
+ if(a->n->flags&(NOTMADE|BEINGMADE))
+ ready = 0;
+ if(outofdate(node, a, 0)){
+ weoutofdate = 1;
+ if((ra == 0) || (ra->n == 0)
+ || (ra->n->time < a->n->time))
+ ra = a;
+ }
+ } else {
+ if(node->time == 0){
+ if(ra == 0)
+ ra = a;
+ weoutofdate = 1;
+ }
+ }
+ if(ready == 0) /* can't do anything now */
+ return(did);
+ if(weoutofdate == 0){
+ MADESET(node, MADE);
+ return(did);
+ }
+ /*
+ can we pretend to be made?
+ */
+ if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND))
+ && p && ra->n && !outofdate(p, ra, 0)){
+ node->flags &= ~CANPRETEND;
+ MADESET(node, MADE);
+ if(explain && ((node->flags&PRETENDING) == 0))
+ fprint(1, "pretending %s has time %ld\n", node->name, node->time);
+ node->flags |= PRETENDING;
+ return(did);
+ }
+ /*
+ node is out of date and we REALLY do have to do something.
+ quickly rescan for pretenders
+ */
+ for(a = node->prereqs; a; a = a->next)
+ if(a->n && (a->n->flags&PRETENDING)){
+ if(explain)
+ Bprint(&bout, "unpretending %s because of %s because of %s\n",
+ a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites");
+
+ unpretend(a->n);
+ did = work(a->n, node, a) || did;
+ ready = 0;
+ }
+ if(ready == 0) /* try later unless nothing has happened for -k's sake */
+ return(did || work(node, p, parc));
+ did = dorecipe(node) || did;
+ return(did);
+}
+
+void
+update(int fake, Node *node)
+{
+ Arc *a;
+
+ MADESET(node, fake? BEINGMADE : MADE);
+ if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
+ node->time = timeof(node->name, 1);
+ node->flags &= ~(CANPRETEND|PRETENDING);
+ for(a = node->prereqs; a; a = a->next)
+ if(a->prog)
+ outofdate(node, a, 1);
+ } else {
+ node->time = 1;
+ for(a = node->prereqs; a; a = a->next)
+ if(a->n && outofdate(node, a, 1))
+ node->time = a->n->time;
+ }
+/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, node->flags);/**/
+}
+
+static
+pcmp(char *prog, char *p, char *q)
+{
+ char buf[3*NAMEBLOCK];
+ int pid;
+
+ Bflush(&bout);
+ sprint(buf, "%s '%s' '%s'\n", prog, p, q);
+ pid = pipecmd(buf, 0, 0);
+ while(waitup(-3, &pid) >= 0)
+ ;
+ return(pid? 2:1);
+}
+
+int
+outofdate(Node *node, Arc *arc, int eval)
+{
+ char buf[3*NAMEBLOCK], *str;
+ Symtab *sym;
+ int ret;
+
+ str = 0;
+ if(arc->prog){
+ sprint(buf, "%s%c%s", node->name, 0377, arc->n->name);
+ sym = symlook(buf, S_OUTOFDATE, 0);
+ if(sym == 0 || eval){
+ if(sym == 0)
+ str = strdup(buf);
+ ret = pcmp(arc->prog, node->name, arc->n->name);
+ if(sym)
+ sym->value = (void *)ret;
+ else
+ symlook(str, S_OUTOFDATE, (void *)ret);
+ } else
+ ret = (int)sym->value;
+ return(ret-1);
+ } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing archive member */
+ return 1;
+ else
+ return node->time <= arc->n->time;
+}
diff --git a/utils/mk/mk.h b/utils/mk/mk.h
new file mode 100644
index 00000000..40618648
--- /dev/null
+++ b/utils/mk/mk.h
@@ -0,0 +1,171 @@
+#include <lib9.h>
+#include <bio.h>
+#include <regexp.h>
+
+#undef assert
+#define assert mkassert
+extern Biobuf bout;
+
+typedef struct Bufblock
+{
+ struct Bufblock *next;
+ char *start;
+ char *end;
+ char *current;
+} Bufblock;
+
+typedef struct Word
+{
+ char *s;
+ struct Word *next;
+} Word;
+
+typedef struct Envy
+{
+ char *name;
+ Word *values;
+} Envy;
+
+extern Envy *envy;
+
+typedef struct Rule
+{
+ char *target; /* one target */
+ Word *tail; /* constituents of targets */
+ char *recipe; /* do it ! */
+ short attr; /* attributes */
+ short line; /* source line */
+ char *file; /* source file */
+ Word *alltargets; /* all the targets */
+ int rule; /* rule number */
+ Reprog *pat; /* reg exp goo */
+ char *prog; /* to use in out of date */
+ struct Rule *chain; /* hashed per target */
+ struct Rule *next;
+} Rule;
+
+extern Rule *rules, *metarules, *patrule;
+
+/* Rule.attr */
+#define META 0x0001
+#define UNUSED 0x0002
+#define UPD 0x0004
+#define QUIET 0x0008
+#define VIR 0x0010
+#define REGEXP 0x0020
+#define NOREC 0x0040
+#define DEL 0x0080
+#define NOVIRT 0x0100
+
+#define NREGEXP 10
+
+typedef struct Arc
+{
+ short flag;
+ struct Node *n;
+ Rule *r;
+ char *stem;
+ char *prog;
+ char *match[NREGEXP];
+ struct Arc *next;
+} Arc;
+
+ /* Arc.flag */
+#define TOGO 1
+
+typedef struct Node
+{
+ char *name;
+ long time;
+ unsigned short flags;
+ Arc *prereqs;
+ struct Node *next; /* list for a rule */
+} Node;
+
+ /* Node.flags */
+#define VIRTUAL 0x0001
+#define CYCLE 0x0002
+#define READY 0x0004
+#define CANPRETEND 0x0008
+#define PRETENDING 0x0010
+#define NOTMADE 0x0020
+#define BEINGMADE 0x0040
+#define MADE 0x0080
+#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEINGMADE|MADE))|(m)
+#define PROBABLE 0x0100
+#define VACUOUS 0x0200
+#define NORECIPE 0x0400
+#define DELETE 0x0800
+#define NOMINUSE 0x1000
+
+typedef struct Job
+{
+ Rule *r; /* master rule for job */
+ Node *n; /* list of node targets */
+ char *stem;
+ char **match;
+ Word *p; /* prerequistes */
+ Word *np; /* new prerequistes */
+ Word *t; /* targets */
+ Word *at; /* all targets */
+ int nproc; /* slot number */
+ struct Job *next;
+} Job;
+extern Job *jobs;
+
+typedef struct Symtab
+{
+ short space;
+ char *name;
+ void *value;
+ struct Symtab *next;
+} Symtab;
+
+enum {
+ S_VAR, /* variable -> value */
+ S_TARGET, /* target -> rule */
+ S_TIME, /* file -> time */
+ S_PID, /* pid -> products */
+ S_NODE, /* target name -> node */
+ S_AGG, /* aggregate -> time */
+ S_BITCH, /* bitched about aggregate not there */
+ S_NOEXPORT, /* var -> noexport */
+ S_OVERRIDE, /* can't override */
+ S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */
+ S_MAKEFILE, /* target -> node */
+ S_MAKEVAR, /* dumpable mk variable */
+ S_EXPORTED, /* var -> current exported value */
+ S_WESET, /* variable; we set in the mkfile */
+ S_INTERNAL /* an internal mk variable (e.g., stem, target) */
+};
+
+extern int debug;
+extern int nflag, tflag, iflag, kflag, aflag, mflag;
+extern int mkinline;
+extern char *infile;
+extern int nreps;
+extern char *explain;
+extern char *termchars;
+extern int IWS;
+extern char *shell;
+extern char *shellname;
+extern char *shflags;
+
+#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline))
+#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line))
+#define NAMEBLOCK 1000
+#define BIGBLOCK 20000
+
+#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n'))
+#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", (r)))
+
+#define DEBUG(x) (debug&(x))
+#define D_PARSE 0x01
+#define D_GRAPH 0x02
+#define D_EXEC 0x04
+
+#define LSEEK(f,o,p) seek(f,o,p)
+
+#define PERCENT(ch) (((ch) == '%') || ((ch) == '&'))
+
+#include "fns.h"
diff --git a/utils/mk/mkfile b/utils/mk/mkfile
new file mode 100644
index 00000000..74ddb579
--- /dev/null
+++ b/utils/mk/mkfile
@@ -0,0 +1,40 @@
+<../../mkconfig
+
+TARG=mk
+
+OFILES= arc.$O\
+ archive.$O\
+ bufblock.$O\
+ env.$O\
+ file.$O\
+ graph.$O\
+ job.$O\
+ lex.$O\
+ main.$O\
+ match.$O\
+ mk.$O\
+ parse.$O\
+ $TARGMODEL.$O\
+ recipe.$O\
+ rule.$O\
+ run.$O\
+ $TARGSHTYPE.$O\
+ shprint.$O\
+ symtab.$O\
+ var.$O\
+ varsub.$O\
+ word.$O\
+
+HFILES= fns.h\
+ ../include/ar.h\
+ mk.h\
+
+LIBS= regexp bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS=$CFLAGS -I../include
+
+<mkfile-$HOSTMODEL
diff --git a/utils/mk/mkfile-Nt b/utils/mk/mkfile-Nt
new file mode 100644
index 00000000..95556e34
--- /dev/null
+++ b/utils/mk/mkfile-Nt
@@ -0,0 +1,12 @@
+#
+# install rule for NT & windows 95
+#
+# since we can't reliably copy the new executable
+# onto the already executing copy, we make the user
+# do it manually
+
+$BIN/%:Q: $O.out
+ echo 'mk must be installed manually on Windows systems'
+ echo use: cp $O.out $target
+ cp $O.out $target
+
diff --git a/utils/mk/mkfile-Plan9 b/utils/mk/mkfile-Plan9
new file mode 100644
index 00000000..9d85eca5
--- /dev/null
+++ b/utils/mk/mkfile-Plan9
@@ -0,0 +1,3 @@
+#
+# install rule for Inferno/Plan9 - use the default
+#
diff --git a/utils/mk/mkfile-Posix b/utils/mk/mkfile-Posix
new file mode 100644
index 00000000..5948b453
--- /dev/null
+++ b/utils/mk/mkfile-Posix
@@ -0,0 +1,7 @@
+#
+# install rule for Posix systems
+#
+
+$BIN/%: $O.out
+ test -x $target && mv $target $BIN/mk.save #because we are executing it
+ cp $O.out $target
diff --git a/utils/mk/parse.c b/utils/mk/parse.c
new file mode 100644
index 00000000..52642ce6
--- /dev/null
+++ b/utils/mk/parse.c
@@ -0,0 +1,309 @@
+#include "mk.h"
+
+char *infile;
+int mkinline;
+static int rhead(char *, Word **, Word **, int *, char **);
+static char *rbody(Biobuf*);
+extern Word *target1;
+
+void
+parse(char *f, int fd, int varoverride)
+{
+ int hline;
+ char *body;
+ Word *head, *tail;
+ int attr, set, pid;
+ char *prog, *p;
+ int newfd;
+ Biobuf in;
+ Bufblock *buf;
+
+ if(fd < 0){
+ perror(f);
+ Exit();
+ }
+ ipush();
+ infile = strdup(f);
+ mkinline = 1;
+ Binit(&in, fd, OREAD);
+ buf = newbuf();
+ while(assline(&in, buf)){
+ hline = mkinline;
+ switch(rhead(buf->start, &head, &tail, &attr, &prog))
+ {
+ case '<':
+ p = wtos(tail, ' ');
+ if(*p == 0){
+ SYNERR(-1);
+ fprint(2, "missing include file name\n");
+ Exit();
+ }
+ newfd = open(p, OREAD);
+ if(newfd < 0){
+ fprint(2, "warning: skipping missing include file: ");
+ perror(p);
+ } else
+ parse(p, newfd, 0);
+ break;
+ case '|':
+ p = wtos(tail, ' ');
+ if(*p == 0){
+ SYNERR(-1);
+ fprint(2, "missing include program name\n");
+ Exit();
+ }
+ execinit();
+ pid=pipecmd(p, envy, &newfd);
+ if(newfd < 0){
+ fprint(2, "warning: skipping missing program file: ");
+ perror(p);
+ } else
+ parse(p, newfd, 0);
+ while(waitup(-3, &pid) >= 0)
+ ;
+ if(pid != 0){
+ fprint(2, "bad include program status\n");
+ Exit();
+ }
+ break;
+ case ':':
+ body = rbody(&in);
+ addrules(head, tail, body, attr, hline, prog);
+ break;
+ case '=':
+ if(head->next){
+ SYNERR(-1);
+ fprint(2, "multiple vars on left side of assignment\n");
+ Exit();
+ }
+ if(symlook(head->s, S_OVERRIDE, 0)){
+ set = varoverride;
+ } else {
+ set = 1;
+ if(varoverride)
+ symlook(head->s, S_OVERRIDE, (void *)"");
+ }
+ if(set){
+/*
+char *cp;
+dumpw("tail", tail);
+cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
+*/
+ setvar(head->s, (void *) tail);
+ symlook(head->s, S_WESET, (void *)"");
+ }
+ if(attr)
+ symlook(head->s, S_NOEXPORT, (void *)"");
+ break;
+ default:
+ SYNERR(hline);
+ fprint(2, "expected one of :<=\n");
+ Exit();
+ break;
+ }
+ }
+ close(fd);
+ freebuf(buf);
+ ipop();
+}
+
+void
+addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
+{
+ Word *w;
+
+ assert("addrules args", head && body);
+ /* tuck away first non-meta rule as default target*/
+ if(target1 == 0 && !(attr&REGEXP)){
+ for(w = head; w; w = w->next)
+ if(charin(w->s, "%&"))
+ break;
+ if(w == 0)
+ target1 = wdup(head);
+ }
+ for(w = head; w; w = w->next)
+ addrule(w->s, tail, body, head, attr, hline, prog);
+}
+
+static int
+rhead(char *line, Word **h, Word **t, int *attr, char **prog)
+{
+ char *p;
+ char *pp;
+ int sep;
+ Rune r;
+ int n;
+ Word *w;
+
+ p = charin(line,":=<");
+ if(p == 0)
+ return('?');
+ sep = *p;
+ *p++ = 0;
+ if(sep == '<' && *p == '|'){
+ sep = '|';
+ p++;
+ }
+ *attr = 0;
+ *prog = 0;
+ if(sep == '='){
+ pp = charin(p, termchars); /* termchars is shell-dependent */
+ if (pp && *pp == '=') {
+ while (p != pp) {
+ n = chartorune(&r, p);
+ switch(r)
+ {
+ default:
+ SYNERR(-1);
+ fprint(2, "unknown attribute '%c'\n",*p);
+ Exit();
+ case 'U':
+ *attr = 1;
+ break;
+ }
+ p += n;
+ }
+ p++; /* skip trailing '=' */
+ }
+ }
+ if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
+ while (*p) {
+ n = chartorune(&r, p);
+ if (r == ':')
+ break;
+ p += n;
+ switch(r)
+ {
+ default:
+ SYNERR(-1);
+ fprint(2, "unknown attribute '%c'\n", p[-1]);
+ Exit();
+ case 'D':
+ *attr |= DEL;
+ break;
+ case 'E':
+ *attr |= NOMINUSE;
+ break;
+ case 'n':
+ *attr |= NOVIRT;
+ break;
+ case 'N':
+ *attr |= NOREC;
+ break;
+ case 'P':
+ pp = utfrune(p, ':');
+ if (pp == 0 || *pp == 0)
+ goto eos;
+ *pp = 0;
+ *prog = strdup(p);
+ *pp = ':';
+ p = pp;
+ break;
+ case 'Q':
+ *attr |= QUIET;
+ break;
+ case 'R':
+ *attr |= REGEXP;
+ break;
+ case 'U':
+ *attr |= UPD;
+ break;
+ case 'V':
+ *attr |= VIR;
+ break;
+ }
+ }
+ if (*p++ != ':') {
+ eos:
+ SYNERR(-1);
+ fprint(2, "missing trailing :\n");
+ Exit();
+ }
+ }
+ *h = w = stow(line);
+ if(*w->s == 0 && sep != '<' && sep != '|') {
+ SYNERR(mkinline-1);
+ fprint(2, "no var on left side of assignment/rule\n");
+ Exit();
+ }
+ *t = stow(p);
+ return(sep);
+}
+
+static char *
+rbody(Biobuf *in)
+{
+ Bufblock *buf;
+ int r, lastr;
+ char *p;
+
+ lastr = '\n';
+ buf = newbuf();
+ for(;;){
+ r = Bgetrune(in);
+ if (r < 0)
+ break;
+ if (lastr == '\n') {
+ if (r == '#')
+ rinsert(buf, r);
+ else if (r != ' ' && r != '\t') {
+ Bungetrune(in);
+ break;
+ }
+ } else
+ rinsert(buf, r);
+ lastr = r;
+ if (r == '\n')
+ mkinline++;
+ }
+ insert(buf, 0);
+ p = strdup(buf->start);
+ freebuf(buf);
+ return p;
+}
+
+struct input
+{
+ char *file;
+ int line;
+ struct input *next;
+};
+static struct input *inputs = 0;
+
+void
+ipush(void)
+{
+ struct input *in, *me;
+
+ me = (struct input *)Malloc(sizeof(*me));
+ me->file = infile;
+ me->line = mkinline;
+ me->next = 0;
+ if(inputs == 0)
+ inputs = me;
+ else {
+ for(in = inputs; in->next; )
+ in = in->next;
+ in->next = me;
+ }
+}
+
+void
+ipop(void)
+{
+ struct input *in, *me;
+
+ assert("pop input list", inputs != 0);
+ if(inputs->next == 0){
+ me = inputs;
+ inputs = 0;
+ } else {
+ for(in = inputs; in->next->next; )
+ in = in->next;
+ me = in->next;
+ in->next = 0;
+ }
+ infile = me->file;
+ mkinline = me->line;
+ free((char *)me);
+}
diff --git a/utils/mk/rc.c b/utils/mk/rc.c
new file mode 100644
index 00000000..657ddf27
--- /dev/null
+++ b/utils/mk/rc.c
@@ -0,0 +1,175 @@
+#include "mk.h"
+
+char *termchars = "'= \t"; /*used in parse.c to isolate assignment attribute*/
+char *shflags = "-I"; /* rc flag to force non-interactive mode */
+int IWS = '\1'; /* inter-word separator in env - not used in plan 9 */
+
+/*
+ * This file contains functions that depend on rc's syntax. Most
+ * of the routines extract strings observing rc's escape conventions
+ */
+
+
+/*
+ * skip a token in single quotes.
+ */
+static char *
+squote(char *cp)
+{
+ Rune r;
+ int n;
+
+ while(*cp){
+ n = chartorune(&r, cp);
+ if(r == '\'') {
+ n += chartorune(&r, cp+n);
+ if(r != '\'')
+ return(cp);
+ }
+ cp += n;
+ }
+ SYNERR(-1); /* should never occur */
+ fprint(2, "missing closing '\n");
+ return 0;
+}
+
+/*
+ * search a string for characters in a pattern set
+ * characters in quotes and variable generators are escaped
+ */
+char *
+charin(char *cp, char *pat)
+{
+ Rune r;
+ int n, vargen;
+
+ vargen = 0;
+ while(*cp){
+ n = chartorune(&r, cp);
+ switch(r){
+ case '\'': /* skip quoted string */
+ cp = squote(cp+1); /* n must = 1 */
+ if(!cp)
+ return 0;
+ break;
+ case '$':
+ if(*(cp+1) == '{')
+ vargen = 1;
+ break;
+ case '}':
+ if(vargen)
+ vargen = 0;
+ else if(utfrune(pat, r))
+ return cp;
+ break;
+ default:
+ if(vargen == 0 && utfrune(pat, r))
+ return cp;
+ break;
+ }
+ cp += n;
+ }
+ if(vargen){
+ SYNERR(-1);
+ fprint(2, "missing closing } in pattern generator\n");
+ }
+ return 0;
+}
+
+/*
+ * extract an escaped token. Possible escape chars are single-quote,
+ * double-quote,and backslash. Only the first is valid for rc. the
+ * others are just inserted into the receiving buffer.
+ */
+char*
+expandquote(char *s, Rune r, Bufblock *b)
+{
+ if (r != '\'') {
+ rinsert(b, r);
+ return s;
+ }
+
+ while(*s){
+ s += chartorune(&r, s);
+ if(r == '\'') {
+ if(*s == '\'')
+ s++;
+ else
+ return s;
+ }
+ rinsert(b, r);
+ }
+ return 0;
+}
+
+/*
+ * Input an escaped token. Possible escape chars are single-quote,
+ * double-quote and backslash. Only the first is a valid escape for
+ * rc; the others are just inserted into the receiving buffer.
+ */
+int
+escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
+{
+ int c, line;
+
+ if(esc != '\'')
+ return 1;
+
+ line = mkinline;
+ while((c = nextrune(bp, 0)) > 0){
+ if(c == '\''){
+ if(preserve)
+ rinsert(buf, c);
+ c = Bgetrune(bp);
+ if (c < 0)
+ break;
+ if(c != '\''){
+ Bungetrune(bp);
+ return 1;
+ }
+ }
+ rinsert(buf, c);
+ }
+ SYNERR(line); fprint(2, "missing closing %c\n", esc);
+ return 0;
+}
+
+/*
+ * copy a single-quoted string; s points to char after opening quote
+ */
+static char *
+copysingle(char *s, Bufblock *buf)
+{
+ Rune r;
+
+ while(*s){
+ s += chartorune(&r, s);
+ rinsert(buf, r);
+ if(r == '\'')
+ break;
+ }
+ return s;
+}
+/*
+ * check for quoted strings. backquotes are handled here; single quotes above.
+ * s points to char after opening quote, q.
+ */
+char *
+copyq(char *s, Rune q, Bufblock *buf)
+{
+ if(q == '\'') /* copy quoted string */
+ return copysingle(s, buf);
+
+ if(q != '`') /* not quoted */
+ return s;
+
+ while(*s){ /* copy backquoted string */
+ s += chartorune(&q, s);
+ rinsert(buf, q);
+ if(q == '}')
+ break;
+ if(q == '\'')
+ s = copysingle(s, buf); /* copy quoted string */
+ }
+ return s;
+}
diff --git a/utils/mk/recipe.c b/utils/mk/recipe.c
new file mode 100644
index 00000000..973bac17
--- /dev/null
+++ b/utils/mk/recipe.c
@@ -0,0 +1,117 @@
+#include "mk.h"
+
+int
+dorecipe(Node *node)
+{
+ char buf[BIGBLOCK];
+ register Node *n;
+ Rule *r = 0;
+ Arc *a, *aa;
+ Word head, ahead, lp, ln, *w, *ww, *aw;
+ Symtab *s;
+ int did = 0;
+
+ aa = 0;
+ /*
+ pick up the rule
+ */
+ for(a = node->prereqs; a; a = a->next)
+ if(*a->r->recipe)
+ r = (aa = a)->r;
+ /*
+ no recipe? go to buggery!
+ */
+ if(r == 0){
+ if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){
+ fprint(2, "mk: no recipe to make '%s'\n", node->name);
+ Exit();
+ }
+ if(strchr(node->name, '(') && node->time == 0)
+ MADESET(node, MADE);
+ else
+ update(0, node);
+ if(tflag){
+ if(!(node->flags&VIRTUAL))
+ touch(node->name);
+ else if(explain)
+ Bprint(&bout, "no touch of virtual '%s'\n", node->name);
+ }
+ return(did);
+ }
+ /*
+ build the node list
+ */
+ node->next = 0;
+ head.next = 0;
+ ww = &head;
+ ahead.next = 0;
+ aw = &ahead;
+ if(r->attr&REGEXP){
+ ww->next = newword(node->name);
+ aw->next = newword(node->name);
+ } else {
+ for(w = r->alltargets; w; w = w->next){
+ if(r->attr&META)
+ subst(aa->stem, w->s, buf);
+ else
+ strcpy(buf, w->s);
+ aw->next = newword(buf);
+ aw = aw->next;
+ if((s = symlook(buf, S_NODE, 0)) == 0)
+ continue; /* not a node we are interested in */
+ n = (Node *)s->value;
+ if(aflag == 0 && n->time) {
+ for(a = n->prereqs; a; a = a->next)
+ if(a->n && outofdate(n, a, 0))
+ break;
+ if(a == 0)
+ continue;
+ }
+ ww->next = newword(buf);
+ ww = ww->next;
+ if(n == node) continue;
+ n->next = node->next;
+ node->next = n;
+ }
+ }
+ for(n = node; n; n = n->next)
+ if((n->flags&READY) == 0)
+ return(did);
+ /*
+ gather the params for the job
+ */
+ lp.next = ln.next = 0;
+ for(n = node; n; n = n->next){
+ for(a = n->prereqs; a; a = a->next){
+ if(a->n){
+ addw(&lp, a->n->name);
+ if(outofdate(n, a, 0)){
+ addw(&ln, a->n->name);
+ if(explain)
+ fprint(1, "%s(%ld) < %s(%ld)\n",
+ n->name, n->time, a->n->name, a->n->time);
+ }
+ } else {
+ if(explain)
+ fprint(1, "%s has no prerequisites\n",
+ n->name);
+ }
+ }
+ MADESET(n, BEINGMADE);
+ }
+ /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),wtos(lp.next, ' '));/**/
+ run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, ahead.next));
+ return(1);
+}
+
+void
+addw(Word *w, char *s)
+{
+ Word *lw;
+
+ for(lw = w; w = w->next; lw = w){
+ if(strcmp(s, w->s) == 0)
+ return;
+ }
+ lw->next = newword(s);
+}
diff --git a/utils/mk/rule.c b/utils/mk/rule.c
new file mode 100644
index 00000000..662f067f
--- /dev/null
+++ b/utils/mk/rule.c
@@ -0,0 +1,107 @@
+#include "mk.h"
+
+static Rule *lr, *lmr;
+static int rcmp(Rule *r, char *target, Word *tail);
+static int nrules = 0;
+
+void
+addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, char *prog)
+{
+ Rule *r;
+ Rule *rr;
+ Symtab *sym;
+ int reuse;
+
+ r = 0;
+ reuse = 0;
+ if(sym = symlook(head, S_TARGET, 0)){
+ for(r = (Rule *)sym->value; r; r = r->chain)
+ if(rcmp(r, head, tail) == 0){
+ reuse = 1;
+ break;
+ }
+ }
+ if(r == 0)
+ r = (Rule *)Malloc(sizeof(Rule));
+ r->target = head;
+ r->tail = tail;
+ r->recipe = body;
+ r->line = hline;
+ r->file = infile;
+ r->attr = attr;
+ r->alltargets = ahead;
+ r->prog = prog;
+ r->rule = nrules++;
+ if(!reuse){
+ rr = (Rule *)symlook(head, S_TARGET, (void *)r)->value;
+ if(rr != r){
+ r->chain = rr->chain;
+ rr->chain = r;
+ } else
+ r->chain = 0;
+ }
+ if(!reuse)
+ r->next = 0;
+ if((attr&REGEXP) || charin(head, "%&")){
+ r->attr |= META;
+ if(reuse)
+ return;
+ if(attr&REGEXP){
+ patrule = r;
+ r->pat = regcomp(head);
+ }
+ if(metarules == 0)
+ metarules = lmr = r;
+ else {
+ lmr->next = r;
+ lmr = r;
+ }
+ } else {
+ if(reuse)
+ return;
+ r->pat = 0;
+ if(rules == 0)
+ rules = lr = r;
+ else {
+ lr->next = r;
+ lr = r;
+ }
+ }
+}
+
+void
+dumpr(char *s, Rule *r)
+{
+ Bprint(&bout, "%s: start=%ld\n", s, r);
+ for(; r; r = r->next){
+ Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld alltarget='%s'",
+ r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' '));
+ if(r->prog)
+ Bprint(&bout, " prog='%s'", r->prog);
+ Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, ' '));
+ Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe);
+ }
+}
+
+static int
+rcmp(Rule *r, char *target, Word *tail)
+{
+ Word *w;
+
+ if(strcmp(r->target, target))
+ return 1;
+ for(w = r->tail; w && tail; w = w->next, tail = tail->next)
+ if(strcmp(w->s, tail->s))
+ return 1;
+ return(w || tail);
+}
+
+char *
+rulecnt(void)
+{
+ char *s;
+
+ s = Malloc(nrules);
+ memset(s, 0, nrules);
+ return(s);
+}
diff --git a/utils/mk/run.c b/utils/mk/run.c
new file mode 100644
index 00000000..4ef4221a
--- /dev/null
+++ b/utils/mk/run.c
@@ -0,0 +1,297 @@
+#include "mk.h"
+
+typedef struct Event
+{
+ int pid;
+ Job *job;
+} Event;
+static Event *events;
+static int nevents, nrunning, nproclimit;
+
+typedef struct Process
+{
+ int pid;
+ int status;
+ struct Process *b, *f;
+} Process;
+static Process *phead, *pfree;
+static void sched(void);
+static void pnew(int, int), pdelete(Process *);
+
+int pidslot(int);
+
+void
+run(Job *j)
+{
+ Job *jj;
+
+ if(jobs){
+ for(jj = jobs; jj->next; jj = jj->next)
+ ;
+ jj->next = j;
+ } else
+ jobs = j;
+ j->next = 0;
+ /* this code also in waitup after parse redirect */
+ if(nrunning < nproclimit)
+ sched();
+}
+
+static void
+sched(void)
+{
+ char *flags;
+ Job *j;
+ Bufblock *buf;
+ int slot;
+ Node *n;
+ Envy *e;
+
+ if(jobs == 0){
+ usage();
+ return;
+ }
+ j = jobs;
+ jobs = j->next;
+ if(DEBUG(D_EXEC))
+ fprint(1, "firing up job for target %s\n", wtos(j->t, ' '));
+ slot = nextslot();
+ events[slot].job = j;
+ buf = newbuf();
+ e = buildenv(j, slot);
+ shprint(j->r->recipe, e, buf);
+ if(!tflag && (nflag || !(j->r->attr&QUIET)))
+ Bwrite(&bout, buf->start, (long)strlen(buf->start));
+ freebuf(buf);
+ if(nflag||tflag){
+ for(n = j->n; n; n = n->next){
+ if(tflag){
+ if(!(n->flags&VIRTUAL))
+ touch(n->name);
+ else if(explain)
+ Bprint(&bout, "no touch of virtual '%s'\n", n->name);
+ }
+ n->time = time((long *)0);
+ MADESET(n, MADE);
+ }
+ } else {
+ if(DEBUG(D_EXEC))
+ fprint(1, "recipe='%s'", j->r->recipe);/**/
+ Bflush(&bout);
+ if(j->r->attr&NOMINUSE)
+ flags = 0;
+ else
+ flags = "-e";
+ events[slot].pid = execsh(flags, j->r->recipe, 0, e);
+ usage();
+ nrunning++;
+ if(DEBUG(D_EXEC))
+ fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid);
+ }
+}
+
+int
+waitup(int echildok, int *retstatus)
+{
+ Envy *e;
+ int pid;
+ int slot;
+ Symtab *s;
+ Word *w;
+ Job *j;
+ char buf[ERRMAX];
+ Bufblock *bp;
+ int uarg = 0;
+ int done;
+ Node *n;
+ Process *p;
+ extern int runerrs;
+
+ /* first check against the proces slist */
+ if(retstatus)
+ for(p = phead; p; p = p->f)
+ if(p->pid == *retstatus){
+ *retstatus = p->status;
+ pdelete(p);
+ return(-1);
+ }
+again: /* rogue processes */
+ pid = waitfor(buf);
+ if(pid == -1){
+ if(echildok > 0)
+ return(1);
+ else {
+ fprint(2, "mk: (waitup %d) ", echildok);
+ perror("mk wait");
+ Exit();
+ }
+ }
+ if(DEBUG(D_EXEC))
+ fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf);
+ if(retstatus && pid == *retstatus){
+ *retstatus = buf[0]? 1:0;
+ return(-1);
+ }
+ slot = pidslot(pid);
+ if(slot < 0){
+ if(DEBUG(D_EXEC))
+ fprint(2, "mk: wait returned unexpected process %d\n", pid);
+ pnew(pid, buf[0]? 1:0);
+ goto again;
+ }
+ j = events[slot].job;
+ usage();
+ nrunning--;
+ events[slot].pid = -1;
+ if(buf[0]){
+ e = buildenv(j, slot);
+ bp = newbuf();
+ shprint(j->r->recipe, e, bp);
+ front(bp->start);
+ fprint(2, "mk: %s: exit status=%s", bp->start, buf);
+ freebuf(bp);
+ for(n = j->n, done = 0; n; n = n->next)
+ if(n->flags&DELETE){
+ if(done++ == 0)
+ fprint(2, ", deleting");
+ fprint(2, " '%s'", n->name);
+ delete(n->name);
+ }
+ fprint(2, "\n");
+ if(kflag){
+ runerrs++;
+ uarg = 1;
+ } else {
+ jobs = 0;
+ Exit();
+ }
+ }
+ for(w = j->t; w; w = w->next){
+ if((s = symlook(w->s, S_NODE, 0)) == 0)
+ continue; /* not interested in this node */
+ update(uarg, (Node *)s->value);
+ }
+ if(nrunning < nproclimit)
+ sched();
+ return(0);
+}
+
+void
+nproc(void)
+{
+ Symtab *sym;
+ Word *w;
+
+ if(sym = symlook("NPROC", S_VAR, 0)) {
+ w = (Word *) sym->value;
+ if (w && w->s && w->s[0])
+ nproclimit = atoi(w->s);
+ }
+ if(nproclimit < 1)
+ nproclimit = 1;
+ if(DEBUG(D_EXEC))
+ fprint(1, "nprocs = %d\n", nproclimit);
+ if(nproclimit > nevents){
+ if(nevents)
+ events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event));
+ else
+ events = (Event *)Malloc(nproclimit*sizeof(Event));
+ while(nevents < nproclimit)
+ events[nevents++].pid = 0;
+ }
+}
+
+int
+nextslot(void)
+{
+ int i;
+
+ for(i = 0; i < nproclimit; i++)
+ if(events[i].pid <= 0) return i;
+ assert("out of slots!!", 0);
+ return 0; /* cyntax */
+}
+
+int
+pidslot(int pid)
+{
+ int i;
+
+ for(i = 0; i < nevents; i++)
+ if(events[i].pid == pid) return(i);
+ if(DEBUG(D_EXEC))
+ fprint(2, "mk: wait returned unexpected process %d\n", pid);
+ return(-1);
+}
+
+
+static void
+pnew(int pid, int status)
+{
+ Process *p;
+
+ if(pfree){
+ p = pfree;
+ pfree = p->f;
+ } else
+ p = (Process *)Malloc(sizeof(Process));
+ p->pid = pid;
+ p->status = status;
+ p->f = phead;
+ phead = p;
+ if(p->f)
+ p->f->b = p;
+ p->b = 0;
+}
+
+static void
+pdelete(Process *p)
+{
+ if(p->f)
+ p->f->b = p->b;
+ if(p->b)
+ p->b->f = p->f;
+ else
+ phead = p->f;
+ p->f = pfree;
+ pfree = p;
+}
+
+void
+killchildren(char *msg)
+{
+ Process *p;
+
+ kflag = 1; /* to make sure waitup doesn't exit */
+ jobs = 0; /* make sure no more get scheduled */
+ for(p = phead; p; p = p->f)
+ expunge(p->pid, msg);
+ while(waitup(1, (int *)0) == 0)
+ ;
+ Bprint(&bout, "mk: %s\n", msg);
+ Exit();
+}
+
+static long tslot[1000];
+static long tick;
+
+void
+usage(void)
+{
+ long t;
+
+ time(&t);
+ if(tick)
+ tslot[nrunning] += (t-tick);
+ tick = t;
+}
+
+void
+prusage(void)
+{
+ int i;
+
+ usage();
+ for(i = 0; i <= nevents; i++)
+ fprint(1, "%d: %ld\n", i, tslot[i]);
+}
diff --git a/utils/mk/sh.c b/utils/mk/sh.c
new file mode 100644
index 00000000..524167a5
--- /dev/null
+++ b/utils/mk/sh.c
@@ -0,0 +1,189 @@
+#include "mk.h"
+
+char *termchars = "\"'= \t"; /*used in parse.c to isolate assignment attribute*/
+char *shflags = 0;
+int IWS = ' '; /* inter-word separator in env */
+
+/*
+ * This file contains functions that depend on the shell's syntax. Most
+ * of the routines extract strings observing the shell's escape conventions.
+ */
+
+
+/*
+ * skip a token in quotes.
+ */
+static char *
+squote(char *cp, int c)
+{
+ Rune r;
+ int n;
+
+ while(*cp){
+ n = chartorune(&r, cp);
+ if(r == c)
+ return cp;
+ if(r == '\\')
+ n += chartorune(&r, cp+n);
+ cp += n;
+ }
+ SYNERR(-1); /* should never occur */
+ fprint(2, "missing closing '\n");
+ return 0;
+}
+/*
+ * search a string for unescaped characters in a pattern set
+ */
+char *
+charin(char *cp, char *pat)
+{
+ Rune r;
+ int n, vargen;
+
+ vargen = 0;
+ while(*cp){
+ n = chartorune(&r, cp);
+ switch(r){
+ case '\\': /* skip escaped char */
+ cp += n;
+ n = chartorune(&r, cp);
+ break;
+ case '\'': /* skip quoted string */
+ case '"':
+ cp = squote(cp+1, r); /* n must = 1 */
+ if(!cp)
+ return 0;
+ break;
+ case '$':
+ if(*(cp+1) == '{')
+ vargen = 1;
+ break;
+ case '}':
+ if(vargen)
+ vargen = 0;
+ else if(utfrune(pat, r))
+ return cp;
+ break;
+ default:
+ if(vargen == 0 && utfrune(pat, r))
+ return cp;
+ break;
+ }
+ cp += n;
+ }
+ if(vargen){
+ SYNERR(-1);
+ fprint(2, "missing closing } in pattern generator\n");
+ }
+ return 0;
+}
+
+/*
+ * extract an escaped token. Possible escape chars are single-quote,
+ * double-quote,and backslash.
+ */
+char*
+expandquote(char *s, Rune esc, Bufblock *b)
+{
+ Rune r;
+
+ if (esc == '\\') {
+ s += chartorune(&r, s);
+ rinsert(b, r);
+ return s;
+ }
+
+ while(*s){
+ s += chartorune(&r, s);
+ if(r == esc)
+ return s;
+ if (r == '\\') {
+ rinsert(b, r);
+ s += chartorune(&r, s);
+ }
+ rinsert(b, r);
+ }
+ return 0;
+}
+
+/*
+ * Input an escaped token. Possible escape chars are single-quote,
+ * double-quote and backslash.
+ */
+int
+escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
+{
+ int c, line;
+
+ if(esc == '\\') {
+ c = Bgetrune(bp);
+ if(c == '\r')
+ c = Bgetrune(bp);
+ if (c == '\n')
+ mkinline++;
+ rinsert(buf, c);
+ return 1;
+ }
+
+ line = mkinline;
+ while((c = nextrune(bp, 0)) >= 0){
+ if(c == esc){
+ if(preserve)
+ rinsert(buf, c);
+ return 1;
+ }
+ if(c == '\\') {
+ rinsert(buf, c);
+ c = Bgetrune(bp);
+ if(c == '\r')
+ c = Bgetrune(bp);
+ if (c < 0)
+ break;
+ if (c == '\n')
+ mkinline++;
+ }
+ rinsert(buf, c);
+ }
+ SYNERR(line); fprint(2, "missing closing %c\n", esc);
+ return 0;
+}
+
+/*
+ * copy a quoted string; s points to char after opening quote
+ */
+static char *
+copysingle(char *s, Rune q, Bufblock *buf)
+{
+ Rune r;
+
+ while(*s){
+ s += chartorune(&r, s);
+ rinsert(buf, r);
+ if(r == q)
+ break;
+ }
+ return s;
+}
+/*
+ * check for quoted strings. backquotes are handled here; single quotes above.
+ * s points to char after opening quote, q.
+ */
+char *
+copyq(char *s, Rune q, Bufblock *buf)
+{
+ if(q == '\'' || q == '"') /* copy quoted string */
+ return copysingle(s, q, buf);
+
+ if(q != '`') /* not quoted */
+ return s;
+
+ while(*s){ /* copy backquoted string */
+ s += chartorune(&q, s);
+ rinsert(buf, q);
+ if(q == '`')
+ break;
+ if(q == '\'' || q == '"')
+ s = copysingle(s, q, buf); /* copy quoted string */
+ }
+ return s;
+}
diff --git a/utils/mk/shprint.c b/utils/mk/shprint.c
new file mode 100644
index 00000000..a3de277d
--- /dev/null
+++ b/utils/mk/shprint.c
@@ -0,0 +1,90 @@
+#include "mk.h"
+
+static char *vexpand(char*, Envy*, Bufblock*);
+static char *shquote(char*, Rune, Bufblock*);
+static char *shbquote(char*, Bufblock*);
+
+void
+shprint(char *s, Envy *env, Bufblock *buf)
+{
+ int n;
+ Rune r;
+
+ while(*s) {
+ n = chartorune(&r, s);
+ if (r == '$')
+ s = vexpand(s, env, buf);
+ else {
+ rinsert(buf, r);
+ s += n;
+ s = copyq(s, r, buf); /*handle quoted strings*/
+ }
+ }
+ insert(buf, 0);
+}
+
+static char *
+mygetenv(char *name, Envy *env)
+{
+ if (!env)
+ return 0;
+ if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == 0)
+ return 0;
+ /* only resolve internal variables and variables we've set */
+ for(; env->name; env++){
+ if (strcmp(env->name, name) == 0)
+ return wtos(env->values, ' ');
+ }
+ return 0;
+}
+
+static char *
+vexpand(char *w, Envy *env, Bufblock *buf)
+{
+ char *s, carry, *p, *q;
+
+ assert("vexpand no $", *w == '$');
+ p = w+1; /* skip dollar sign */
+ if(*p == '{') {
+ p++;
+ q = utfrune(p, '}');
+ if (!q)
+ q = strchr(p, 0);
+ } else
+ q = shname(p);
+ carry = *q;
+ *q = 0;
+ s = mygetenv(p, env);
+ *q = carry;
+ if (carry == '}')
+ q++;
+ if (s) {
+ bufcpy(buf, s, strlen(s));
+ free(s);
+ } else /* copy name intact*/
+ bufcpy(buf, w, q-w);
+ return(q);
+}
+
+void
+front(char *s)
+{
+ char *t, *q;
+ int i, j;
+ char *flds[512];
+
+ q = strdup(s);
+ i = getfields(q, flds, 512, 0, " \t\n");
+ if(i > 5){
+ flds[4] = flds[i-1];
+ flds[3] = "...";
+ i = 5;
+ }
+ t = s;
+ for(j = 0; j < i; j++){
+ for(s = flds[j]; *s; *t++ = *s++);
+ *t++ = ' ';
+ }
+ *t = 0;
+ free(q);
+}
diff --git a/utils/mk/symtab.c b/utils/mk/symtab.c
new file mode 100644
index 00000000..06a4d146
--- /dev/null
+++ b/utils/mk/symtab.c
@@ -0,0 +1,97 @@
+#include "mk.h"
+
+#define NHASH 4099
+#define HASHMUL 79L /* this is a good value */
+static Symtab *hash[NHASH];
+
+void
+syminit(void)
+{
+ Symtab **s, *ss, *next;
+
+ for(s = hash; s < &hash[NHASH]; s++){
+ for(ss = *s; ss; ss = next){
+ next = ss->next;
+ free((char *)ss);
+ }
+ *s = 0;
+ }
+}
+
+Symtab *
+symlook(char *sym, int space, void *install)
+{
+ long h;
+ char *p;
+ Symtab *s;
+
+ for(p = sym, h = space; *p; h += *p++)
+ h *= HASHMUL;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s; s = s->next)
+ if((s->space == space) && (strcmp(s->name, sym) == 0))
+ return(s);
+ if(install == 0)
+ return(0);
+ s = (Symtab *)Malloc(sizeof(Symtab));
+ s->space = space;
+ s->name = sym;
+ s->value = install;
+ s->next = hash[h];
+ hash[h] = s;
+ return(s);
+}
+
+void
+symdel(char *sym, int space)
+{
+ long h;
+ char *p;
+ Symtab *s, *ls;
+
+ /* multiple memory leaks */
+
+ for(p = sym, h = space; *p; h += *p++)
+ h *= HASHMUL;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h], ls = 0; s; ls = s, s = s->next)
+ if((s->space == space) && (strcmp(s->name, sym) == 0)){
+ if(ls)
+ ls->next = s->next;
+ else
+ hash[h] = s->next;
+ free((char *)s);
+ }
+}
+
+void
+symtraverse(int space, void (*fn)(Symtab*))
+{
+ Symtab **s, *ss;
+
+ for(s = hash; s < &hash[NHASH]; s++)
+ for(ss = *s; ss; ss = ss->next)
+ if(ss->space == space)
+ (*fn)(ss);
+}
+
+void
+symstat(void)
+{
+ Symtab **s, *ss;
+ int n;
+ int l[1000];
+
+ memset((char *)l, 0, sizeof(l));
+ for(s = hash; s < &hash[NHASH]; s++){
+ for(ss = *s, n = 0; ss; ss = ss->next)
+ n++;
+ l[n]++;
+ }
+ for(n = 0; n < 1000; n++)
+ if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n);
+}
diff --git a/utils/mk/var.c b/utils/mk/var.c
new file mode 100644
index 00000000..8429918d
--- /dev/null
+++ b/utils/mk/var.c
@@ -0,0 +1,41 @@
+#include "mk.h"
+
+void
+setvar(char *name, void *value)
+{
+ symlook(name, S_VAR, value)->value = value;
+ symlook(name, S_MAKEVAR, (void*)"");
+}
+
+static void
+print1(Symtab *s)
+{
+ Word *w;
+
+ Bprint(&bout, "\t%s=", s->name);
+ for (w = (Word *) s->value; w; w = w->next)
+ Bprint(&bout, "'%s'", w->s);
+ Bprint(&bout, "\n");
+}
+
+void
+dumpv(char *s)
+{
+ Bprint(&bout, "%s:\n", s);
+ symtraverse(S_VAR, print1);
+}
+
+char *
+shname(char *a)
+{
+ Rune r;
+ int n;
+
+ while (*a) {
+ n = chartorune(&r, a);
+ if (!WORDCHR(r))
+ break;
+ a += n;
+ }
+ return a;
+}
diff --git a/utils/mk/varsub.c b/utils/mk/varsub.c
new file mode 100644
index 00000000..2a9ad987
--- /dev/null
+++ b/utils/mk/varsub.c
@@ -0,0 +1,256 @@
+#include "mk.h"
+
+static Word *subsub(Word*, char*, char*);
+static Word *expandvar(char**);
+static Bufblock *varname(char**);
+static Word *extractpat(char*, char**, char*, char*);
+static int submatch(char*, Word*, Word*, int*, char**);
+static Word *varmatch(char *, char**);
+
+Word *
+varsub(char **s)
+{
+ Bufblock *b;
+ Word *w;
+
+ if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
+ return expandvar(s);
+
+ b = varname(s);
+ if(b == 0)
+ return 0;
+
+ w = varmatch(b->start, s);
+ freebuf(b);
+ return w;
+}
+
+/*
+ * extract a variable name
+ */
+static Bufblock*
+varname(char **s)
+{
+ Bufblock *b;
+ char *cp;
+ Rune r;
+ int n;
+
+ b = newbuf();
+ cp = *s;
+ for(;;){
+ n = chartorune(&r, cp);
+ if (!WORDCHR(r))
+ break;
+ rinsert(b, r);
+ cp += n;
+ }
+ if (b->current == b->start){
+ SYNERR(-1);
+ fprint(2, "missing variable name <%s>\n", *s);
+ freebuf(b);
+ return 0;
+ }
+ *s = cp;
+ insert(b, 0);
+ return b;
+}
+
+static Word*
+varmatch(char *name, char **s)
+{
+ Word *w;
+ Symtab *sym;
+ char *cp;
+
+ sym = symlook(name, S_VAR, 0);
+ if(sym){
+ /* check for at least one non-NULL value */
+ for (w = (Word*)sym->value; w; w = w->next)
+ if(w->s && *w->s)
+ return wdup(w);
+ }
+ for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */
+ ;
+ *s = cp;
+ return 0;
+}
+
+static Word*
+expandvar(char **s)
+{
+ Word *w;
+ Bufblock *buf;
+ Symtab *sym;
+ char *cp, *begin, *end;
+
+ begin = *s;
+ (*s)++; /* skip the '{' */
+ buf = varname(s);
+ if (buf == 0)
+ return 0;
+ cp = *s;
+ if (*cp == '}') { /* ${name} variant*/
+ (*s)++; /* skip the '}' */
+ w = varmatch(buf->start, s);
+ freebuf(buf);
+ return w;
+ }
+ if (*cp != ':') {
+ SYNERR(-1);
+ fprint(2, "bad variable name <%s>\n", buf->start);
+ freebuf(buf);
+ return 0;
+ }
+ cp++;
+ end = charin(cp , "}");
+ if(end == 0){
+ SYNERR(-1);
+ fprint(2, "missing '}': %s\n", begin);
+ Exit();
+ }
+ *end = 0;
+ *s = end+1;
+
+ sym = symlook(buf->start, S_VAR, 0);
+ if(sym == 0 || sym->value == 0)
+ w = newword(buf->start);
+ else
+ w = subsub((Word*) sym->value, cp, end);
+ freebuf(buf);
+ return w;
+}
+
+static Word*
+extractpat(char *s, char **r, char *term, char *end)
+{
+ int save;
+ char *cp;
+ Word *w;
+
+ cp = charin(s, term);
+ if(cp){
+ *r = cp;
+ if(cp == s)
+ return 0;
+ save = *cp;
+ *cp = 0;
+ w = stow(s);
+ *cp = save;
+ } else {
+ *r = end;
+ w = stow(s);
+ }
+ return w;
+}
+
+static Word*
+subsub(Word *v, char *s, char *end)
+{
+ int nmid;
+ Word *head, *tail, *w, *h;
+ Word *a, *b, *c, *d;
+ Bufblock *buf;
+ char *cp, *enda;
+
+ a = extractpat(s, &cp, "=%&", end);
+ b = c = d = 0;
+ if(PERCENT(*cp))
+ b = extractpat(cp+1, &cp, "=", end);
+ if(*cp == '=')
+ c = extractpat(cp+1, &cp, "&%", end);
+ if(PERCENT(*cp))
+ d = stow(cp+1);
+ else if(*cp)
+ d = stow(cp);
+
+ head = tail = 0;
+ buf = newbuf();
+ for(; v; v = v->next){
+ h = w = 0;
+ if(submatch(v->s, a, b, &nmid, &enda)){
+ /* enda points to end of A match in source;
+ * nmid = number of chars between end of A and start of B
+ */
+ if(c){
+ h = w = wdup(c);
+ while(w->next)
+ w = w->next;
+ }
+ if(PERCENT(*cp) && nmid > 0){
+ if(w){
+ bufcpy(buf, w->s, strlen(w->s));
+ bufcpy(buf, enda, nmid);
+ insert(buf, 0);
+ free(w->s);
+ w->s = strdup(buf->start);
+ } else {
+ bufcpy(buf, enda, nmid);
+ insert(buf, 0);
+ h = w = newword(buf->start);
+ }
+ buf->current = buf->start;
+ }
+ if(d && *d->s){
+ if(w){
+
+ bufcpy(buf, w->s, strlen(w->s));
+ bufcpy(buf, d->s, strlen(d->s));
+ insert(buf, 0);
+ free(w->s);
+ w->s = strdup(buf->start);
+ w->next = wdup(d->next);
+ while(w->next)
+ w = w->next;
+ buf->current = buf->start;
+ } else
+ h = w = wdup(d);
+ }
+ }
+ if(w == 0)
+ h = w = newword(v->s);
+
+ if(head == 0)
+ head = h;
+ else
+ tail->next = h;
+ tail = w;
+ }
+ freebuf(buf);
+ delword(a);
+ delword(b);
+ delword(c);
+ delword(d);
+ return head;
+}
+
+static int
+submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
+{
+ Word *w;
+ int n;
+ char *end;
+
+ n = 0;
+ for(w = a; w; w = w->next){
+ n = strlen(w->s);
+ if(strncmp(s, w->s, n) == 0)
+ break;
+ }
+ if(a && w == 0) /* a == NULL matches everything*/
+ return 0;
+
+ *enda = s+n; /* pointer to end a A part match */
+ *nmid = strlen(s)-n; /* size of remainder of source */
+ end = *enda+*nmid;
+ for(w = b; w; w = w->next){
+ n = strlen(w->s);
+ if(strcmp(w->s, end-n) == 0){
+ *nmid -= n;
+ break;
+ }
+ }
+ if(b && w == 0) /* b == NULL matches everything */
+ return 0;
+ return 1;
+}
diff --git a/utils/mk/word.c b/utils/mk/word.c
new file mode 100644
index 00000000..ac34c47b
--- /dev/null
+++ b/utils/mk/word.c
@@ -0,0 +1,180 @@
+#include "mk.h"
+
+static Word *nextword(char**);
+
+Word*
+newword(char *s)
+{
+ Word *w;
+
+ w = (Word *)Malloc(sizeof(Word));
+ w->s = strdup(s);
+ w->next = 0;
+ return(w);
+}
+
+Word *
+stow(char *s)
+{
+ Word *head, *w, *new;
+
+ w = head = 0;
+ while(*s){
+ new = nextword(&s);
+ if(new == 0)
+ break;
+ if (w)
+ w->next = new;
+ else
+ head = w = new;
+ while(w->next)
+ w = w->next;
+
+ }
+ if (!head)
+ head = newword("");
+ return(head);
+}
+
+char *
+wtos(Word *w, int sep)
+{
+ Bufblock *buf;
+ char *cp;
+
+ buf = newbuf();
+ for(; w; w = w->next){
+ for(cp = w->s; *cp; cp++)
+ insert(buf, *cp);
+ if(w->next)
+ insert(buf, sep);
+ }
+ insert(buf, 0);
+ cp = strdup(buf->start);
+ freebuf(buf);
+ return(cp);
+}
+
+Word*
+wdup(Word *w)
+{
+ Word *v, *new, *base;
+
+ v = base = 0;
+ while(w){
+ new = newword(w->s);
+ if(v)
+ v->next = new;
+ else
+ base = new;
+ v = new;
+ w = w->next;
+ }
+ return base;
+}
+
+void
+delword(Word *w)
+{
+ Word *v;
+
+ while(v = w){
+ w = w->next;
+ if(v->s)
+ free(v->s);
+ free(v);
+ }
+}
+
+/*
+ * break out a word from a string handling quotes, executions,
+ * and variable expansions.
+ */
+static Word*
+nextword(char **s)
+{
+ Bufblock *b;
+ Word *head, *tail, *w;
+ Rune r;
+ char *cp;
+
+ cp = *s;
+ b = newbuf();
+ head = tail = 0;
+ while(*cp == ' ' || *cp == '\t') /* leading white space */
+ cp++;
+ while(*cp){
+ cp += chartorune(&r, cp);
+ switch(r)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ goto out;
+ case '\\':
+ case '\'':
+ case '"':
+ cp = expandquote(cp, r, b);
+ if(cp == 0){
+ fprint(2, "missing closing quote: %s\n", *s);
+ Exit();
+ }
+ break;
+ case '$':
+ w = varsub(&cp);
+ if(w == 0)
+ break;
+ if(b->current != b->start){
+ bufcpy(b, w->s, strlen(w->s));
+ insert(b, 0);
+ free(w->s);
+ w->s = strdup(b->start);
+ b->current = b->start;
+ }
+ if(head){
+ bufcpy(b, tail->s, strlen(tail->s));
+ bufcpy(b, w->s, strlen(w->s));
+ insert(b, 0);
+ free(tail->s);
+ tail->s = strdup(b->start);
+ tail->next = w->next;
+ free(w->s);
+ free(w);
+ b->current = b->start;
+ } else
+ tail = head = w;
+ while(tail->next)
+ tail = tail->next;
+ break;
+ default:
+ rinsert(b, r);
+ break;
+ }
+ }
+out:
+ *s = cp;
+ if(b->current != b->start){
+ if(head){
+ cp = b->current;
+ bufcpy(b, tail->s, strlen(tail->s));
+ bufcpy(b, b->start, cp-b->start);
+ insert(b, 0);
+ free(tail->s);
+ tail->s = strdup(cp);
+ } else {
+ insert(b, 0);
+ head = newword(b->start);
+ }
+ }
+ freebuf(b);
+ return head;
+}
+
+void
+dumpw(char *s, Word *w)
+{
+ Bprint(&bout, "%s", s);
+ for(; w; w = w->next)
+ Bprint(&bout, " '%s'", w->s);
+ Bputc(&bout, '\n');
+}
diff --git a/utils/mkdir/mkdir.c b/utils/mkdir/mkdir.c
new file mode 100644
index 00000000..5bdf53c0
--- /dev/null
+++ b/utils/mkdir/mkdir.c
@@ -0,0 +1,18 @@
+#include <lib9.h>
+
+void
+main(int argc, char **argv)
+{
+ for(argv++; *argv; argv++){
+ if(access(*argv, 0) == 0){
+ fprint(2, "mkdir: %s already exists\n", *argv);
+ exits("exists");
+ }
+ if(mkdir(*argv) < 0){
+ fprint(2, "mkdir: can't create %s\n", *argv);
+ perror(0);
+ exits("error");
+ }
+ }
+ exits(0);
+}
diff --git a/utils/mkdir/mkfile b/utils/mkdir/mkfile
new file mode 100644
index 00000000..af0eb499
--- /dev/null
+++ b/utils/mkdir/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=mkdir
+
+OFILES= mkdir.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/mkext/mkext.c b/utils/mkext/mkext.c
new file mode 100644
index 00000000..3361a23b
--- /dev/null
+++ b/utils/mkext/mkext.c
@@ -0,0 +1,313 @@
+#include <lib9.h>
+#include <bio.h>
+
+#define dirfwstat(b,d) 0 /* lib9 doesn't implement it */
+#define mkdir extmkdir
+
+enum{
+ LEN = 8*1024,
+ NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
+};
+
+int selected(char*, int, char*[]);
+void mkdirs(char*, char*);
+void mkdir(char*, ulong, ulong, char*, char*);
+void extract(char*, ulong, ulong, char*, char*, ulong);
+void seekpast(ulong);
+void error(char*, ...);
+void warn(char*, ...);
+void usage(void);
+#pragma varargck argpos warn 1
+#pragma varargck argpos error 1
+
+Biobuf bin;
+uchar binbuf[2*LEN];
+char linebuf[LEN];
+int uflag;
+int hflag;
+int vflag;
+int Tflag;
+
+void
+main(int argc, char **argv)
+{
+ Biobuf bout;
+ char *fields[NFLDS], name[2*LEN], *p, *namep;
+ char *uid, *gid;
+ ulong mode, bytes, mtime;
+
+ setbinmode();
+ quotefmtinstall();
+ namep = name;
+ ARGBEGIN{
+ case 'd':
+ p = ARGF();
+ if(strlen(p) >= LEN)
+ error("destination fs name too long\n");
+ strcpy(name, p);
+ namep = name + strlen(name);
+ break;
+ case 'h':
+ hflag = 1;
+ Binit(&bout, 1, OWRITE);
+ break;
+ case 'u':
+ uflag = 1;
+ Tflag = 1;
+ break;
+ case 'T':
+ Tflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
+ while(p = Brdline(&bin, '\n')){
+ p[Blinelen(&bin)-1] = '\0';
+ strcpy(linebuf, p);
+ p = linebuf;
+ if(strcmp(p, "end of archive") == 0){
+ Bterm(&bout);
+ fprint(2, "done\n");
+ exits(0);
+ }
+ if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){
+ warn("too few fields in file header");
+ continue;
+ }
+ strcpy(namep, fields[0]);
+ mode = strtoul(fields[1], 0, 8);
+ uid = fields[2];
+ gid = fields[3];
+ mtime = strtoul(fields[4], 0, 10);
+ bytes = strtoul(fields[5], 0, 10);
+ if(argc){
+ if(!selected(namep, argc, argv)){
+ if(bytes)
+ seekpast(bytes);
+ continue;
+ }
+ mkdirs(name, namep);
+ }
+ if(hflag){
+ Bprint(&bout, "%q %luo %q %q %lud %lud\n",
+ name, mode, uid, gid, mtime, bytes);
+ if(bytes)
+ seekpast(bytes);
+ continue;
+ }
+ if(mode & DMDIR)
+ mkdir(name, mode, mtime, uid, gid);
+ else
+ extract(name, mode, mtime, uid, gid, bytes);
+ }
+ fprint(2, "premature end of archive\n");
+ exits("premature end of archive");
+}
+
+int
+fileprefix(char *prefix, char *s)
+{
+ while(*prefix)
+ if(*prefix++ != *s++)
+ return 0;
+ if(*s && *s != '/')
+ return 0;
+ return 1;
+}
+
+int
+selected(char *s, int argc, char *argv[])
+{
+ int i;
+
+ for(i=0; i<argc; i++)
+ if(fileprefix(argv[i], s))
+ return 1;
+ return 0;
+}
+
+void
+mkdirs(char *name, char *namep)
+{
+ char buf[2*LEN], *p;
+ int fd;
+
+ strcpy(buf, name);
+ for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){
+ if(p[1] == '\0')
+ return;
+ *p = 0;
+ fd = create(buf, OREAD, 0775|DMDIR);
+ close(fd);
+ *p = '/';
+ }
+}
+
+void
+mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
+{
+ Dir *d, xd;
+ int fd;
+ char *p;
+ char olderr[256];
+
+ fd = create(name, OREAD, mode);
+ if(fd < 0){
+ rerrstr(olderr, sizeof(olderr));
+ if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
+ free(d);
+ warn("can't make directory %q, mode %luo: %s", name, mode, olderr);
+ return;
+ }
+ free(d);
+ }
+ close(fd);
+
+ d = &xd;
+ nulldir(d);
+ p = utfrrune(name, L'/');
+ if(p)
+ p++;
+ else
+ p = name;
+ d->name = p;
+ if(uflag){
+ d->uid = uid;
+ d->gid = gid;
+ }
+ if(Tflag)
+ d->mtime = mtime;
+ d->mode = mode;
+ if(dirwstat(name, d) < 0)
+ warn("can't set modes for %q: %r", name);
+
+ if(uflag||Tflag){
+ if((d = dirstat(name)) == nil){
+ warn("can't reread modes for %q: %r", name);
+ return;
+ }
+ if(Tflag && d->mtime != mtime)
+ warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime);
+ if(uflag && strcmp(uid, d->uid))
+ warn("%q: uid mismatch %q %q", name, uid, d->uid);
+ if(uflag && strcmp(gid, d->gid))
+ warn("%q: gid mismatch %q %q", name, gid, d->gid);
+ }
+}
+
+void
+extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes)
+{
+ Dir d, *nd;
+ Biobuf *b;
+ char buf[LEN];
+ char *p;
+ ulong n, tot;
+
+ if(vflag)
+ print("x %q %lud bytes\n", name, bytes);
+
+ b = Bopen(name, OWRITE);
+ if(!b){
+ warn("can't make file %q: %r", name);
+ seekpast(bytes);
+ return;
+ }
+ for(tot = 0; tot < bytes; tot += n){
+ n = sizeof buf;
+ if(tot + n > bytes)
+ n = bytes - tot;
+ n = Bread(&bin, buf, n);
+ if(n <= 0)
+ error("premature eof reading %q", name);
+ if(Bwrite(b, buf, n) != n)
+ warn("error writing %q: %r", name);
+ }
+
+ nulldir(&d);
+ p = utfrrune(name, '/');
+ if(p)
+ p++;
+ else
+ p = name;
+ d.name = p;
+ if(uflag){
+ d.uid = uid;
+ d.gid = gid;
+ }
+ if(Tflag)
+ d.mtime = mtime;
+ d.mode = mode;
+ Bflush(b);
+ if(dirfwstat(Bfildes(b), &d) < 0)
+ warn("can't set modes for %q: %r", name);
+ if(uflag||Tflag){
+ if((nd = dirfstat(Bfildes(b))) == nil)
+ warn("can't reread modes for %q: %r", name);
+ else{
+ if(Tflag && nd->mtime != mtime)
+ warn("%q: time mismatch %lud %lud\n", name, mtime, nd->mtime);
+ if(uflag && strcmp(uid, nd->uid))
+ warn("%q: uid mismatch %q %q", name, uid, nd->uid);
+ if(uflag && strcmp(gid, nd->gid))
+ warn("%q: gid mismatch %q %q", name, gid, nd->gid);
+ free(nd);
+ }
+ }
+ Bterm(b);
+}
+
+void
+seekpast(ulong bytes)
+{
+ char buf[LEN];
+ ulong tot, n;
+
+ for(tot = 0; tot < bytes; tot += n){
+ n = sizeof buf;
+ if(tot + n > bytes)
+ n = bytes - tot;
+ n = Bread(&bin, buf, n);
+ if(n < 0)
+ error("premature eof");
+ }
+}
+
+void
+error(char *fmt, ...)
+{
+ char buf[1024];
+ va_list arg;
+
+ sprint(buf, "%q: ", argv0);
+ va_start(arg, fmt);
+ vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s\n", buf);
+ exits(0);
+}
+
+void
+warn(char *fmt, ...)
+{
+ char buf[1024];
+ va_list arg;
+
+ sprint(buf, "%q: ", argv0);
+ va_start(arg, fmt);
+ vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s\n", buf);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
+ exits("usage");
+}
diff --git a/utils/mkext/mkfile b/utils/mkext/mkfile
new file mode 100644
index 00000000..a8b4caad
--- /dev/null
+++ b/utils/mkext/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=mkext
+
+OFILES= mkext.$O\
+
+HFILES=
+
+LIBS=bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/mkfile b/utils/mkfile
new file mode 100644
index 00000000..c70e52d4
--- /dev/null
+++ b/utils/mkfile
@@ -0,0 +1,112 @@
+<../mkconfig
+
+#
+# Utils we build everywhere, because the Plan 9 versions don't yet
+# contain our changes (or they don't exist on Plan 9).
+# Fairly soon the Plan 9 compilers will be updated to match.
+#
+ALWAYS=\
+ libmach\
+ libregexp\
+ iar\
+ cc\
+ 0a\
+ 0c\
+ 0l\
+ 1a\
+ 1c\
+ 1l\
+ 2a\
+ 2c\
+ 2l\
+ 5a\
+ 5c\
+ 5l\
+# 5i\
+ 5coff\
+ 5cv\
+ ka\
+ kc\
+ kl\
+ qa\
+ qc\
+ ql\
+ sqz\
+ tc\
+ acid\
+ srclist\
+ ftl\
+ ms2\
+ data2c\
+ data2s\
+ idea\
+ kprof\
+ c2l\
+ mkppcimage\
+ nm\
+
+#
+# Utils we build on Posix and Nt, which already exist on Plan 9.
+#
+NOTPLAN9=\
+ yacc\
+ 8a\
+ 8c\
+ 8l\
+ va\
+ vc\
+ vl\
+ mk\
+ ksize\
+ kstrip\
+ md5sum\
+ mkext\
+ ndate\
+
+#
+# Utils we build on Nt, for build environment compatibility.
+#
+NTONLY=\
+ cp\
+ echo\
+ format\
+ mkdir\
+ mv\
+ ntsrv\
+ rcsh\
+ rm\
+ sed\
+ test\
+ tr\
+
+all:QV: all-$TARGMODEL
+clean:QV: clean-$TARGMODEL
+install:QV: install-$TARGMODEL
+installall:QV: installall-$TARGMODEL
+nuke:QV: nuke-$TARGMODEL
+
+%-Plan9:QV:
+ for (j in $ALWAYS)
+ {
+ test -d $j && {
+ echo '@{cd' $j '; mk $MKFLAGS $stem}'
+ @{cd $j; mk $MKFLAGS $stem }
+ } || test ! -e $j
+ }
+
+%-Posix:QV:
+ for j in $ALWAYS $NOTPLAN9
+ do
+ test -d $j || continue
+ echo "(cd $j; mk $MKFLAGS $stem)"
+ (cd $j; mk $MKFLAGS $stem)
+ done
+
+%-Nt:QV:
+ for (j in $ALWAYS $NTONLY $NOTPLAN9)
+ {
+ test -d $j && {
+ echo.exe '@{cd' $j '; mk $MKFLAGS $stem}'
+ @{cd $j; mk $MKFLAGS $stem }
+ } || test ! -e $j
+ }
diff --git a/utils/mkppcimage/mkfile b/utils/mkppcimage/mkfile
new file mode 100644
index 00000000..b0a95dff
--- /dev/null
+++ b/utils/mkppcimage/mkfile
@@ -0,0 +1,18 @@
+<../../mkconfig
+
+TARG=mkppcimage
+
+OFILES= mkppcimage.$O\
+
+HFILES=\
+ a.out.h\
+ bio.h\
+ mach.h\
+
+LIBS=mach bio 9 # order matters.
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/mkppcimage/mkppcimage.c b/utils/mkppcimage/mkppcimage.c
new file mode 100644
index 00000000..4dc243e3
--- /dev/null
+++ b/utils/mkppcimage/mkppcimage.c
@@ -0,0 +1,261 @@
+/*
+ * generate the special header needed by DENX's ppcboot
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+/*
+ * the following values are all determined by PPCBOOT
+ */
+enum {
+ /* OS code */
+ IH_OS_NCR = 12, /* we'll use this for the time being; there isn't a general purpose one */
+
+ /* CPU code */
+ IH_CPU_ARM = 2,
+ IH_CPU_PPC = 7,
+
+ /* image type */
+ IH_TYPE_KERNEL = 2, /* OS kernel */
+
+ /* compression type */
+ IH_COMP_NONE = 0, /* none: if i need one, i'll use sqz internally, much faster */
+
+ IH_MAGIC = 0x27051956, /* Image Magic Number */
+
+ IH_NMLEN = 32 /* image name length */
+};
+
+typedef struct Imagehdr Imagehdr;
+struct Imagehdr
+{
+ ulong magic; /* image header magic number */
+ ulong hcrc; /* image header crc */
+ ulong time; /* image creation timestamp */
+ ulong size; /* image data size */
+ ulong load; /* data load address */
+ ulong entry; /* entry point address */
+ ulong dcrc; /* image data crc */
+ uchar os; /* operating system */
+ uchar arch; /* cpu type */
+ uchar type; /* image type */
+ uchar comp; /* compression type */
+ char name[IH_NMLEN]; /* image name */
+};
+
+
+static Imagehdr ih;
+static char *fname;
+
+static ulong crc32(ulong, uchar*, unsigned int);
+static long Read(int, void*, long);
+static void Write(int, void*, long);
+
+/*
+ * data is big endian
+ */
+static ulong
+swal(ulong l)
+{
+ return beswal(l);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: mkppcimage [-l loadaddr] q.out ppcboot.out\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, ofd;
+ long len;
+ uchar *data;
+ ulong load, entry;
+ Exec ex;
+ int arch;
+
+ load = ~0;
+ entry = ~0;
+ ARGBEGIN{
+ case 'l':
+ load = strtoul(EARGF(usage()), nil, 0);
+ entry = load + sizeof(Exec);
+ break;
+ }ARGEND
+ if(*argv == nil || argv[1] == nil)
+ usage();
+ fname = *argv;
+ fd = open(*argv, OREAD);
+ if(fd < 0){
+ fprint(2, "mkppcimage: can't open %s: %r\n", *argv);
+ exits("image");
+ }
+ Read(fd, &ex, sizeof(Exec));
+ switch(beswal(ex.magic)){
+ case Q_MAGIC: /* powerpc */
+ arch = IH_CPU_PPC;
+ break;
+ case E_MAGIC: /* arm */
+ arch = IH_CPU_ARM;
+ break;
+ default:
+ arch = 0;
+ fprint(2, "mkppcboot: unknown magic: %8.8lux\n", beswal(ex.magic));
+ exits("bad magic");
+ }
+ len = beswal(ex.text);
+ len += beswal(ex.data);
+ if(load == ~0){
+ entry = beswal(ex.entry);
+ entry &= ~0xFF000000; /* physical address */
+ load = entry - sizeof(Exec);
+ }
+ data = malloc(len+sizeof(Exec));
+ if(data == nil){
+ fprint(2, "mkppcimage: can't allocate data: %r\n");
+ exits("mem");
+ }
+ memmove(data, &ex, sizeof(Exec));
+ Read(fd, data+sizeof(Exec), len);
+ len += sizeof(Exec);
+ ih.magic = swal(IH_MAGIC);
+ ih.hcrc = 0;
+ ih.time = swal(time(0));
+ ih.size = swal(len);
+ ih.load = swal(load);
+ ih.entry = swal(entry);
+ ih.dcrc = swal(crc32(0, data, len));
+ ih.os = IH_OS_NCR; /* why not */
+ ih.arch = arch;
+ ih.type = IH_TYPE_KERNEL;
+ ih.comp = IH_COMP_NONE;
+ strcpy(ih.name, "Himmel!");
+ ih.hcrc = swal(crc32(0, (uchar*)&ih, sizeof(ih)));
+ ofd = create(argv[1], OWRITE, 0666);
+ if(ofd < 0){
+ fprint(2, "mkppcimage: can't create %s: %r\n", argv[1]);
+ exits("image");
+ }
+ Write(ofd, &ih, sizeof(ih));
+ Write(ofd, data, len);
+ exits(nil);
+}
+
+static long
+Read(int fd, void *buf, long nb)
+{
+ long n;
+
+ n = readn(fd, buf, nb);
+ if(n < 0){
+ fprint(2, "mkppcimage: %s: read error: %r\n", fname);
+ exits("read");
+ }
+ if(n < nb){
+ fprint(2, "mkppcimage: %s: unexpected end-of-file\n", fname);
+ exits("read");
+ }
+ return n;
+}
+
+static void
+Write(int fd, void *buf, long nb)
+{
+ if(write(fd, buf, nb) != nb){
+ fprint(2, "mkppcboot: write error: %r\n");
+ exits("write err");
+ }
+}
+
+/*
+ * The remainder of this file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+static ulong crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+static ulong
+crc32(ulong crc, uchar *buf, unsigned len)
+{
+ crc = ~crc;
+ while (len >= 8) {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+ return ~crc;
+}
diff --git a/utils/ms2/mkfile b/utils/ms2/mkfile
new file mode 100644
index 00000000..7850753e
--- /dev/null
+++ b/utils/ms2/mkfile
@@ -0,0 +1,16 @@
+<../../mkconfig
+CFLAGS=$CFLAGS -I../include
+
+TARG=ms2
+
+OFILES= ms2.$O\
+
+HFILES= \
+ $ROOT/include/bio.h\
+ ../include/mach.h\
+
+LIBS=mach bio 9 #order matters
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/ms2/ms2.c b/utils/ms2/ms2.c
new file mode 100644
index 00000000..e36307db
--- /dev/null
+++ b/utils/ms2/ms2.c
@@ -0,0 +1,186 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+void record(uchar*, int);
+void usage(void);
+void dosegment(long, int);
+void trailer(ulong);
+void header(void);
+
+enum
+{
+ Recordsize = 32
+};
+
+int dsegonly;
+int supressend;
+int binary;
+ulong addr;
+ulong psize = 4096;
+ulong startaddr = 0x030000;
+Biobuf bout;
+Biobuf bio;
+
+void
+main(int argc, char **argv)
+{
+ Dir *dir;
+ Fhdr f;
+ int fd;
+
+ ARGBEGIN{
+ case 'd':
+ dsegonly++;
+ break;
+ case 's':
+ supressend++;
+ break;
+ case 'a':
+ case 'T':
+ addr = strtoul(ARGF(), 0, 0);
+ break;
+ case 'p':
+ case 'R':
+ psize = strtoul(ARGF(), 0, 0);
+ break;
+ case 'b':
+ binary++;
+ break;
+ case 'S':
+ startaddr = strtoul(ARGF(), 0, 0);
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+
+ Binit(&bout, 1, OWRITE);
+
+ fd = open(argv[0], OREAD);
+ if(fd < 0) {
+ fprint(2, "ms2: open %s: %r\n", argv[0]);
+ exits("open");
+ }
+
+ if(binary) {
+ if((dir = dirfstat(fd)) == nil) {
+ fprint(2, "ms2: stat failed %r");
+ exits("dirfstat");
+ }
+ Binit(&bio, fd, OREAD);
+ header();
+ dosegment(0, dir->length);
+ if(supressend == 0)
+ trailer(startaddr);
+ Bterm(&bout);
+ Bterm(&bio);
+ free(dir);
+ exits(0);
+ }
+
+ if(crackhdr(fd, &f) == 0){
+ fprint(2, "ms2: bad magic: %r\n");
+ exits("magic");
+ }
+ seek(fd, 0, 0);
+
+ Binit(&bio, fd, OREAD);
+
+ header();
+ if(dsegonly)
+ dosegment(f.datoff, f.datsz);
+ else {
+ dosegment(f.txtoff, f.txtsz);
+ addr = (addr+(psize-1))&~(psize-1);
+ dosegment(f.datoff, f.datsz);
+ }
+
+ if(supressend == 0)
+ trailer(startaddr);
+
+ Bterm(&bout);
+ Bterm(&bio);
+ exits(0);
+}
+
+void
+dosegment(long foff, int len)
+{
+ int l, n;
+ uchar buf[2*Recordsize];
+
+ Bseek(&bio, foff, 0);
+ for(;;) {
+ l = len;
+ if(l > Recordsize)
+ l = Recordsize;
+ n = Bread(&bio, buf, l);
+ if(n == 0)
+ break;
+ if(n < 0) {
+ fprint(2, "ms2: read error: %r\n");
+ exits("read");
+ }
+ record(buf, l);
+ len -= l;
+ }
+}
+
+void
+record(uchar *s, int l)
+{
+ int i;
+ ulong cksum;
+
+ if(addr & (0xFF<<24)){
+ Bprint(&bout, "S3%.2X%.8X", l+5, addr);
+ cksum = l+5;
+ cksum += (addr>>24)&0xff;
+ }else{
+ Bprint(&bout, "S2%.2X%.6X", l+4, addr);
+ cksum = l+4;
+ }
+ cksum += addr&0xff;
+ cksum += (addr>>8)&0xff;
+ cksum += (addr>>16)&0xff;
+
+ for(i = 0; i < l; i++) {
+ cksum += *s;
+ Bprint(&bout, "%.2X", *s++);
+ }
+ Bprint(&bout, "%.2X\n", (~cksum)&0xff);
+ addr += l;
+}
+
+void
+header(void)
+{
+ Bprint(&bout, "S0030000FC\n");
+}
+
+void
+trailer(ulong a)
+{
+ ulong cksum;
+
+ cksum = 0;
+ if(a & (0xFF<<24)){
+ Bprint(&bout, "S7%.8X", a);
+ cksum += (a>>24)&0xff;
+ }else
+ Bprint(&bout, "S9%.6X", a);
+ cksum += a&0xff;
+ cksum += (a>>8)&0xff;
+ cksum += (a>>16)&0xff;
+ Bprint(&bout, "%.2X\n", (~cksum)&0xff);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: ms2 [-dsb] [-T address] [-R pagesize] [-S startaddress] ?.out\n");
+ exits("usage");
+}
diff --git a/utils/mv/mkfile b/utils/mv/mkfile
new file mode 100644
index 00000000..c04450e6
--- /dev/null
+++ b/utils/mv/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=mv
+
+OFILES= mv.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/mv/mv.c b/utils/mv/mv.c
new file mode 100644
index 00000000..f8a9893f
--- /dev/null
+++ b/utils/mv/mv.c
@@ -0,0 +1,210 @@
+#include <lib9.h>
+
+void split(char *, char **, char **);
+int samefile(char *, char *);
+int mv(char *from, char *todir, char *toelem);
+int copy1(int fdf, int fdt, char *from, char *to);
+void hardremove(char *);
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ int failed;
+ Dir *dirto, *dirfrom;
+ char *todir, *toelem;
+
+ if(argc<3){
+ fprint(2, "usage: mv fromfile tofile\n");
+ fprint(2, " mv fromfile ... todir\n");
+ exits("bad usage");
+ }
+ if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){
+ if(argc == 3
+ && (dirfrom = dirstat(argv[1])) !=nil
+ && (dirfrom->mode & DMDIR))
+ split(argv[argc-1], &todir, &toelem);
+ else{
+ todir = argv[argc-1];
+ toelem = 0; /* toelem will be fromelem */
+ }
+ }else
+ split(argv[argc-1], &todir, &toelem);
+ if(argc>3 && toelem != 0){
+ fprint(2, "mv: %s not a directory\n", argv[argc-1]);
+ exits("bad usage");
+ }
+ failed = 0;
+ for(i=1; i < argc-1; i++)
+ if (mv(argv[i], todir, toelem) < 0)
+ failed++;
+ if(failed)
+ exits("failure");
+ exits(0);
+}
+
+int
+mv(char *from, char *todir, char *toelem)
+{
+ Dir *dirb, *dirt, null;
+ char toname[4096], fromname[4096];
+ int fdf, fdt, i, j;
+ int stat;
+ char *fromdir, *fromelem;
+
+ dirb = dirstat(from);
+ if(dirb == nil){
+ fprint(2, "mv: can't stat %s: %r\n", from);
+ return -1;
+ }
+ strncpy(fromname, from, sizeof fromname);
+ split(from, &fromdir, &fromelem);
+ if(toelem == 0)
+ toelem = fromelem;
+ i = strlen(toelem);
+ if(i==0){
+ fprint(2, "mv: null last name element moving %s\n", fromname);
+ return -1;
+ }
+ j = strlen(todir);
+ if(i + j + 2 > sizeof toname){
+ fprint(2, "mv: path too big (max %d): %s/%s\n", sizeof toname, todir, toelem);
+ return -1;
+ }
+ memmove(toname, todir, j);
+ toname[j] = '/';
+ memmove(toname+j+1, toelem, i);
+ toname[i+j+1] = 0;
+ if(samefile(fromdir, todir)){
+ if(samefile(fromname, toname)){
+ fprint(2, "mv: %s and %s are the same\n", fromname, toname);
+ return -1;
+ }
+ dirt = dirstat(toname);
+ if(dirt != nil){
+ free(dirt);
+ hardremove(toname);
+ }
+ nulldir(&null);
+ null.name = toelem;
+ if(dirwstat(fromname, &null) >= 0)
+ return 0;
+ if(dirb->mode & DMDIR){
+ fprint(2, "mv: can't rename directory %s: %r\n", fromname);
+ return -1;
+ }
+ }
+ /*
+ * Renaming won't work --- must copy
+ */
+ if(dirb->mode & DMDIR){
+ fprint(2, "mv: %s is a directory, not copied to %s\n", fromname, toname);
+ return -1;
+ }
+ fdf = open(fromname, OREAD);
+ if(fdf < 0){
+ fprint(2, "mv: can't open %s: %r\n", fromname);
+ return -1;
+ }
+ dirt = dirstat(toname);
+ if(dirt != nil && (dirt->mode & DMAPPEND))
+ hardremove(toname); /* because create() won't truncate file */
+ free(dirt);
+ fdt = create(toname, OWRITE, dirb->mode);
+ if(fdt < 0){
+ fprint(2, "mv: can't create %s: %r\n", toname);
+ close(fdf);
+ return -1;
+ }
+ if ((stat = copy1(fdf, fdt, fromname, toname)) != -1) {
+ nulldir(&null);
+ null.mtime = dirb->mtime;
+ null.mode = dirb->mode;
+ dirfwstat(fdt, &null); /* ignore errors; e.g. user none always fails */
+ close(fdf);
+ close(fdt);
+ if (remove(fromname) < 0) {
+ fprint(2, "mv: can't remove %s: %r\n", fromname);
+ return -1;
+ }
+ }
+ close(fdf);
+ close(fdt);
+ return stat;
+}
+
+int
+copy1(int fdf, int fdt, char *from, char *to)
+{
+ char buf[8192];
+ long n, n1;
+
+ for(;;) {
+ n = read(fdf, buf, sizeof buf);
+ if(n >= 0) {
+ if(n == 0)
+ break;
+ n1 = write(fdt, buf, n);
+ if(n1 != n) {
+ fprint(2, "mv: error writing %s: %r\n", to);
+ return -1;
+ }
+ }
+ }
+ if(n < 0) {
+ fprint(2, "mv: error reading %s: %r\n", from);
+ return -1;
+ }
+ return 0;
+}
+
+void
+split(char *name, char **pdir, char **pelem)
+{
+ char *s;
+
+ s = utfrrune(name, '/');
+ if(s){
+ *s = 0;
+ *pelem = s+1;
+ *pdir = name;
+ }else if(strcmp(name, "..") == 0){
+ *pdir = "..";
+ *pelem = ".";
+ }else{
+ *pdir = ".";
+ *pelem = name;
+ }
+}
+
+int
+samefile(char *a, char *b)
+{
+ Dir *da, *db;
+ int ret;
+
+ if(strcmp(a, b) == 0)
+ return 1;
+ da = dirstat(a);
+ db = dirstat(b);
+ ret = (da !=nil ) &&
+ (db != nil) &&
+ (da->qid.type==db->qid.type) &&
+ (da->qid.path==db->qid.path) &&
+ (da->qid.vers==db->qid.vers) &&
+ (da->dev==db->dev) &&
+ da->type==db->type;
+ free(da);
+ free(db);
+ return ret;
+}
+
+void
+hardremove(char *a)
+{
+ if(remove(a) == -1){
+ fprint(2, "mv: can't remove %s: %r\n", a);
+ exits("mv");
+ }
+ do; while(remove(a) != -1);
+}
diff --git a/utils/na/mkfile b/utils/na/mkfile
new file mode 100644
index 00000000..d28ee1c5
--- /dev/null
+++ b/utils/na/mkfile
@@ -0,0 +1,18 @@
+<../../mkconfig
+
+TARG=na
+HFILES=\
+ na.h\
+
+OFILES=\
+ y.tab.$O\
+
+YFILES=na.y\
+
+LIBS=9
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/na/na.h b/utils/na/na.h
new file mode 100755
index 00000000..ef8bc3cd
--- /dev/null
+++ b/utils/na/na.h
@@ -0,0 +1,13 @@
+#ifndef NA_H
+#define NA_H
+
+struct na_patch {
+ unsigned lwoff;
+ unsigned char type;
+};
+
+int na_fixup(unsigned long *script, unsigned long pa_script, unsigned long pa_reg,
+ struct na_patch *patch, int patches,
+ int (*externval)(int x, unsigned long *v));
+
+#endif
diff --git a/utils/na/na.man b/utils/na/na.man
new file mode 100644
index 00000000..eb0a111e
--- /dev/null
+++ b/utils/na/na.man
@@ -0,0 +1,33 @@
+.TH NA 8
+.SH NAME
+na \- assembler for the Symbios Logic PCI-SCSI I/O Processors
+.SH SYNOPSIS
+.B aux/na file
+.SH DESCRIPTION
+The SYM53C8XX series of PCI-SCSI I/O Processors contain
+loadable microcode to control their operation.
+The microcode is written in a language called SCRIPTS.
+.I Aux/na
+is an assembler for the SCRIPTS programming language.
+It assembles SCRIPTS code in
+.I file
+into an array of assembled SCRIPTS
+instructions, patches, defines and enums
+that can be included in a C device driver.
+.SH SOURCE
+.TF /sys/src/cmd/aux/na
+.TP
+.B /sys/src/cmd/aux/na
+.SH "SEE ALSO"
+Symbios Logic,
+``PCI-SCSI I/O Processors Programming Guide Version 2.1''
+.br
+.TF /sys/src/9/*/sd53c8xx.c
+.TP
+.B /sys/src/9/*/sd53c8xx.n
+SCRIPTS source code
+.TP
+.B /sys/src/9/*/sd53c8xx.c
+driver for the SYM53C8XX series of PCI-SCSI controllers
+.SH AUTHOR
+Nigel Roles (ngr@9fs.org)
diff --git a/utils/na/na.y b/utils/na/na.y
new file mode 100755
index 00000000..4021cb43
--- /dev/null
+++ b/utils/na/na.y
@@ -0,0 +1,1231 @@
+/* NCR53c8xx assembler */
+%{
+#include <lib9.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "na.h"
+
+#define COND_WAIT (1L << 16)
+#define COND_TRUE (1L << 19)
+#define COND_INTFLY (1L << 20)
+#define COND_CARRY (1L << 21)
+#define COND_REL (1L << 23)
+#define COND_PHASE (1L << 17)
+#define COND_DATA (1L << 18)
+
+#define IO_REL (1L << 26)
+
+#define MOVE_MODE (1L << 27)
+
+int yylex(void);
+int yyparse(void);
+void assemble(void);
+void yyerror(char *, ...);
+void yywarn(char *, ...);
+void p2error(int line, char *);
+
+struct addr {
+ int type; /* 0 - direct, 1 - indirect 2 - table indirect */
+ unsigned long offset;
+};
+
+typedef enum Type { Const, Addr, Table, Extern, Reg, Unknown, Error } Type;
+
+struct sym {
+ char *name;
+ int set;
+ Type t;
+ long value;
+ struct sym *next;
+};
+
+struct sym *findsym(char *name);
+struct sym *symlist;
+
+void newsym(struct sym *s, Type t, long v);
+
+struct binary {
+ char len;
+ unsigned long data[3];
+ unsigned char patch[3];
+};
+
+#define MAXCPPOPTS 30
+#define MAX_PATCHES 1000
+struct na_patch patch[MAX_PATCHES];
+int patches;
+
+struct binary out;
+
+struct expval {
+ Type t;
+ long value;
+};
+
+struct expval eval(struct expval a, struct expval b, char op);
+
+int patchtype(Type t);
+void fixup(void);
+
+unsigned dot;
+unsigned externs;
+int errors, warnings;
+struct sym *externp[100];
+
+void regmove(unsigned char src_reg, unsigned char op,
+ unsigned char dst_reg, struct expval *imm);
+
+void preprocess(char *in, FILE *out);
+
+int mk24bitssigned(long *l);
+long mkreladdr(long value, int len);
+long chkreladdr(int d, struct expval *e, int len, long relrv);
+int pass2;
+FILE *in_f;
+
+int yyline = 0;
+char yyfilename[200];
+char line[500];
+char *cppopts[MAXCPPOPTS];
+int ncppopts;
+int wflag;
+%}
+
+%union {
+ long n;
+ struct sym *s;
+ struct expval e;
+}
+
+%token NUM MOVE WHEN SYMBOL SELECT WAIT DISCONNECT RESELECT SET CLEAR
+%token DATA_OUT DATA_IN COMMAND STATUS RESERVED_OUT RESERVED_IN MESSAGE_OUT
+%token MESSAGE_IN WITH ATN FAIL CARRY TARGET ACK COMMENT TO
+%token SCNTL0 SCNTL1 SCNTL2 SCNTL3 SCID SXFER SDID GPREG
+%token SFBR SOCL SSID SBCL DSTAT SSTAT0 SSTAT1 SSTAT2
+%token ISTAT CTEST0 CTEST1 CTEST2 CTEST3 TEMP DFIFO CTEST4 CTEST5 CTEST6
+%token DBC DCMD DNAD DSP DSPS DMODE DIEN DWT DCNTL ADDER
+%token SIEN0 SIEN1 SIST0 SIST1 SLPAR MACNTL GPCNTL STIME0 STIME1 RESPID
+%token STEST0 STEST1 STEST2 STEST3 SIDL SODL SBDL
+%token SHL SHR AND OR XOR ADD ADDC
+%token JUMP CALL RETURN INT INTFLY NOT ABSOLUTE MASK IF REL PTR
+%token TABLE FROM MEMORY NOP EXTERN
+%token SCRATCHA0 SCRATCHA1 SCRATCHA2 SCRATCHA3
+%token SCRATCHB0 SCRATCHB1 SCRATCHB2 SCRATCHB3
+%token SCRATCHC0 SCRATCHC1 SCRATCHC2 SCRATCHC3
+%token DSA0 DSA1 DSA2 DSA3
+%token DEFW
+
+%left '-' '+'
+%left '*' '/'
+%left NEG /* negation--unary minus */
+%right '^' /* exponentiation */
+%type <n> NUM phase .atn set_list set_bit regA reg
+%type <n> set_cmd .cond condsfbr condphase
+%type <n> jump_or_call .ptr
+%type <s> SYMBOL
+%type <e> exp byteexp regexp
+
+/* Grammar follows */
+%%
+input: /* empty string */
+ | input line
+;
+
+line: .label .opcode .comment '\n'
+ {
+ if (pass2) {
+ int x;
+ for (x = 0; x < out.len; x++) {
+ printf("/* %.4x */ 0x%.8lxL,",
+ dot, out.data[x]);
+ if (x == 0) {
+ printf(" /*\t");
+ fwrite(line,
+ strlen(line) - 1, 1, stdout);
+ printf(" */");
+ }
+ printf("\n");
+ if (out.patch[x]) {
+ patch[patches].lwoff = dot / 4;
+ patch[patches].type = out.patch[x];
+ patches++;
+ }
+ dot += 4;
+ }
+ }
+ else
+ dot += 4 * out.len;
+ }
+ | ABSOLUTE SYMBOL '=' exp .comment '\n'
+ {
+ setsym($2, $4.t, $4.value);
+ if (pass2) {
+ printf("\t\t\t/*\t");
+ fwrite(line, strlen(line) - 1, 1, stdout);
+ printf(" */\n");
+ }
+ }
+ | SYMBOL '=' exp .comment '\n'
+ {
+ setsym($1, $3.t, $3.value);
+ if (pass2) {
+ printf("\t\t\t/*\t");
+ fwrite(line, strlen(line) - 1, 1, stdout);
+ printf(" */\n");
+ }
+ }
+ | EXTERN SYMBOL {
+ if (pass2) {
+ printf("\t\t\t/*\t");
+ fwrite(line, strlen(line) - 1, 1, stdout);
+ printf(" */\n");
+ }
+ else {
+ if (!pass2)
+ externp[externs] = $2;
+ setsym($2, Extern, externs++);
+ }
+ }
+ ;
+
+.comment: COMMENT
+ | /* nothing */
+ ;
+
+.label: SYMBOL ':' {
+ if ($1->t != Unknown)
+ {
+ if (!pass2)
+ yyerror("multiply defined symbol");
+ }
+ else {
+ $1->t = Addr;
+ $1->value = dot;
+ }
+ }
+ | /* nothing */
+ ;
+
+set_cmd: SET { $$ = 3; }
+ | CLEAR { $$ = 4; }
+ ;
+
+set_bit: CARRY { $$ = 0x400; }
+ | TARGET { $$ = 0x200; }
+ | ACK { $$ = 0x40; }
+ | ATN { $$ = 0x8; }
+ ;
+
+set_list: set_list ',' set_bit { $$ = $1 | $3; }
+ | set_list AND set_bit { $$ = $1 | $3; }
+ | set_bit { $$ = $1; }
+ ;
+
+opcode: set_cmd set_list {
+ out.len = 2;
+ out.data[0] = (1L << 30) | ((long)$1 << 27) | $2;
+ out.data[1] = 0;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | DISCONNECT
+ {
+ out.len = 2;
+ out.data[0] = 0x48020000L;
+ out.data[1] = 0;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | INT exp .cond {
+ out.len = 2;
+ out.data[0] = $3 | 0x98000000L;
+ out.data[1] = $2.value;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | INTFLY exp .cond {
+ out.len = 2;
+ out.data[0] = $3 | 0x98000000L | COND_INTFLY;
+ out.data[1] = $2.value;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | jump_or_call exp .cond {
+ out.len = 2;
+ out.data[0] = $1 | $3 | chkreladdr(1, &$2, 2, COND_REL);
+ out.patch[0] = 0;
+ }
+ | jump_or_call REL '(' exp ')' .cond {
+ out.len = 2;
+ out.data[0] = $1 | $6 | COND_REL;
+ out.data[1] = mkreladdr($4.value, 2);
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | MOVE exp ',' .ptr regexp ',' with_or_when phase {
+ out.len = 2;
+ out.data[0] = ($8 << 24) | $2.value | ($4 << 29) | MOVE_MODE;
+ out.data[1] = $5.value;
+ out.patch[0] = 0;
+ out.patch[1] = patchtype($5.t);
+ }
+ | MOVE FROM exp ',' with_or_when phase {
+ out.len = 2;
+ out.data[0] = ($6 << 24) | (1L << 28) | MOVE_MODE;
+ out.data[1] = $3.value;
+ out.patch[0] = 0;
+ out.patch[1] = patchtype($3.t);
+ }
+ | MOVE MEMORY exp ',' regexp ',' regexp {
+ out.len = 3;
+ out.data[0] = 0xc0000000L | $3.value;
+ out.data[1] = $5.value;
+ out.data[2] = $7.value;
+ out.patch[0] = 0;
+ out.patch[1] = patchtype($5.t);
+ out.patch[2] = patchtype($7.t);
+ }
+ | MOVE regA TO regA { regmove($2, 2, $4, 0); } /* do reg to sfbr moves using or 0 */
+ | MOVE exp TO regA { regmove($4, 0, $4, &$2); }
+ | MOVE regA '|' exp TO regA { regmove($2, 2, $6, &$4); }
+ | MOVE regA '&' exp TO regA { regmove($2, 4, $6, &$4); }
+ | MOVE regA '+' exp TO regA { regmove($2, 6, $6, &$4); }
+ | MOVE regA '-' exp TO regA { regmove($2, 6, $6, &$4); }
+ | MOVE regA '+' exp TO regA WITH CARRY {
+ regmove($2, 7, $6, &$4);
+ }
+ | MOVE regA '-' exp TO regA WITH CARRY {
+ $4.value = -$4.value;
+ regmove($2, 7, $6, &$4);
+ }
+ | MOVE regA SHL TO regA { regmove($2, 1, $5, 0); }
+ | MOVE regA SHR TO regA { regmove($2, 5, $5, 0); }
+ | MOVE regA XOR exp TO regA { regmove($2, 3, $6, &$4); }
+ | NOP {
+ out.len = 2;
+ out.data[0] = 0x80000000L;
+ out.data[1] = 0;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | RESELECT exp ',' exp {
+ out.len = 2;
+ out.data[0] = 0x40000000L | ((long)$2.value << 16) | (1L << 9) | chkreladdr(1, &$4, 2, IO_REL);
+ out.patch[0] = 0;
+ }
+ | RESELECT exp ',' REL '(' exp ')' {
+ out.len = 2;
+ out.data[0] = 0x40000000L | IO_REL
+ | ((long)$2.value << 16) | (1L << 9);
+ out.data[1] = mkreladdr($6.value, 2);
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | RESELECT FROM exp ',' exp {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 25) | $3.value | chkreladdr(1, &$5, 2, IO_REL);
+ out.patch[0] = 5;
+ }
+ | RESELECT FROM exp ',' REL '(' exp ')' {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 25) | IO_REL | $3.value;
+ out.patch[0] = 5;
+ out.data[1] = mkreladdr($7.value, 2);
+ out.patch[1] = 0;
+ }
+ | RETURN .cond {
+
+ out.len = 2;
+ out.data[0] = 0x90000000L | $2;
+ out.data[1] = 0;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | SELECT .atn exp ',' exp {
+ out.len = 2;
+ out.data[0] =
+ 0x40000000L | ((long)$3.value << 16) | (1L << 9) | $2 | chkreladdr(1, &$5, 2, IO_REL);
+ out.patch[0] = 0;
+ }
+ | SELECT .atn exp ',' REL '(' exp ')' {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 26)
+ | ((long)$3.value << 16) | (1L << 9) | $2;
+ out.data[1] = mkreladdr($7.value, 2);
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | SELECT .atn FROM exp ',' exp {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 25) | $4.value | $2 | chkreladdr(1, &$6, 2, IO_REL);
+ out.patch[0] = 5;
+ }
+ | SELECT .atn FROM exp ',' REL '(' exp ')' {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 25) | IO_REL | $4.value | $2;
+ out.patch[0] = 5;
+ out.data[1] = mkreladdr($8.value, 2);
+ out.patch[1] = 0;
+ }
+ | WAIT DISCONNECT {
+ out.len = 2;
+ out.data[0] = 0x48000000L;
+ out.data[1] = 0;
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | WAIT RESELECT exp {
+ out.len = 2;
+ out.data[0] = 0x50000000L | chkreladdr(1, &$3, 2, IO_REL);
+ out.patch[0] = 0;
+ }
+ | WAIT RESELECT REL '(' exp ')' {
+ out.len = 2;
+ out.data[0] = 0x50000000L | (1L << 26);
+ out.data[1] = mkreladdr($5.value, 2);
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | WAIT SELECT exp {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 9) | chkreladdr(1, &$3, 2, IO_REL);
+ out.patch[0] = 0;
+ }
+ | WAIT SELECT REL '(' exp ')' {
+ out.len = 2;
+ out.data[0] = 0x40000000L | (1L << 26) | (1L << 9);
+ out.data[1] = mkreladdr($5.value, 2);
+ out.patch[0] = out.patch[1] = 0;
+ }
+ | DEFW exp {
+ out.len = 1;
+ out.data[0] = $2.value;
+ out.patch[0] = patchtype($2.t);
+ }
+ ;
+
+.ptr: PTR { $$ = 1; }
+ | { $$ = 0; }
+ ;
+
+with_or_when: WITH
+ | WHEN
+ ;
+
+jump_or_call: JUMP { $$ = 0x80000000L; }
+ | CALL { $$ = 0x88000000L; }
+ ;
+
+condsfbr: byteexp { $$ = $1.value | COND_DATA; }
+ | byteexp AND MASK byteexp { $$ = ($4.value << 8) | $1.value | COND_DATA; }
+ ;
+
+condphase: phase { $$ = ($1 << 24) | COND_PHASE; }
+
+.cond: ',' IF ATN { $$ = COND_TRUE; }
+ | ',' IF condphase { $$ = $3 | COND_TRUE; }
+ | ',' IF CARRY { $$ = COND_CARRY | COND_TRUE; }
+ | ',' IF condsfbr { $$ = $3 | COND_TRUE; }
+ | ',' IF ATN AND condsfbr { $$ = $5 | COND_TRUE; }
+ | ',' IF condphase AND condsfbr { $$ = $3 | $5 | COND_TRUE; }
+ | ',' WHEN condphase { $$ = $3 | COND_WAIT | COND_TRUE; }
+ | ',' WHEN CARRY { $$ = COND_CARRY | COND_WAIT | COND_TRUE; }
+ | ',' WHEN condsfbr { $$ = $3 | COND_WAIT | COND_TRUE; }
+ | ',' WHEN condphase AND condsfbr { $$ = $3 | $5 | COND_WAIT | COND_TRUE; }
+ | ',' IF NOT ATN { $$ = 0; }
+ | ',' IF NOT condphase { $$ = $4; }
+ | ',' IF NOT CARRY { $$ = COND_CARRY; }
+ | ',' IF NOT condsfbr { $$ = $4; }
+ | ',' IF NOT ATN OR condsfbr { $$ = $6; }
+ | ',' IF NOT condphase OR condsfbr { $$ = $4 | $6; }
+ | ',' WHEN NOT condphase { $$ = $4 | COND_WAIT; }
+ | ',' WHEN NOT CARRY { $$ = COND_CARRY | COND_WAIT; }
+ | ',' WHEN NOT condsfbr { $$ = $4 | COND_WAIT; }
+ | ',' WHEN NOT condphase OR condsfbr { $$ = $4 | $6 | COND_WAIT; }
+ | { $$ = COND_TRUE; }
+ ;
+
+.opcode: opcode
+ | { out.len = 0; }
+ ;
+
+regA: reg
+ | SFBR { $$ = 8; }
+ ;
+
+reg: SCNTL0 { $$ = 0; }
+ | SCNTL1 { $$ = 1; }
+ | SCNTL2 { $$ = 2; }
+ | SCNTL3 { $$ = 3; }
+ | SCID { $$ = 4; }
+ | SXFER { $$ = 5; }
+ | SDID { $$ = 6; }
+ | GPREG { $$ = 7; }
+ | SOCL { $$ = 9; }
+ | SSID { $$ = 0xa; }
+ | SBCL { $$ = 0xb; }
+ | DSTAT { $$ = 0xc; }
+ | SSTAT0 { $$ = 0xd; }
+ | SSTAT1 { $$ = 0xe; }
+ | SSTAT2 { $$ = 0xf; }
+ | DSA0 { $$ = 0x10; }
+ | DSA1 { $$ = 0x11; }
+ | DSA2 { $$ = 0x12; }
+ | DSA3 { $$ = 0x13; }
+ | ISTAT { $$ = 0x14; }
+ | CTEST0 { $$ = 0x18; }
+ | CTEST1 { $$ = 0x19; }
+ | CTEST2 { $$ = 0x1a; }
+ | CTEST3 { $$ = 0x1b; }
+ | TEMP { $$ = 0x1c; }
+ | DFIFO { $$ = 0x20; }
+ | CTEST4 { $$ = 0x21; }
+ | CTEST5 { $$ = 0x22; }
+ | CTEST6 { $$ = 0x23; }
+ | DBC { $$ = 0x24; }
+ | DCMD { $$ = 0x27; }
+ | DNAD { $$ = 0x28; }
+ | DSP { $$ = 0x2c; }
+ | DSPS { $$ = 0x30; }
+ | SCRATCHA0 { $$ = 0x34; }
+ | SCRATCHA1 { $$ = 0x35; }
+ | SCRATCHA2 { $$ = 0x36; }
+ | SCRATCHA3 { $$ = 0x37; }
+ | DMODE { $$ = 0x38; }
+ | DIEN { $$ = 0x39; }
+ | DWT { $$ = 0x3a; }
+ | DCNTL { $$ = 0x3b; }
+ | ADDER { $$ = 0x3c; }
+ | SIEN0 { $$ = 0x40; }
+ | SIEN1 { $$ = 0x41; }
+ | SIST0 { $$ = 0x42; }
+ | SIST1 { $$ = 0x43; }
+ | SLPAR { $$ = 0x44; }
+ | MACNTL { $$ = 0x46; }
+ | GPCNTL { $$ = 0x47; }
+ | STIME0 { $$ = 0x48; }
+ | STIME1 { $$ = 0x49; }
+ | RESPID { $$ = 0x4a; }
+ | STEST0 { $$ = 0x4c; }
+ | STEST1 { $$ = 0x4d; }
+ | STEST2 { $$ = 0x4e; }
+ | STEST3 { $$ = 0x4f; }
+ | SIDL { $$ = 0x50; }
+ | SODL { $$ = 0x54; }
+ | SBDL { $$ = 0x58; }
+ | SCRATCHB0 { $$ = 0x5c; }
+ | SCRATCHB1 { $$ = 0x5d; }
+ | SCRATCHB2 { $$ = 0x5e; }
+ | SCRATCHB3 { $$ = 0x5f; }
+ | SCRATCHC0 { $$ = 0x60; }
+ | SCRATCHC1 { $$ = 0x61; }
+ | SCRATCHC2 { $$ = 0x62; }
+ | SCRATCHC3 { $$ = 0x63; }
+ ;
+
+.atn: ATN { $$ = (1 << 24); }
+ | /* nothing */ { $$ = 0; }
+;
+
+phase: DATA_OUT { $$ = 0; }
+ | DATA_IN { $$ = 1; }
+ | COMMAND { $$ = 2; }
+ | STATUS { $$ = 3; }
+ | RESERVED_OUT { $$ = 4; }
+ | RESERVED_IN { $$ = 5; }
+ | MESSAGE_OUT { $$ = 6; }
+ | MESSAGE_IN { $$ = 7; }
+;
+
+byteexp: exp
+ {
+ if (pass2 && ($1.value < 0 || $1.value > 255)) {
+ if (wflag)
+ yywarn("conversion causes truncation");
+ $$.value = $1.value & 0xff;
+ }
+ else
+ $$.value = $1.value;
+ }
+ ;
+
+regexp: exp
+ | regA { $$.t = Reg; $$.value = $1; }
+ ;
+
+exp: NUM { $$.t = Const; $$.value = $1; }
+ | SYMBOL {
+ $$.t = $1->t; $$.value = $1->value;
+ if (pass2 && $1->t == Unknown)
+ {
+ yyerror("Undefined symbol %s", $1->name);
+ $1->t = Error;
+ $1->value = 0;
+ $$.t = Error;
+ $$.value = 0;
+ }
+ }
+ | exp '+' exp { $$ = eval($1, $3, '+'); }
+ | exp '-' exp { $$ = eval($1, $3, '-'); }
+ | exp '*' exp { $$ = eval($1, $3, '*'); }
+ | exp '/' exp { $$ = eval($1, $3, '/'); }
+ | '-' exp %prec NEG { $$ = eval($2, $2, '_'); }
+ | '(' exp ')' { $$ = $2; }
+ | '~' exp %prec NEG { $$ = eval($2, $2, '~'); }
+ ;
+%%
+
+struct {
+ char *name;
+ int tok;
+} toktab[] =
+{
+ { "when", WHEN },
+ { "data_out", DATA_OUT },
+ { "data_in", DATA_IN },
+ { "msg_out", MESSAGE_OUT },
+ { "msg_in", MESSAGE_IN },
+ { "cmd", COMMAND },
+ { "command", COMMAND },
+ { "status", STATUS },
+ { "move", MOVE },
+ { "select", SELECT },
+ { "reselect", RESELECT },
+ { "disconnect", DISCONNECT },
+ { "wait", WAIT },
+ { "set", SET },
+ { "clear", CLEAR },
+ { "with", WITH },
+ { "atn", ATN },
+ { "fail", FAIL },
+ { "carry", CARRY },
+ { "target", TARGET },
+ { "ack", ACK },
+ { "scntl0", SCNTL0 },
+ { "scntl1", SCNTL1 },
+ { "scntl2", SCNTL2 },
+ { "scntl3", SCNTL3 },
+ { "scid", SCID },
+ { "sxfer", SXFER },
+ { "sdid", SDID },
+ { "gpreg", GPREG },
+ { "sfbr", SFBR },
+ { "socl", SOCL },
+ { "ssid", SSID },
+ { "sbcl", SBCL },
+ { "dstat", DSTAT },
+ { "sstat0", SSTAT0 },
+ { "sstat1", SSTAT1 },
+ { "sstat2", SSTAT2 },
+ { "dsa", DSA0 },
+ { "dsa0", DSA0 },
+ { "dsa1", DSA1 },
+ { "dsa2", DSA2 },
+ { "dsa3", DSA3 },
+ { "istat", ISTAT },
+ { "ctest0", CTEST0 },
+ { "ctest1", CTEST1 },
+ { "ctest2", CTEST2 },
+ { "ctest3", CTEST3 },
+ { "temp", TEMP },
+ { "dfifo", DFIFO },
+ { "ctest4", CTEST4 },
+ { "ctest5", CTEST5 },
+ { "ctest6", CTEST6 },
+ { "dbc", DBC },
+ { "dcmd", DCMD },
+ { "dnad", DNAD },
+ { "dsp", DSP },
+ { "dsps", DSPS },
+ { "scratcha", SCRATCHA0 },
+ { "scratcha0", SCRATCHA0 },
+ { "scratcha1", SCRATCHA1 },
+ { "scratcha2", SCRATCHA2 },
+ { "scratcha3", SCRATCHA3 },
+ { "dmode", DMODE },
+ { "dien", DIEN },
+ { "dwt", DWT },
+ { "dcntl", DCNTL },
+ { "adder", ADDER },
+ { "sien0", SIEN0 },
+ { "sien1", SIEN1 },
+ { "sist0", SIST0 },
+ { "sist1", SIST1 },
+ { "slpar", SLPAR },
+ { "macntl", MACNTL },
+ { "gpcntl", GPCNTL },
+ { "stime0", STIME0 },
+ { "stime1", STIME1 },
+ { "respid", RESPID },
+ { "stest0", STEST0 },
+ { "stest1", STEST1 },
+ { "stest2", STEST2 },
+ { "stest3", STEST3 },
+ { "sidl", SIDL },
+ { "sodl", SODL },
+ { "sbdl", SBDL },
+ { "scratchb", SCRATCHB0 },
+ { "scratchb0", SCRATCHB0 },
+ { "scratchb1", SCRATCHB1 },
+ { "scratchb2", SCRATCHB2 },
+ { "scratchb3", SCRATCHB3 },
+ { "scratchc", SCRATCHC0 },
+ { "scratchc0", SCRATCHC0 },
+ { "scratchc1", SCRATCHC1 },
+ { "scratchc2", SCRATCHC2 },
+ { "scratchc3", SCRATCHC3 },
+ { "add", ADD },
+ { "addc", ADDC },
+ { "and", AND },
+ { "or", OR },
+ { "xor", XOR },
+ { "shl", SHL },
+ { "shr", SHR },
+ { "jump", JUMP },
+ { "call", CALL },
+ { "return", RETURN },
+ { "int", INT },
+ { "intfly", INTFLY },
+ { "not", NOT },
+ { "absolute", ABSOLUTE },
+ { "mask", MASK },
+ { "if", IF },
+ { "rel", REL },
+ { "ptr", PTR },
+ { "table", TABLE },
+ { "from", FROM },
+ { "memory", MEMORY },
+ { "to", TO },
+ { "nop", NOP },
+ { "extern", EXTERN },
+ { "defw", DEFW },
+};
+
+#define TOKS (sizeof(toktab)/sizeof(toktab[0]))
+
+int lc;
+int ll;
+
+void
+yyrewind(void)
+{
+ rewind(in_f);
+ ll = lc = 0;
+ yyline = 0;
+ dot = 0;
+}
+
+int
+yygetc(void)
+{
+ if (lc == ll)
+ {
+ next:
+ if (fgets(line, 500, in_f) == 0)
+ return EOF;
+ /* do nasty check for #line directives */
+ if (strncmp(line, "#line", 5) == 0) {
+ /* #line n "filename" */
+ sscanf(line, "#line %d \"%[^\"]", &yyline, yyfilename);
+ yyline--;
+ goto next;
+ }
+ yyline++;
+ ll = strlen(line);
+ lc = 0;
+ }
+ return line[lc++];
+}
+
+void
+yyungetc(void)
+{
+ if (lc <= 0)
+ exits("ungetc");
+ lc--;
+}
+
+int
+yylex(void)
+{
+ char token[100];
+ int tl = 0;
+ int c;
+
+ while ((c = yygetc()) != EOF && (c == ' ' || c == '\t'))
+ ;
+ if (c == EOF)
+ return 0;
+ if(c == '/'){
+ int x;
+ x = yygetc();
+ if(x != '/')
+ yyungetc();
+ else{
+ lc -= 2;
+ while(lc >= 0 && (line[lc-1]==' ' || line[lc-1]=='\t'))
+ lc--;
+ line[lc++] = '\n';
+ line[lc] = 0;
+ ll = lc;
+ return '\n';
+ }
+ }
+ if (isalpha(c) || c == '_')
+ {
+ int x;
+ do {
+ token[tl++] = c;
+ } while ((c = yygetc()) != EOF && (isalnum(c) || c == '_'));
+ if (c == EOF)
+ return 0;
+ yyungetc();
+ token[tl] = 0;
+ for (x = 0; x < TOKS; x++)
+ if (strcmp(toktab[x].name, token) == 0)
+ return toktab[x].tok;
+ /* must be a symbol */
+ yylval.s = findsym(token);
+ return SYMBOL;
+ }
+ else if (isdigit(c))
+ {
+ /* accept 0x<digits> or 0b<digits> 0<digits> or <digits> */
+ int prefix = c == '0';
+ unsigned long n = c - '0';
+ int base = 10;
+ for (;;)
+ {
+ c = yygetc();
+ if (c == EOF)
+ return 0;
+ if (prefix)
+ {
+ prefix = 0;
+ if (c == 'x') {
+ base = 16;
+ continue;
+ }
+ else if (c == 'b')
+ {
+ base = 2;
+ continue;
+ }
+ else
+ base = 8;
+ }
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c) && base > 10)
+ {
+ if (isupper(c))
+ c = tolower(c);
+ c = c - 'a' + 10;
+ }
+ else {
+ yyungetc();
+ yylval.n = n;
+ return NUM;
+ }
+ if (c >= base)
+ yyerror("illegal format number");
+ n = n * base + c;
+ }
+ }
+ else if (c == ';') {
+ /* skip to end of line */
+ while ((c = yygetc()) != EOF && c != '\n')
+ ;
+ if (c != EOF)
+ yyungetc();
+ return COMMENT;
+ }
+ return c;
+}
+
+void
+yyerror(char *s, ...)
+{
+ va_list ap;
+
+ va_start(ap, s);
+ fprintf(stderr, "%s: %d: ", yyfilename, yyline);
+ vfprintf(stderr, s, ap);
+ if (putc('\n', stderr) < 0)
+ exits("io");
+ errors++;
+ va_end(ap);
+}
+
+void
+yywarn(char *s, ...)
+{
+ va_list ap;
+
+ va_start(ap, s);
+ fprintf(stderr, "%s: %d: warning: ", yyfilename, yyline);
+ vfprintf(stderr, s, ap);
+ if (putc('\n', stderr) < 0)
+ exits("io");
+ warnings++;
+ va_end(ap);
+}
+
+void
+p2error(int line, char *s)
+{
+ USED(line);
+ printf("/*\t%s */\n", s);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int a;
+ for (a = 1; a < argc; a++)
+ {
+ if (argv[a][0] == '-')
+ switch (argv[a][1]) {
+ case 'D':
+ /* #defines for cpp */
+ if (ncppopts >= MAXCPPOPTS) {
+ fprintf(stderr, "too many cpp options\n");
+ exits("options");
+ }
+ cppopts[ncppopts++] = argv[a];
+ break;
+ default:
+ fprintf(stderr, "unrecognised option %s\n",
+ argv[a]);
+ exits("options");
+ }
+ else
+ break;
+ }
+ if (a != argc - 1)
+ {
+ fprintf(stderr, "usage: na [options] file\n");
+ exits("options");
+ }
+ if (access(argv[a], 4) < 0) {
+ fprintf(stderr, "can't read %s\n", argv[a]);
+ exits("");
+ }
+ in_f = tmpfile();
+ preprocess(argv[a], in_f);
+ rewind(in_f);
+ strcpy(yyfilename, argv[a]);
+ yyparse();
+ if (errors)
+ exits("pass1");
+ pass2 = 1;
+ printf("unsigned long na_script[] = {\n");
+ yyrewind();
+ yyparse();
+ printf("};\n");
+ printf("\n");
+ printf("#define NA_SCRIPT_SIZE %d\n", dot / 4);
+ printf("\n");
+ fixup();
+/*
+ assemble();
+*/
+ exits(errors ? "pass2" : "");
+}
+
+void
+preprocess(char *in, FILE *out)
+{
+#ifdef USECPP
+ Waitmsg *w;
+ char **argv;
+
+ if (fork() == 0) {
+ /* child */
+ dup(fileno(out), 1);
+ argv = (char **)malloc(sizeof(char *) * (ncppopts + 5));
+ argv[0] = "cpp";
+ memcpy(&argv[1], cppopts, sizeof(char *) * ncppopts);
+ argv[ncppopts + 1] = "-+";
+ argv[ncppopts + 2] = "-N";
+ argv[ncppopts + 3] = in;
+ argv[ncppopts + 4] = 0;
+ if (exec("/bin/cpp", argv) < 0) {
+ fprintf(stderr, "failed to exec cpp (%R)\n");
+ exits("exec");
+ }
+ exits("");
+ }
+ w = wait();
+ free(w);
+#else
+ FILE *fi;
+ int c;
+
+
+ fi = fopen(in, "r");
+ if(fi == NULL){
+ fprintf(stderr, "na: can't open %s\n", in);
+ exits("open");
+ }
+ while((c = fgetc(fi)) != EOF)
+ fputc(c, out);
+ fclose(fi);
+#endif
+}
+
+struct sym *
+findsym(char *name)
+{
+ struct sym *s;
+ for (s = symlist; s; s = s->next)
+ if (strcmp(name, s->name) == 0)
+ return s;
+ s = (struct sym *)malloc(sizeof(*s));
+ s->name = strdup(name);
+ s->t = Unknown;
+ s->set = 0;
+ s->next = symlist;
+ symlist = s;
+ return s;
+}
+
+void
+setsym(struct sym *s, Type t, long v)
+{
+ if (pass2) {
+ if (t == Unknown || t == Error)
+ yyerror("can't resolve symbol");
+ else {
+ s->t = t;
+ s->value = v;
+ }
+ }
+ else {
+ if (s->set)
+ yyerror("multiply defined symbol");
+ s->set = 1;
+ s->t = t;
+ s->value = v;
+ }
+}
+
+int
+mk24bitssigned(long *l)
+{
+ if (*l < 0) {
+ if ((*l & 0xff800000L) != 0xff800000L) {
+ *l = 0;
+ return 0;
+ }
+ else
+ *l = (*l) & 0xffffffL;
+ }
+ else if (*l > 0xffffffL) {
+ *l = 0;
+ return 0;
+ }
+ return 1;
+}
+
+static Type addresult[5][5] = {
+/* Const Addr Table Extern Reg */
+/* Const */ Const, Addr, Table, Error, Reg,
+/* Addr */ Addr, Error, Error, Error, Error,
+/* Table */ Table, Error, Error, Error, Error,
+/* Extern */ Error, Error, Error, Error, Error,
+/* Reg */ Reg, Error, Error, Error, Error,
+};
+
+static Type subresult[5][5] = {
+/* Const Addr Table Extern Reg */
+/* Const */ Const, Error, Error, Error, Error,
+/* Addr */ Addr, Const, Error, Error, Error,
+/* Table */ Table, Error, Const, Error, Error,
+/* Extern */ Error, Error, Error, Const, Error,
+/* Reg */ Error, Error, Error, Error, Error,
+};
+
+static Type muldivresult[5][5] = {
+/* Const Addr Table Extern */
+/* Const */ Const, Error, Error, Error, Error,
+/* Addr */ Error, Error, Error, Error, Error,
+/* Table */ Error, Error, Error, Error, Error,
+/* Extern */ Error, Error, Error, Error, Error,
+/* Reg */ Error, Error, Error, Error, Error,
+};
+
+static Type negresult[] = {
+/* Const */ Const,
+/* Addr */ Error,
+/* Table */ Error,
+/* Extern */ Error,
+/* Reg */ Error,
+};
+
+int
+patchtype(Type t)
+{
+ switch (t) {
+ case Addr:
+ return 1;
+ case Reg:
+ return 2;
+ case Extern:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+struct expval
+eval(struct expval a, struct expval b, char op)
+{
+ struct expval c;
+
+ if (a.t == Unknown || b.t == Unknown) {
+ c.t = Unknown;
+ c.value = 0;
+ }
+ else if (a.t == Error || b.t == Error) {
+ c.t = Error;
+ c.value = 0;
+ }
+ else {
+ switch (op) {
+ case '+':
+ c.t = addresult[a.t][b.t];
+ break;
+ case '-':
+ c.t = subresult[a.t][b.t];
+ break;
+ case '*':
+ case '/':
+ c.t = muldivresult[a.t][b.t];
+ break;
+ case '_':
+ case '~':
+ c.t = negresult[a.t];
+ break;
+ default:
+ c.t = Error;
+ break;
+ }
+ if (c.t == Error) {
+ if (pass2)
+ yyerror("type clash in evaluation");
+ c.value = 0;
+ }
+ else {
+ switch (op) {
+ case '+':
+ c.value = a.value + b.value;
+ break;
+ case '-':
+ c.value = a.value - b.value;
+ break;
+ case '*':
+ c.value = a.value * b.value;
+ break;
+ case '/':
+ c.value = a.value / b.value;
+ break;
+ case '_':
+ c.value = -a.value;
+ break;
+ case '~':
+ c.value = ~a.value;
+ break;
+ }
+ }
+ }
+ return c;
+}
+
+void
+regmove(unsigned char src_reg, unsigned char op,
+ unsigned char dst_reg, struct expval *imm)
+{
+ unsigned char func, reg;
+ int immdata;
+ out.len = 2;
+ if (src_reg == 8) {
+ func = 5;
+ reg = dst_reg;
+ }
+ else if (dst_reg == 8) {
+ func = 6;
+ reg = src_reg;
+ }
+ else {
+ if (pass2 && src_reg != dst_reg)
+ yyerror("Registers must be the same");
+ func = 7;
+ reg = src_reg;
+ }
+ immdata = imm ? (imm->value & 0xff) : 0;
+ out.data[0] = 0x40000000L
+ | ((long)func << 27)
+ | ((long)op << 24)
+ | ((long)reg << 16)
+ | ((long)(immdata) << 8);
+ out.data[1] = 0;
+ out.patch[0] = (imm && imm->t == Extern) ? 3 : 0;
+ out.patch[1] = 0;
+}
+
+long
+mkreladdr(long addr, int len)
+{
+ long rel;
+ rel = addr - (dot + 4 * len);
+ mk24bitssigned(&rel);
+ return rel;
+}
+
+long
+chkreladdr(int d, struct expval *e, int len, long relrv)
+{
+ if (e->t == Addr) {
+ out.data[d] = mkreladdr(e->value, len);
+ out.patch[d] = 0;
+ return relrv;
+ } else {
+ out.data[d] = e->value;
+ out.patch[d] = patchtype(e->t);
+ return 0;
+ }
+}
+
+void
+fixup(void)
+{
+ struct sym *s;
+ int p;
+ printf("struct na_patch na_patches[] = {\n");
+ for (p = 0; p < patches; p++) {
+ printf("\t{ 0x%.4x, %d }, /* %.8lx */\n",
+ patch[p].lwoff, patch[p].type, patch[p].lwoff * 4L);
+ }
+ if (patches == 0) {
+ printf("\t{ 0, 0 },\n");
+ }
+ printf("};\n");
+ printf("#define NA_PATCHES %d\n", patches);
+ printf("\n");
+ if (externs) {
+ printf("enum na_external {\n");
+ for (p = 0; p < externs; p++) {
+ printf("\tX_%s,\n", externp[p]->name);
+ }
+ printf("};\n");
+ }
+ /* dump all labels (symbols of type Addr) as E_<Name> */
+ for (s = symlist; s; s = s->next)
+ if (s->t == Addr)
+ break;
+ if (s) {
+ printf("\nenum {\n");
+ while (s) {
+ if (s->t == Addr)
+ printf("\tE_%s = %ld,\n", s->name, s->value);
+ s = s->next;
+ }
+ printf("};\n");
+ }
+ /* dump all Consts as #define A_<Name> value */
+ for (s = symlist; s; s = s->next)
+ if (s->t == Const)
+ printf("#define A_%s %ld\n", s->name, s->value);
+}
+
diff --git a/utils/ndate/mkfile b/utils/ndate/mkfile
new file mode 100644
index 00000000..01565f8d
--- /dev/null
+++ b/utils/ndate/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=ndate
+
+OFILES= ndate.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/ndate/ndate.c b/utils/ndate/ndate.c
new file mode 100644
index 00000000..0cbc3574
--- /dev/null
+++ b/utils/ndate/ndate.c
@@ -0,0 +1,11 @@
+#include <lib9.h>
+
+void
+main(void)
+{
+ ulong t;
+
+ t = time(0);
+ print("%lud\n", t);
+ exits(0);
+}
diff --git a/utils/nm/mkfile b/utils/nm/mkfile
new file mode 100644
index 00000000..983f0f52
--- /dev/null
+++ b/utils/nm/mkfile
@@ -0,0 +1,14 @@
+<../../mkconfig
+
+TARG=inm # inferno nm
+
+OFILES=\
+ nm.$O\
+
+LIBS=mach bio 9 # order is important.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I. -I../include
diff --git a/utils/nm/nm.c b/utils/nm/nm.c
new file mode 100644
index 00000000..cf36ad10
--- /dev/null
+++ b/utils/nm/nm.c
@@ -0,0 +1,287 @@
+/*
+ * nm.c -- drive nm
+ */
+#include <lib9.h>
+#include <ar.h>
+#include <bio.h>
+#include <mach.h>
+
+enum{
+ CHUNK = 256 /* must be power of 2 */
+};
+
+char *errs; /* exit status */
+char *filename; /* current file */
+char symname[]="__.SYMDEF"; /* table of contents file name */
+int multifile; /* processing multiple files */
+int aflag;
+int gflag;
+int hflag;
+int nflag;
+int sflag;
+int uflag;
+
+Sym **fnames; /* file path translation table */
+Sym **symptr;
+int nsym;
+Biobuf bout;
+char* argv0;
+
+void error(char*, ...);
+void execsyms(int);
+void psym(Sym*, void*);
+void printsyms(Sym**, long);
+void doar(Biobuf*);
+void dofile(Biobuf*);
+void zenter(Sym*);
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ Biobuf *bin;
+
+ Binit(&bout, 1, OWRITE);
+ argv0 = argv[0];
+ ARGBEGIN {
+ case 'a': aflag = 1; break;
+ case 'g': gflag = 1; break;
+ case 'h': hflag = 1; break;
+ case 'n': nflag = 1; break;
+ case 's': sflag = 1; break;
+ case 'u': uflag = 1; break;
+ } ARGEND
+ if (argc > 1)
+ multifile++;
+ for(i=0; i<argc; i++){
+ filename = argv[i];
+ bin = Bopen(filename, OREAD);
+ if(bin == 0){
+ error("cannot open %s", filename);
+ continue;
+ }
+ if (isar(bin))
+ doar(bin);
+ else{
+ Bseek(bin, 0, 0);
+ dofile(bin);
+ }
+ Bterm(bin);
+ }
+ exits(errs);
+}
+
+/*
+ * read an archive file,
+ * processing the symbols for each intermediate file in it.
+ */
+void
+doar(Biobuf *bp)
+{
+ int offset, size, obj;
+ char membername[SARNAME];
+
+ multifile = 1;
+ for (offset = Boffset(bp);;offset += size) {
+ size = nextar(bp, offset, membername);
+ if (size < 0) {
+ error("phase error on ar header %ld", offset);
+ return;
+ }
+ if (size == 0)
+ return;
+ if (strcmp(membername, symname) == 0)
+ continue;
+ obj = objtype(bp, 0);
+ if (obj < 0) {
+ error("inconsistent file %s in %s",
+ membername, filename);
+ return;
+ }
+ if (!readar(bp, obj, offset+size, 1)) {
+ error("invalid symbol reference in file %s",
+ membername);
+ return;
+ }
+ filename = membername;
+ nsym=0;
+ objtraverse(psym, 0);
+ printsyms(symptr, nsym);
+ }
+}
+
+/*
+ * process symbols in a file
+ */
+void
+dofile(Biobuf *bp)
+{
+ int obj;
+
+ obj = objtype(bp, 0);
+ if (obj < 0)
+ execsyms(Bfildes(bp));
+ else
+ if (readobj(bp, obj)) {
+ nsym = 0;
+ objtraverse(psym, 0);
+ printsyms(symptr, nsym);
+ }
+}
+
+/*
+ * comparison routine for sorting the symbol table
+ * this screws up on 'z' records when aflag == 1
+ */
+int
+cmp(const void *vs, const void *vt)
+{
+ Sym **s, **t;
+
+ s = (Sym**)vs;
+ t = (Sym**)vt;
+ if(nflag)
+ if((ulong)(*s)->value < (ulong)(*t)->value)
+ return -1;
+ else
+ return (ulong)(*s)->value > (ulong)(*t)->value;
+ return strcmp((*s)->name, (*t)->name);
+}
+/*
+ * enter a symbol in the table of filename elements
+ */
+void
+zenter(Sym *s)
+{
+ static int maxf = 0;
+
+ if (s->value > maxf) {
+ maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
+ fnames = realloc(fnames, maxf*sizeof(*fnames));
+ if(fnames == 0) {
+ error("out of memory", argv0);
+ exits("memory");
+ }
+ }
+ fnames[s->value] = s;
+}
+
+/*
+ * get the symbol table from an executable file, if it has one
+ */
+void
+execsyms(int fd)
+{
+ Fhdr f;
+ Sym *s;
+ long n;
+
+ seek(fd, 0, 0);
+ if (crackhdr(fd, &f) == 0) {
+ error("Can't read header for %s", filename);
+ return;
+ }
+ if (syminit(fd, &f) < 0)
+ return;
+ s = symbase(&n);
+ nsym = 0;
+ while(n--)
+ psym(s++, 0);
+
+ printsyms(symptr, nsym);
+}
+
+void
+psym(Sym *s, void* p)
+{
+ USED(p);
+ switch(s->type) {
+ case 'T':
+ case 'L':
+ case 'D':
+ case 'B':
+ if (uflag)
+ return;
+ if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
+ return;
+ break;
+ case 'b':
+ case 'd':
+ case 'l':
+ case 't':
+ if (uflag || gflag)
+ return;
+ if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
+ return;
+ break;
+ case 'U':
+ if (gflag)
+ return;
+ break;
+ case 'Z':
+ if (!aflag)
+ return;
+ break;
+ case 'm':
+ case 'f': /* we only see a 'z' when the following is true*/
+ if(!aflag || uflag || gflag)
+ return;
+ if (strcmp(s->name, ".frame"))
+ zenter(s);
+ break;
+ case 'a':
+ case 'p':
+ case 'z':
+ default:
+ if(!aflag || uflag || gflag)
+ return;
+ break;
+ }
+ symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
+ if (symptr == 0) {
+ error("out of memory");
+ exits("memory");
+ }
+ symptr[nsym++] = s;
+}
+
+void
+printsyms(Sym **symptr, long nsym)
+{
+ Sym *s;
+ char *cp;
+ char path[512];
+
+ if(!sflag)
+ qsort(symptr, nsym, sizeof(*symptr), cmp);
+ while (nsym-- > 0) {
+ s = *symptr++;
+ if (multifile && !hflag)
+ Bprint(&bout, "%s:", filename);
+ if (s->type == 'z') {
+ fileelem(fnames, (uchar *) s->name, path, 512);
+ cp = path;
+ } else
+ cp = s->name;
+ if (s->value || s->type == 'a' || s->type == 'p')
+ Bprint(&bout, "%8lux %c %s\n", s->value, s->type, cp);
+ else
+ Bprint(&bout, " %c %s\n", s->type, cp);
+ }
+}
+
+void
+error(char *fmt, ...)
+{
+ char buf[4096], *s;
+ va_list arg;
+
+ s = buf;
+ s += sprint(s, "%s: ", argv0);
+ va_start(arg, fmt);
+ s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
+ va_end(arg);
+ *s++ = '\n';
+ write(2, buf, s - buf);
+ errs = "errors";
+}
diff --git a/utils/ntsrv/domk b/utils/ntsrv/domk
new file mode 100644
index 00000000..544ad331
--- /dev/null
+++ b/utils/ntsrv/domk
@@ -0,0 +1,2 @@
+os -d $emuroot\utils\ntsrv mk | sed 's/\(([0-9]*)\)/:\1/
+s/ //'
diff --git a/utils/ntsrv/mkfile b/utils/ntsrv/mkfile
new file mode 100755
index 00000000..8d15bec8
--- /dev/null
+++ b/utils/ntsrv/mkfile
@@ -0,0 +1,25 @@
+#uncomment following line for full Microsoft debug symbols
+#LDEBUG=-debug -debugtype:cv -pdb:none
+<../../mkconfig
+SYSTARG=Nt
+SYSHOST=Nt
+OBJTYPE=386
+OBJDIR=$SYSTARG/$OBJTYPE
+<$ROOT/mkfiles/mkhost-$SYSHOST
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE
+
+TARG=ntsrv
+
+OFILES= ntsrv.$O\
+
+HFILES=
+
+LIBS=9
+
+CFLAGS=$CFLAGS -I.
+
+BIN=$ROOT/$OBJDIR/bin
+
+SYSLIBS= $SYSLIBS wsock32.lib user32.lib gdi32.lib advapi32.lib winmm.lib mpr.lib
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/ntsrv/ntsrv.c b/utils/ntsrv/ntsrv.c
new file mode 100644
index 00000000..881a0c3f
--- /dev/null
+++ b/utils/ntsrv/ntsrv.c
@@ -0,0 +1,573 @@
+#ifndef ForNT4
+/* only for XP, 2000 and above - JobObject only available on these*/
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include "lib9.h"
+#include <windows.h>
+#include <winsvc.h>
+#include <stdarg.h>
+
+#ifdef JOB_OBJECT_TERMINATE
+#define Jobs
+#endif
+
+#ifdef ForNT4
+#undef Jobs
+#endif
+
+/*
+ * ntsrv add Name Inferno-root Cmds
+ * ntsrv del Name
+ * ntsrv run Name Inferno-root Cmds
+ *
+ * 'add' registers service: Name with args "run Name Inferno-root Cmds"
+ * 'del' unregisters service Name
+ * 'run' - only given by NT service manager when starting the service (see 'add')
+ *
+ * Cmds are cat'd (with space separator) and requoted for CreateProcess()
+ *
+ * There must be an ntsrv.exe in Inferno-root/Nt/386/bin
+ */
+
+
+SERVICE_STATUS status = {
+ SERVICE_WIN32_OWN_PROCESS, /* dwServiceType */
+ 0, /* dwCurrentState */
+ SERVICE_ACCEPT_STOP /* dwControlsAccepted */
+};
+
+typedef struct Emu Emu;
+struct Emu {
+ HANDLE proc; /* NULL if error */
+ HANDLE job; /* job for all children */
+ HANDLE stdin; /* stdio pipes */
+ HANDLE stdout;
+ DWORD notepg; /* process group ID (in case we lack Jobs) */
+};
+
+typedef struct Copyargs Copyargs;
+struct Copyargs {
+ HANDLE in;
+ HANDLE out;
+};
+
+#ifdef Jobs
+static char *myname = "ntsrv.exe";
+#else
+static char *myname = "ntsrv4.exe";
+#endif
+#define LOGFILE "grid\\slave\\svclog"
+static char *name;
+static char *root;
+static char *cmds;
+static SERVICE_STATUS_HANDLE statush;
+static HANDLE emujob; /* win32 job object for emu session */
+static DWORD emugroup; /* process group ID for emu session */
+static HANDLE emuin; /* stdin pipe of emu */
+static HANDLE logf;
+
+HANDLE openlog(char*);
+void logmsg(char*, ...);
+void WINAPI infmain(ulong, LPTSTR[]);
+void WINAPI infctl(ulong);
+Emu runemu(char*);
+HANDLE exporthandle(HANDLE, int);
+DWORD WINAPI copy(LPVOID);
+int shuttingdown = 0;
+int nice = 0;
+
+static void
+usage()
+{
+ fprint(2, "usage: ntsrv [-n] add name root cmds | del name\n");
+}
+
+/* (from rcsh)
+ * windows quoting rules - I think
+ * Words are seperated by space or tab
+ * Words containing a space or tab can be quoted using "
+ * 2N backslashes + " ==> N backslashes and end quote
+ * 2N+1 backslashes + " ==> N backslashes + literal "
+ * N backslashes not followed by " ==> N backslashes
+ */
+static char *
+dblquote(char *cmd, char *s)
+{
+ int nb;
+ char *p;
+
+ for(p=s; *p; p++)
+ if(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '"')
+ break;
+
+ if(*p == 0){ /* easy case */
+ strcpy(cmd, s);
+ return cmd+(p-s);
+ }
+
+ *cmd++ = '"';
+ for(;;) {
+ for(nb=0; *s=='\\'; nb++)
+ *cmd++ = *s++;
+
+ if(*s == 0) { /* trailing backslashes -> 2N */
+ while(nb-- > 0)
+ *cmd++ = '\\';
+ break;
+ }
+
+ if(*s == '"') { /* literal quote -> 2N+1 backslashes */
+ while(nb-- > 0)
+ *cmd++ = '\\';
+ *cmd++ = '\\'; /* escape the quote */
+ }
+ *cmd++ = *s++;
+ }
+
+ *cmd++ = '"';
+ *cmd = 0;
+
+ return cmd;
+}
+
+static char *
+proccmd(char **argv)
+{
+ int i, n;
+ char *cmd, *p;
+
+ /* conservatively calculate length of command;
+ * backslash expansion can cause growth in dblquote().
+ */
+ for(i=0,n=0; argv[i]; i++) {
+ n += 2*strlen(argv[i]);
+ }
+ n++;
+
+ cmd = malloc(n);
+ for(i=0,p=cmd; argv[i]; i++) {
+ p = dblquote(p, argv[i]);
+ *p++ = ' ';
+ }
+ if(p != cmd)
+ p--;
+ *p = 0;
+
+ return cmd;
+}
+
+int
+installnewemu()
+{
+ LPCTSTR currpath, newpath;
+ currpath = smprint("%s\\Nt\\386\\bin\\emu.exe", root);
+ newpath = smprint("%s\\Nt\\386\\bin\\newemu.exe", root);
+ if(GetFileAttributes(newpath) == 0xffffffff) // INVALID_FILE_ATTRIBUTES is not defined
+ return 0;
+ DeleteFile(currpath); // ignore error message - it might not be there.
+ if(MoveFile(newpath, currpath) == 0){
+ logmsg("cannot rename %s to %s: %r", newpath, currpath);
+ return -1;
+ }
+ return 0;
+}
+
+void WINAPI
+infmain(ulong argc, char *argv[])
+{
+ HANDLE cpt;
+ Emu emu;
+ Copyargs cp;
+ DWORD tid;
+ char *cmd;
+
+ argc--;
+ argv++;
+ cmd = smprint("%s\\%s", root, LOGFILE);
+ logf = openlog(cmd);
+ free(cmd);
+ statush = RegisterServiceCtrlHandler(name, infctl);
+ if (statush == 0)
+ return;
+
+ status.dwCurrentState = SERVICE_START_PENDING;
+ SetServiceStatus(statush, &status);
+
+ while(installnewemu() != -1){
+ /* start the service */
+ cmd = smprint("%s\\Nt\\386\\bin\\emu.exe -r%s %s", root, root, cmds);
+ logmsg("starting %s", cmd);
+ emu = runemu(cmd);
+ free(cmd);
+ if (emu.proc == NULL) {
+ logmsg("runemu failed: %r");
+ status.dwCurrentState = SERVICE_STOPPED;
+ SetServiceStatus(statush, &status);
+ return;
+ }
+
+ cp.in = emu.stdout;
+ cp.out = logf;
+ cpt = CreateThread(NULL, 0, copy, (void*)&cp, 0, &tid);
+ if (cpt == NULL) {
+ logmsg("failed to create copy thread: %r");
+ CloseHandle(emu.stdout);
+ }
+
+ logmsg("infmain blocking on emu proc");
+ emujob = emu.job;
+ emugroup = emu.notepg;
+ status.dwCurrentState = SERVICE_RUNNING;
+ SetServiceStatus(statush, &status);
+ WaitForSingleObject(emu.proc, INFINITE);
+ logmsg("infmain emu proc terminated");
+ emujob = NULL;
+ emugroup = 0;
+#ifdef Jobs
+ logmsg("terminating job");
+ TerminateJobObject(emu.job, 0);
+#else
+ logmsg("notepg (%d)", emu.notepg);
+ if(emu.notepg)
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, emu.notepg);
+#endif
+ if (cpt) {
+ /* copy() sees eof on emu.stdout and exits */
+ WaitForSingleObject(cpt, INFINITE);
+ CloseHandle(cpt);
+ CloseHandle(emu.stdout);
+ }
+ CloseHandle(emu.proc);
+ if(emu.job != NULL)
+ CloseHandle(emu.job);
+ CloseHandle(emu.stdin);
+ // XXX should check to see that we're not starting up again too quickly, as
+ // it's quite possible to get into an infinite loop here.
+ // but what are good criteria? 5 times? 100 times?
+ // 10 times within a minute?
+ // for the moment, just sleep for a while before restarting...
+ if(shuttingdown)
+ break;
+ SleepEx(10000, FALSE);
+ }
+ logmsg("infmain done");
+ if (logf)
+ CloseHandle(logf);
+ status.dwCurrentState = SERVICE_STOPPED;
+ SetServiceStatus(statush, &status);
+ return;
+}
+
+void WINAPI
+infctl(ulong op)
+{
+ if (op != SERVICE_CONTROL_STOP)
+ return;
+
+ /* stop the service (status set by infmain()
+ *
+ * NOTE: there is a race for emujob - may have been closed
+ * after test, but before TerminateJobObject()
+ * MSDN is unclear as to whether TerminatJobObject() handles
+ * NULL job ptr - should probably use a mutex
+ */
+ shuttingdown = 1;
+#ifdef Jobs
+ logmsg("svc stop: stopping job");
+ if (emujob)
+ TerminateJobObject(emujob, 0);
+#else
+ logmsg("svc stop: interrupting emu");
+ if (emugroup)
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, emugroup);
+#endif
+}
+
+void
+printerror(char *s)
+{
+ char *msg;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
+ FORMAT_MESSAGE_FROM_SYSTEM|
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&msg,
+ 0,
+ NULL);
+ fprint(2, "%s: %s\n", s, msg);
+ LocalFree(msg);
+}
+
+int
+add(char *name, char *root, char *cmds)
+{
+ char *path;
+ int r;
+ SC_HANDLE scm, scs;
+ char *nopt;
+
+ nopt = nice ? " -n" : "";
+ path = smprint("%s\\Nt\\386\\bin\\%s%s run %s %s %s", root, myname, nopt, name, root, cmds);
+ r = 0;
+ scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (scm == NULL) {
+ printerror("cannot open service control manager");
+ return -1;
+ }
+ scs = CreateService(scm,
+ name,
+ name,
+ SERVICE_START|SERVICE_STOP,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_AUTO_START,
+ SERVICE_ERROR_IGNORE,
+ path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (scs == NULL) {
+ printerror("cannot create service");
+ r = -1;
+ } else {
+ CloseServiceHandle(scs);
+ }
+ CloseServiceHandle(scm);
+ return r;
+}
+
+int
+del(char *name)
+{
+ SC_HANDLE scm, scs;
+
+ scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (scm == NULL) {
+ printerror("cannot open service control manager");
+ return -1;
+ }
+
+ scs = OpenService(scm, name, DELETE);
+ if (scs == NULL) {
+ printerror("cannot open service");
+ CloseServiceHandle(scm);
+ return -1;
+ }
+ if (!DeleteService(scs)) {
+ printerror("cannot delete Iservice");
+ CloseServiceHandle(scs);
+ CloseServiceHandle(scm);
+ return -1;
+ }
+ CloseServiceHandle(scs);
+ CloseServiceHandle(scm);
+ return 0;
+}
+
+HANDLE
+openlog(char *p)
+{
+ HANDLE h;
+ h = CreateFile(p, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ SetFilePointer(h, 0, NULL, FILE_END);
+ return h;
+}
+
+void
+logmsg(char *fmt, ...)
+{
+ int n;
+ char *p;
+ va_list args;
+ if(logf == 0)
+ return;
+ va_start(args, fmt);
+ p = vsmprint(fmt, args);
+ va_end(args);
+ n = strlen(p);
+ if (n)
+ WriteFile(logf, p, n, &n, NULL);
+ WriteFile(logf, "\n", 1, &n, NULL);
+}
+
+Emu
+runemu(char *cmd)
+{
+ Emu r = {NULL, NULL, NULL};
+ STARTUPINFO si;
+ PROCESS_INFORMATION pinfo;
+ HANDLE job, emu, emut, stdin, stdout, stderr, emui, emuo;
+ SECURITY_ATTRIBUTES sec;
+ DWORD flags;
+
+ job = emu = emut = stdin = stdout = stderr = emui = emuo = NULL;
+#ifdef Jobs
+ job = CreateJobObject(NULL, NULL);
+ if (job == NULL) {
+ logmsg("cannot create job object: %r");
+ goto error;
+ }
+#endif
+
+ /* set up pipes */
+ sec.nLength = sizeof(sec);
+ sec.lpSecurityDescriptor = 0;
+ sec.bInheritHandle = 0;
+ if (!CreatePipe(&stdin, &emui, &sec, 0)) {
+ logmsg("cannot create stdin pipe: %r");
+ goto error;
+ }
+ if (!CreatePipe(&emuo, &stdout, &sec, 0)) {
+ logmsg("cannot create stdout pipe: %r");
+ goto error;
+ }
+ stdin = exporthandle(stdin, 1);
+ stdout = exporthandle(stdout, 1);
+ stderr = exporthandle(stdout, 0);
+
+ /* create emu process (suspended) */
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = stdin;
+ si.hStdOutput = stdout;
+ si.hStdError = stderr;
+
+ flags = CREATE_NEW_PROCESS_GROUP|CREATE_DEFAULT_ERROR_MODE|CREATE_SUSPENDED;
+ if(nice)
+ flags |= IDLE_PRIORITY_CLASS;
+ if(!CreateProcess(0, cmd, 0, 0, 1, flags, 0, 0, &si, &pinfo)) {
+ logmsg("cannot create process: %r");
+ goto error;
+ }
+ emu = pinfo.hProcess;
+ emut = pinfo.hThread;
+ CloseHandle(stdin);
+ stdin = NULL;
+ CloseHandle(stdout);
+ stdout = NULL;
+ CloseHandle(stderr);
+ stderr = NULL;
+
+#ifdef Jobs
+ if(!AssignProcessToJobObject(job, emu)) {
+ logmsg("failed to assign emu to job: %r");
+ goto error;
+ }
+#endif
+ ResumeThread(emut);
+ CloseHandle(emut);
+
+ r.proc = emu;
+ r.notepg = pinfo.dwProcessId;
+ r.job = job; /* will be NULL if not implemented (NT4) */
+ r.stdin = emui;
+ r.stdout = emuo;
+ return r;
+
+error:
+ if (stdin)
+ CloseHandle(stdin);
+ if (stdout)
+ CloseHandle(stdout);
+ if (stderr)
+ CloseHandle(stderr);
+ if (emui)
+ CloseHandle(emuin);
+ if (emuo)
+ CloseHandle(emuo);
+ if (emut)
+ CloseHandle(emut);
+ if (emu) {
+ TerminateProcess(emu, 0);
+ CloseHandle(emu);
+ }
+ if (job)
+ CloseHandle(job);
+ return r;
+}
+
+HANDLE
+exporthandle(HANDLE h, int close)
+{
+ HANDLE cp, dh;
+ DWORD flags = DUPLICATE_SAME_ACCESS;
+ if (close)
+ flags |= DUPLICATE_CLOSE_SOURCE;
+ cp = GetCurrentProcess();
+ if (!DuplicateHandle(cp, h, cp, &dh, DUPLICATE_SAME_ACCESS, 1, flags))
+ return nil;
+ return dh;
+}
+
+DWORD WINAPI
+copy(void *arg)
+{
+ Copyargs *cp = (Copyargs*)arg;
+ char buf[1024];
+ DWORD n;
+
+ while (ReadFile(cp->in, buf, sizeof(buf), &n, NULL)) {
+ if (n && cp->out)
+ WriteFile(cp->out, buf, n, &n, NULL);
+ }
+ return 0;
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *verb;
+ SERVICE_TABLE_ENTRY services[2];
+
+ memset(services, 0, sizeof(services));
+
+ ARGBEGIN{
+ case 'n':
+ nice = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if (argc < 2) {
+ usage();
+ return;
+ }
+
+ verb = argv[0];
+ name = argv[1];
+ if (argc > 2)
+ root = argv[2];
+ if (argc > 3)
+ cmds = proccmd(argv+3);
+
+ if (strcmp(verb, "del") == 0)
+ exit(del(name));
+ if (strcmp(verb, "add") == 0) {
+ if (root == NULL || cmds == NULL) {
+ usage();
+ return;
+ }
+ exit(add(name, root, cmds));
+ }
+ if (strcmp(verb, "run") == 0) {
+ if (root == NULL || cmds == NULL || *cmds == '\0') {
+ usage();
+ return;
+ }
+ services[0].lpServiceName = name;
+ services[0].lpServiceProc = infmain;
+ StartServiceCtrlDispatcher(services);
+ exit(0);
+ }
+ usage();
+}
diff --git a/utils/qa/Ins b/utils/qa/Ins
new file mode 100644
index 00000000..d113e845
--- /dev/null
+++ b/utils/qa/Ins
@@ -0,0 +1,203 @@
+a OR XO(31,10)
+abs OR XO(31,360)
+ae OR XO(31,138)
+ai 0 D(12) +
+
+ai. 0 D(13)
+ame OR XO(31,234)
+and R X(31,28)
+andc R X(31,60)
+
+andil. 0 D(28,0)
+andiu. 0 D(29,0)
+aze OR XO(31,202)
+cal 0 D(14)
+
+cau 0 D(15)
+cax OR XO(31,266)
+cmp 0 X(31,0)
+cmpi 0 D(11)
+
+cmpl 0 X(31,32)
+cmpli 0 D(10)
+cntlz R X(31,26)
+crand 0 XL(19,257)
+
+crandc 0 XL(19,129)
+creqv 0 XL(19,289)
+crnand 0 XL(19,225)
+crnor 0 XL(19,33)
+
+cror 0 XL(19,449)
+crorc 0 XL(19,417)
+crxor 0 XL(19,193)
+div OR XO(31,331)
+
+divs OR XO(31,331)
+doz OR XO(31,264)
+dozi 0 D(9)
+
+eqv R X(31,284)
+exts R X(31,922)
+fa R A(63,21)
+fabs R X(63,264)
+fcmpo 0 X(63,32)
+
+fcmpu 0 X(63,0)
+fd R A(63,8)
+fm R A(63,5)
+fma R A(63,29)
+
+fmr R X(63,72)
+fms R A(63,28)
+fnabs R X(63,136)
+fneg R X(63,40)
+
+fnma R A(63,31)
+fnms R A(63,30)
+frsp R X(63,12)
+fs R A(63,20)
+
+l 0 D(32)
+lbrx 0 X(31,534)
+lbz 0 D(34)
+lbzu 0 D(35)
+
+lbzux 0 X(31,119)
+lbzx 0 X(31,87)
+lfd 0 D(50)
+lfdu 0 D(51)
+
+lfdux 0 X(31,631)
+lfdx 0 X(31,599)
+lfs 0 D(48)
+lfsu 0 D(49)
+
+lfsux 0 X(31,567)
+lfsx 0 X(31,535)
+lha 0 D(42)
+lhau 0 D(43)
+
+lhaux 0 X(31,375)
+lhax 0 X(31,343)
+lhbrx 0 X(31,790)
+lhz 0 D(40)
+
+lhzu 0 D(41)
+lhzux 0 X(31,311)
+lhzx 0 X(31,279)
+lm 0 D(46)
+
+lscbx R X(31,277)
+lsi 0 X(31,597)
+lsx 0 X(31,533)
+lu 0 D(33)
+
+lux 0 X(31,55)
+lx 0 X(31,23)
+maskg R X(31,29)
+maskir R X(31,541)
+
+mcrf 0 XL(19,0)
+mcrfs 0 X(63,64)
+mcrxr 0 X(31,512)
+mfcr 0 X(31,19)
+
+mffs R X(63,583)
+mfmsr 0 X(31,83)
+mfspr 0 X(31,339)
+mtcrf 0 XFX(31,144)
+
+mtfsb0 R X(63,70)
+mtfsb1 R X(63,38)
+mtfsf R XFL(63,711)
+mtfsfi R X(63,134)
+
+mtspr 0 X(31,467)
+mul OR XO(31,107)
+muli 0 D(7)
+muls OR XO(31,235)
+
+nabs OR XO(31,488)
+nand R X(31,476)
+neg OR XO(31,104)
+
+nor R X(31,124)
+or R X(31,444)
+orc R X(31,412)
+oril 0 D(24)
+
+oriu 0 D(25)
+rlmi R M(20)
+rlinm R M(21)
+rlmi R M(22)
+
+rlnm R M(23)
+rrib R X(31,537)
+sf OR XO(31,8)
+sfe OR XO(31,36)
+
+sfi 0 D(8)
+sfme OR XO(31,232)
+sfze OR XO(31,200)
+sl R X(31,24)
+
+sle R X(31,153)
+sleq R X(31,217)
+sliq R X(31,184)
+slliq R X(31,248)
+
+sllq R X(31,216)
+slq R X(31,152)
+sr R X(31,536)
+sra R X(31,792)
+
+srai R X(31,824)
+sraiq R X(31,952)
+sraq R X(31,920)
+sre R X(31,665)
+
+srea R X(31,921)
+sreq R X(31,729)
+sriq R X(31,696)
+srliq R X(31,760)
+srlq R X(31,728)
+
+srq R X(31,664)
+st 0 D(36)
+stb 0 D(38)
+stbrx 0 X(31,662)
+
+stbu 0 D(39)
+stbux 0 X(31,247)
+stbx 0 X(31,215)
+stfd 0 D(54)
+
+stfdu 0 D(55)
+stfdux 0 X(31,759)
+stfdx 0 X(31,727)
+stfs 0 D(52)
+
+stfsu 0 D(53)
+stfsux 0 X(31,695)
+stfsx 0 X(31,663)
+sth 0 D(44)
+
+sthbrx 0 X(31,918)
+sthu 0 D(45)
+sthux 0 X(31,439)
+sthx 0 X(3,407)
+
+stm 0 D(47)
+stsi 0 X(31,725)
+stsx 0 X(31,661)
+stu 0 D(37)
+
+stux 0 X(31,183)
+stx 0 X(31,151)
+svc 0 SC(17)
+t 0 X(31,4)
+ti 0 D(3)
+xor R X(31,316)
+xoril 0 D(26)
+xoriu 0 D(27)
diff --git a/utils/qa/a.h b/utils/qa/a.h
new file mode 100644
index 00000000..f7fce238
--- /dev/null
+++ b/utils/qa/a.h
@@ -0,0 +1,199 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../qc/q.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+#define ALLOC(lhs, type)\
+ while(nhunk < sizeof(type))\
+ gethunk();\
+ lhs = (type*)hunk;\
+ nhunk -= sizeof(type);\
+ hunk += sizeof(type);
+
+#define ALLOCN(lhs, len, n)\
+ if(lhs+len != hunk || nhunk < n) {\
+ while(nhunk <= len)\
+ gethunk();\
+ memmove(hunk, lhs, len);\
+ lhs = hunk;\
+ hunk += len;\
+ nhunk -= len;\
+ }\
+ hunk += n;\
+ nhunk -= n;
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ long offset;
+ short type;
+ short reg;
+ short xreg;
+ short name;
+ ushort mask;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int nosched;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+void outcode(int, Gen*, int, Gen*);
+void outgcode(int, Gen*, int, Gen*, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void outhist(void);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/qa/a.y b/utils/qa/a.y
new file mode 100644
index 00000000..3474ea0d
--- /dev/null
+++ b/utils/qa/a.y
@@ -0,0 +1,974 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP
+%token <lval> LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW
+%token <lval> LNOP LEND LRETT LWORD LTEXT LDATA LRETRN
+%token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH
+%token <lval> LREG LFREG LR LCR LF LFPSCR
+%token <lval> LLR LCTR LSPR LSPREG LSEG LMSR
+%token <lval> LSCHED LXLD LXST LXOP LXMV
+%token <lval> LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset sreg
+%type <gen> addr rreg regaddr name creg freg xlreg lr ctr
+%type <gen> imm ximm fimm rel psr lcr cbit fpscr fpscrf seg msr mask
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LSCHED ';'
+ {
+ nosched = $1;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * load ints and bytes
+ */
+ LMOVW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * load floats
+ */
+| LFMOV addr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV regaddr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV fimm ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFMOV freg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * store ints and bytes
+ */
+| LMOVW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * store floats
+ */
+| LMOVW freg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * floating point status
+ */
+| LMOVW fpscr ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' fpscr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW freg ',' imm ',' fpscr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LMOVW fpscr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW imm ',' fpscrf
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMTFSB imm ',' con
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+/*
+ * field moves (mtcrf)
+ */
+| LMOVW rreg ',' imm ',' lcr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LMOVW rreg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' lcr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * integer operations
+ * logical instructions
+ * shift instructions
+ * unary instructions
+ */
+| LADDW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LADDW rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LADDW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LADDW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LLOGW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LLOGW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LSHW rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LSHW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LSHW imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LSHW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LABS rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LABS rreg
+ {
+ outcode($1, &$2, NREG, &$2);
+ }
+/*
+ * multiply-accumulate
+ */
+| LMA rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * move immediate: macro for cau+or, addi, addis, and other combinations
+ */
+| LMOVW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW ximm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * condition register operations
+ */
+| LCROP cbit ',' cbit
+ {
+ outcode($1, &$2, $4.reg, &$4);
+ }
+| LCROP cbit ',' con ',' cbit
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * condition register moves
+ * move from machine state register
+ */
+| LMOVW creg ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW psr ',' creg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW lcr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW psr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW seg ',' rreg
+ {
+ int r;
+ r = $2.offset;
+ $2.offset = 0;
+ outcode($1, &$2, r, &$4);
+ }
+| LMOVW rreg ',' seg
+ {
+ int r;
+ r = $4.offset;
+ $4.offset = 0;
+ outcode($1, &$2, r, &$4);
+ }
+| LMOVW xlreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' xlreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW creg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' psr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * branch, branch conditional
+ * branch conditional register
+ * branch conditional to count register
+ */
+| LBRA rel
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+| LBRA addr
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+| LBRA '(' xlreg ')'
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' addr
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LBRA ',' '(' xlreg ')'
+ {
+ outcode($1, &nullgen, NREG, &$4);
+ }
+| LBRA creg ',' rel
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LBRA creg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LBRA creg ',' '(' xlreg ')'
+ {
+ outcode($1, &$2, NREG, &$5);
+ }
+| LBRA con ',' rel
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LBRA con ',' addr
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LBRA con ',' '(' xlreg ')'
+ {
+ outcode($1, &nullgen, $2, &$5);
+ }
+| LBRA con ',' con ',' rel
+ {
+ Gen g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$6);
+ }
+| LBRA con ',' con ',' addr
+ {
+ Gen g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$6);
+ }
+| LBRA con ',' con ',' '(' xlreg ')'
+ {
+ Gen g;
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = $2;
+ outcode($1, &g, $4, &$7);
+ }
+/*
+ * conditional trap
+ */
+| LTRAP rreg ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP imm ',' sreg
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTRAP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LTRAP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * floating point operate
+ */
+| LFCONV freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFADD freg ',' freg ',' freg
+ {
+ outcode($1, &$2, $4.reg, &$6);
+ }
+| LFMA freg ',' freg ',' freg ',' freg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LFCMP freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFCMP freg ',' freg ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+/*
+ * CMP
+ */
+| LCMP rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LCMP rreg ',' rreg ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+| LCMP rreg ',' imm ',' creg
+ {
+ outcode($1, &$2, $6.reg, &$4);
+ }
+/*
+ * rotate and mask
+ */
+| LRLWM imm ',' rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM imm ',' rreg ',' mask ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM rreg ',' rreg ',' imm ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+| LRLWM rreg ',' rreg ',' mask ',' rreg
+ {
+ outgcode($1, &$2, $4.reg, &$6, &$8);
+ }
+/*
+ * load/store multiple
+ */
+| LMOVMW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVMW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * various indexed load/store
+ * indexed unary (eg, cache clear)
+ */
+| LXLD regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXLD regaddr ',' imm ',' rreg
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LXST rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXST rreg ',' imm ',' regaddr
+ {
+ outgcode($1, &$2, NREG, &$4, &$6);
+ }
+| LXMV regaddr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXMV rreg ',' regaddr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LXOP regaddr
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * NOP
+ */
+| LNOP comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LNOP rreg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP freg comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LNOP ',' rreg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LNOP ',' freg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * word
+ */
+| LWORD imm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+| LWORD ximm comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * END
+ */
+| LEND comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTEXT name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTEXT name ',' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTEXT name ',' imm ':' imm
+ {
+ outgcode($1, &$2, NREG, &$6, &$4);
+ }
+| LTEXT name ',' con ',' imm ':' imm
+ {
+ outgcode($1, &$2, $4, &$8, &$6);
+ }
+/*
+ * DATA
+ */
+| LDATA name '/' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' fimm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * RETURN
+ */
+| LRETRN comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+rreg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+xlreg:
+ lr
+| ctr
+
+lr:
+ LLR
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+
+lcr:
+ LCR
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = NREG; /* whole register */
+ }
+
+ctr:
+ LCTR
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+
+msr:
+ LMSR
+ {
+ $$ = nullgen;
+ $$.type = D_MSR;
+ }
+
+psr:
+ LSPREG
+ {
+ $$ = nullgen;
+ $$.type = D_SPR;
+ $$.offset = $1;
+ }
+| LSPR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = $1;
+ $$.offset = $3;
+ }
+| msr
+
+seg:
+ LSEG '(' con ')'
+ {
+ if($3 < 0 || $3 > 15)
+ yyerror("segment register number out of range");
+ $$ = nullgen;
+ $$.type = D_SREG;
+ $$.reg = $3;
+ $$.offset = NREG;
+ }
+| LSEG '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_SREG;
+ $$.reg = NREG;
+ $$.offset = $3;
+ }
+
+fpscr:
+ LFPSCR
+ {
+ $$ = nullgen;
+ $$.type = D_FPSCR;
+ $$.reg = NREG;
+ }
+
+fpscrf:
+ LFPSCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FPSCR;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+creg:
+ LCREG
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $1;
+ }
+| LCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_CREG;
+ $$.reg = $3;
+ }
+
+
+cbit: con
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+mask:
+ con ',' con
+ {
+ int mb, me;
+ ulong v;
+
+ $$ = nullgen;
+ $$.type = D_CONST;
+ mb = $1;
+ me = $3;
+ if(mb < 0 || mb > 31 || me < 0 || me > 31){
+ yyerror("illegal mask start/end value(s)");
+ mb = me = 0;
+ }
+ if(mb <= me)
+ v = ((ulong)~0L>>mb) & (~0L<<(31-me));
+ else
+ v = ~(((ulong)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
+ $$.offset = v;
+ }
+
+ximm:
+ '$' addr
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+
+fimm:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+sreg:
+ LREG
+| LR '(' con ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+regaddr:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| '(' sreg '+' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.xreg = $4;
+ $$.offset = 0;
+ }
+
+addr:
+ name
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+comma:
+| ','
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/qa/branch b/utils/qa/branch
new file mode 100644
index 00000000..8092a2c5
--- /dev/null
+++ b/utils/qa/branch
@@ -0,0 +1,37 @@
+BO operand encodings
+
+0+y 0000y decrement CTR, then branch if CTR != 0 && condition is false
+2+y 0001y decrement CTR, then branch if CTR == 0 && condition is false
+4+y 0010y branch if condition is false
+8+y 0100y decrement CTR, then branch if CTR != 0 && condition is true
+10+y 0101y decrement CTR, then branch if CTR == 0 && condition is true
+12+y 0110y branch if condition is true
+16+y 1000y decrement CTR, then branch if CTR != 0
+18+y 1001y decrement CTR, then branch if CTR == 0
+20 10100 branch always
+
+y=0:
+ BCx with negative displacement: branch probably taken
+ all other cases: branch not taken
+
+y=1:
+ reverse prediction
+
+predict to be taken if
+ ((BO[0] & BO[2]) | sign(displacement)) xor y
+
+CR field bit:
+
+lt 0
+gt 1
+eq 2
+so 3
+un 3 (after fp comparison)
+
+CR fields:
+
+cr0 0
+cr1 4
+cr2 8
+...
+cr7 28
diff --git a/utils/qa/lex.c b/utils/qa/lex.c
new file mode 100644
index 00000000..228ec4e1
--- /dev/null
+++ b/utils/qa/lex.c
@@ -0,0 +1,856 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = 'q';
+ thestring = "power";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p);
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ if(p = strrchr(ofile, pathchar())) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(p = strrchr(outfile, '.'))
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = strrchr(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ nosched = 0;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ nosched = 0;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "LR", LLR, D_LR,
+ "CTR", LCTR, D_CTR,
+
+ "XER", LSPREG, D_XER,
+ "MSR", LMSR, D_MSR,
+ "FPSCR", LFPSCR, D_FPSCR,
+ "SPR", LSPR, D_SPR,
+ "DCR", LSPR, D_DCR,
+
+ "SEG", LSEG, D_SREG,
+
+ "CR", LCR, 0,
+ "CR0", LCREG, 0,
+ "CR1", LCREG, 1,
+ "CR2", LCREG, 2,
+ "CR3", LCREG, 3,
+ "CR4", LCREG, 4,
+ "CR5", LCREG, 5,
+ "CR6", LCREG, 6,
+ "CR7", LCREG, 7,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+ "R16", LREG, 16,
+ "R17", LREG, 17,
+ "R18", LREG, 18,
+ "R19", LREG, 19,
+ "R20", LREG, 20,
+ "R21", LREG, 21,
+ "R22", LREG, 22,
+ "R23", LREG, 23,
+ "R24", LREG, 24,
+ "R25", LREG, 25,
+ "R26", LREG, 26,
+ "R27", LREG, 27,
+ "R28", LREG, 28,
+ "R29", LREG, 29,
+ "R30", LREG, 30,
+ "R31", LREG, 31,
+
+ "F", LF, 0,
+ "F0", LFREG, 0,
+ "F1", LFREG, 1,
+ "F2", LFREG, 2,
+ "F3", LFREG, 3,
+ "F4", LFREG, 4,
+ "F5", LFREG, 5,
+ "F6", LFREG, 6,
+ "F7", LFREG, 7,
+ "F8", LFREG, 8,
+ "F9", LFREG, 9,
+ "F10", LFREG, 10,
+ "F11", LFREG, 11,
+ "F12", LFREG, 12,
+ "F13", LFREG, 13,
+ "F14", LFREG, 14,
+ "F15", LFREG, 15,
+ "F16", LFREG, 16,
+ "F17", LFREG, 17,
+ "F18", LFREG, 18,
+ "F19", LFREG, 19,
+ "F20", LFREG, 20,
+ "F21", LFREG, 21,
+ "F22", LFREG, 22,
+ "F23", LFREG, 23,
+ "F24", LFREG, 24,
+ "F25", LFREG, 25,
+ "F26", LFREG, 26,
+ "F27", LFREG, 27,
+ "F28", LFREG, 28,
+ "F29", LFREG, 29,
+ "F30", LFREG, 30,
+ "F31", LFREG, 31,
+
+ "CREQV", LCROP, ACREQV,
+ "CRXOR", LCROP, ACRXOR,
+ "CRAND", LCROP, ACRAND,
+ "CROR", LCROP, ACROR,
+ "CRANDN", LCROP, ACRANDN,
+ "CRORN", LCROP, ACRORN,
+ "CRNAND", LCROP, ACRNAND,
+ "CRNOR", LCROP, ACRNOR,
+
+ "ADD", LADDW, AADD,
+ "ADDV", LADDW, AADDV,
+ "ADDCC", LADDW, AADDCC,
+ "ADDVCC", LADDW, AADDVCC,
+ "ADDC", LADDW, AADDC,
+ "ADDCV", LADDW, AADDCV,
+ "ADDCCC", LADDW, AADDCCC,
+ "ADDCVCC", LADDW, AADDCVCC,
+ "ADDE", LLOGW, AADDE,
+ "ADDEV", LLOGW, AADDEV,
+ "ADDECC", LLOGW, AADDECC,
+ "ADDEVCC", LLOGW, AADDEVCC,
+
+ "ADDME", LABS, AADDME,
+ "ADDMEV", LABS, AADDMEV,
+ "ADDMECC", LABS, AADDMECC,
+ "ADDMEVCC", LABS, AADDMEVCC,
+ "ADDZE", LABS, AADDZE,
+ "ADDZEV", LABS, AADDZEV,
+ "ADDZECC", LABS, AADDZECC,
+ "ADDZEVCC", LABS, AADDZEVCC,
+
+ "SUB", LADDW, ASUB,
+ "SUBV", LADDW, ASUBV,
+ "SUBCC", LADDW, ASUBCC,
+ "SUBVCC", LADDW, ASUBVCC,
+ "SUBE", LLOGW, ASUBE,
+ "SUBECC", LLOGW, ASUBECC,
+ "SUBEV", LLOGW, ASUBEV,
+ "SUBEVCC", LLOGW, ASUBEVCC,
+ "SUBC", LADDW, ASUBC,
+ "SUBCCC", LADDW, ASUBCCC,
+ "SUBCV", LADDW, ASUBCV,
+ "SUBCVCC", LADDW, ASUBCVCC,
+
+ "SUBME", LABS, ASUBME,
+ "SUBMEV", LABS, ASUBMEV,
+ "SUBMECC", LABS, ASUBMECC,
+ "SUBMEVCC", LABS, ASUBMEVCC,
+ "SUBZE", LABS, ASUBZE,
+ "SUBZEV", LABS, ASUBZEV,
+ "SUBZECC", LABS, ASUBZECC,
+ "SUBZEVCC", LABS, ASUBZEVCC,
+
+ "AND", LADDW, AAND,
+ "ANDCC", LADDW, AANDCC, /* includes andil & andiu */
+ "ANDN", LLOGW, AANDN,
+ "ANDNCC", LLOGW, AANDNCC,
+ "EQV", LLOGW, AEQV,
+ "EQVCC", LLOGW, AEQVCC,
+ "NAND", LLOGW, ANAND,
+ "NANDCC", LLOGW, ANANDCC,
+ "NOR", LLOGW, ANOR,
+ "NORCC", LLOGW, ANORCC,
+ "OR", LADDW, AOR, /* includes oril & oriu */
+ "ORCC", LADDW, AORCC,
+ "ORN", LLOGW, AORN,
+ "ORNCC", LLOGW, AORNCC,
+ "XOR", LADDW, AXOR, /* includes xoril & xoriu */
+ "XORCC", LLOGW, AXORCC,
+
+ "EXTSB", LABS, AEXTSB,
+ "EXTSBCC", LABS, AEXTSBCC,
+ "EXTSH", LABS, AEXTSH,
+ "EXTSHCC", LABS, AEXTSHCC,
+
+ "CNTLZW", LABS, ACNTLZW,
+ "CNTLZWCC", LABS, ACNTLZWCC,
+
+ "RLWMI", LRLWM, ARLWMI,
+ "RLWMICC", LRLWM, ARLWMICC,
+ "RLWNM", LRLWM, ARLWNM,
+ "RLWNMCC", LRLWM, ARLWNMCC,
+
+ "SLW", LSHW, ASLW,
+ "SLWCC", LSHW, ASLWCC,
+ "SRW", LSHW, ASRW,
+ "SRWCC", LSHW, ASRWCC,
+ "SRAW", LSHW, ASRAW,
+ "SRAWCC", LSHW, ASRAWCC,
+
+ "BR", LBRA, ABR,
+ "BC", LBRA, ABC,
+ "BCL", LBRA, ABC,
+ "BL", LBRA, ABL,
+ "BEQ", LBRA, ABEQ,
+ "BNE", LBRA, ABNE,
+ "BGT", LBRA, ABGT,
+ "BGE", LBRA, ABGE,
+ "BLT", LBRA, ABLT,
+ "BLE", LBRA, ABLE,
+ "BVC", LBRA, ABVC,
+ "BVS", LBRA, ABVS,
+
+ "CMP", LCMP, ACMP,
+ "CMPU", LCMP, ACMPU,
+
+ "DIVW", LLOGW, ADIVW,
+ "DIVWV", LLOGW, ADIVWV,
+ "DIVWCC", LLOGW, ADIVWCC,
+ "DIVWVCC", LLOGW, ADIVWVCC,
+ "DIVWU", LLOGW, ADIVWU,
+ "DIVWUV", LLOGW, ADIVWUV,
+ "DIVWUCC", LLOGW, ADIVWUCC,
+ "DIVWUVCC", LLOGW, ADIVWUVCC,
+
+ "FABS", LFCONV, AFABS,
+ "FABSCC", LFCONV, AFABSCC,
+ "FNEG", LFCONV, AFNEG,
+ "FNEGCC", LFCONV, AFNEGCC,
+ "FNABS", LFCONV, AFNABS,
+ "FNABSCC", LFCONV, AFNABSCC,
+
+ "FADD", LFADD, AFADD,
+ "FADDCC", LFADD, AFADDCC,
+ "FSUB", LFADD, AFSUB,
+ "FSUBCC", LFADD, AFSUBCC,
+ "FMUL", LFADD, AFMUL,
+ "FMULCC", LFADD, AFMULCC,
+ "FDIV", LFADD, AFDIV,
+ "FDIVCC", LFADD, AFDIVCC,
+ "FRSP", LFCONV, AFRSP,
+ "FRSPCC", LFCONV, AFRSPCC,
+
+ "FMADD", LFMA, AFMADD,
+ "FMADDCC", LFMA, AFMADDCC,
+ "FMSUB", LFMA, AFMSUB,
+ "FMSUBCC", LFMA, AFMSUBCC,
+ "FNMADD", LFMA, AFNMADD,
+ "FNMADDCC", LFMA, AFNMADDCC,
+ "FNMSUB", LFMA, AFNMSUB,
+ "FNMSUBCC", LFMA, AFNMSUBCC,
+ "FMADDS", LFMA, AFMADDS,
+ "FMADDSCC", LFMA, AFMADDSCC,
+ "FMSUBS", LFMA, AFMSUBS,
+ "FMSUBSCC", LFMA, AFMSUBSCC,
+ "FNMADDS", LFMA, AFNMADDS,
+ "FNMADDSCC", LFMA, AFNMADDSCC,
+ "FNMSUBS", LFMA, AFNMSUBS,
+ "FNMSUBSCC", LFMA, AFNMSUBSCC,
+
+ "FCMPU", LFCMP, AFCMPU,
+ "FCMPO", LFCMP, AFCMPO,
+ "MTFSB0", LMTFSB, AMTFSB0,
+ "MTFSB1", LMTFSB, AMTFSB1,
+
+ "FMOVD", LFMOV, AFMOVD,
+ "FMOVS", LFMOV, AFMOVS,
+ "FMOVDCC", LFCONV, AFMOVDCC, /* fmr. */
+
+ "GLOBL", LTEXT, AGLOBL,
+
+ "MOVB", LMOVB, AMOVB,
+ "MOVBZ", LMOVB, AMOVBZ,
+ "MOVBU", LMOVB, AMOVBU,
+ "MOVBZU", LMOVB, AMOVBZU,
+ "MOVH", LMOVB, AMOVH,
+ "MOVHZ", LMOVB, AMOVHZ,
+ "MOVHU", LMOVB, AMOVHU,
+ "MOVHZU", LMOVB, AMOVHZU,
+ "MOVHBR", LXMV, AMOVHBR,
+ "MOVWBR", LXMV, AMOVWBR,
+ "MOVW", LMOVW, AMOVW,
+ "MOVWU", LMOVW, AMOVWU,
+ "MOVMW", LMOVMW, AMOVMW,
+ "MOVFL", LMOVW, AMOVFL,
+
+ "MULLW", LADDW, AMULLW, /* includes multiply immediate 10-139 */
+ "MULLWV", LLOGW, AMULLWV,
+ "MULLWCC", LLOGW, AMULLWCC,
+ "MULLWVCC", LLOGW, AMULLWVCC,
+
+ "MULHW", LLOGW, AMULHW,
+ "MULHWCC", LLOGW, AMULHWCC,
+ "MULHWU", LLOGW, AMULHWU,
+ "MULHWUCC", LLOGW, AMULHWUCC,
+
+ "NEG", LABS, ANEG,
+ "NEGV", LABS, ANEGV,
+ "NEGCC", LABS, ANEGCC,
+ "NEGVCC", LABS, ANEGVCC,
+
+ "NOP", LNOP, ANOP, /* ori 0,0,0 */
+ "SYSCALL", LNOP, ASYSCALL,
+
+ "RETURN", LRETRN, ARETURN,
+ "RFI", LRETRN, ARFI,
+ "RFCI", LRETRN, ARFCI,
+
+ "DATA", LDATA, ADATA,
+ "END", LEND, AEND,
+ "TEXT", LTEXT, ATEXT,
+
+ /* IBM powerpc embedded */
+ "MACCHW", LMA, AMACCHW,
+ "MACCHWCC", LMA, AMACCHWCC,
+ "MACCHWS", LMA, AMACCHWS,
+ "MACCHWSCC", LMA, AMACCHWSCC,
+ "MACCHWSU", LMA, AMACCHWSU,
+ "MACCHWSUCC", LMA, AMACCHWSUCC,
+ "MACCHWSUV", LMA, AMACCHWSUV,
+ "MACCHWSUVCC", LMA, AMACCHWSUVCC,
+ "MACCHWSV", LMA, AMACCHWSV,
+ "MACCHWSVCC", LMA, AMACCHWSVCC,
+ "MACCHWU", LMA, AMACCHWU,
+ "MACCHWUCC", LMA, AMACCHWUCC,
+ "MACCHWUV", LMA, AMACCHWUV,
+ "MACCHWUVCC", LMA, AMACCHWUVCC,
+ "MACCHWV", LMA, AMACCHWV,
+ "MACCHWVCC", LMA, AMACCHWVCC,
+ "MACHHW", LMA, AMACHHW,
+ "MACHHWCC", LMA, AMACHHWCC,
+ "MACHHWS", LMA, AMACHHWS,
+ "MACHHWSCC", LMA, AMACHHWSCC,
+ "MACHHWSU", LMA, AMACHHWSU,
+ "MACHHWSUCC", LMA, AMACHHWSUCC,
+ "MACHHWSUV", LMA, AMACHHWSUV,
+ "MACHHWSUVCC", LMA, AMACHHWSUVCC,
+ "MACHHWSV", LMA, AMACHHWSV,
+ "MACHHWSVCC", LMA, AMACHHWSVCC,
+ "MACHHWU", LMA, AMACHHWU,
+ "MACHHWUCC", LMA, AMACHHWUCC,
+ "MACHHWUV", LMA, AMACHHWUV,
+ "MACHHWUVCC", LMA, AMACHHWUVCC,
+ "MACHHWV", LMA, AMACHHWV,
+ "MACHHWVCC", LMA, AMACHHWVCC,
+ "MACLHW", LMA, AMACLHW,
+ "MACLHWCC", LMA, AMACLHWCC,
+ "MACLHWS", LMA, AMACLHWS,
+ "MACLHWSCC", LMA, AMACLHWSCC,
+ "MACLHWSU", LMA, AMACLHWSU,
+ "MACLHWSUCC", LMA, AMACLHWSUCC,
+ "MACLHWSUV", LMA, AMACLHWSUV,
+ "MACLHWSUVCC", LMA, AMACLHWSUVCC,
+ "MACLHWSV", LMA, AMACLHWSV,
+ "MACLHWSVCC", LMA, AMACLHWSVCC,
+ "MACLHWU", LMA, AMACLHWU,
+ "MACLHWUCC", LMA, AMACLHWUCC,
+ "MACLHWUV", LMA, AMACLHWUV,
+ "MACLHWUVCC", LMA, AMACLHWUVCC,
+ "MACLHWV", LMA, AMACLHWV,
+ "MACLHWVCC", LMA, AMACLHWVCC,
+ "MULCHW", LLOGW, AMULCHW,
+ "MULCHWCC", LLOGW, AMULCHWCC,
+ "MULCHWU", LLOGW, AMULCHWU,
+ "MULCHWUCC", LLOGW, AMULCHWUCC,
+ "MULHHW", LLOGW, AMULHHW,
+ "MULHHWCC", LLOGW, AMULHHWCC,
+ "MULHHWU", LLOGW, AMULHHWU,
+ "MULHHWUCC", LLOGW, AMULHHWUCC,
+ "MULLHW", LLOGW, AMULLHW,
+ "MULLHWCC", LLOGW, AMULLHWCC,
+ "MULLHWU", LLOGW, AMULLHWU,
+ "MULLHWUCC", LLOGW, AMULLHWUCC,
+ "NMACCHW", LMA, ANMACCHW,
+ "NMACCHWCC", LMA, ANMACCHWCC,
+ "NMACCHWS", LMA, ANMACCHWS,
+ "NMACCHWSCC", LMA, ANMACCHWSCC,
+ "NMACCHWSV", LMA, ANMACCHWSV,
+ "NMACCHWSVCC", LMA, ANMACCHWSVCC,
+ "NMACCHWV", LMA, ANMACCHWV,
+ "NMACCHWVCC", LMA, ANMACCHWVCC,
+ "NMACHHW", LMA, ANMACHHW,
+ "NMACHHWCC", LMA, ANMACHHWCC,
+ "NMACHHWS", LMA, ANMACHHWS,
+ "NMACHHWSCC", LMA, ANMACHHWSCC,
+ "NMACHHWSV", LMA, ANMACHHWSV,
+ "NMACHHWSVCC", LMA, ANMACHHWSVCC,
+ "NMACHHWV", LMA, ANMACHHWV,
+ "NMACHHWVCC", LMA, ANMACHHWVCC,
+ "NMACLHW", LMA, ANMACLHW,
+ "NMACLHWCC", LMA, ANMACLHWCC,
+ "NMACLHWS", LMA, ANMACLHWS,
+ "NMACLHWSCC", LMA, ANMACLHWSCC,
+ "NMACLHWSV", LMA, ANMACLHWSV,
+ "NMACLHWSVCC", LMA, ANMACLHWSVCC,
+ "NMACLHWV", LMA, ANMACLHWV,
+ "NMACLHWVCC", LMA, ANMACLHWVCC,
+
+/* special instructions */
+ "DCBF", LXOP, ADCBF,
+ "DCBI", LXOP, ADCBI,
+ "DCBST", LXOP, ADCBST,
+ "DCBT", LXOP, ADCBT,
+ "DCBTST", LXOP, ADCBTST,
+ "DCBZ", LXOP, ADCBZ,
+ "ICBI", LXOP, AICBI,
+
+ "ECIWX", LXLD, AECIWX,
+ "ECOWX", LXST, AECOWX,
+ "LWAR", LXLD, ALWAR,
+ "STWCCC", LXST, ASTWCCC,
+ "EIEIO", LRETRN, AEIEIO,
+ "TLBIE", LNOP, ATLBIE,
+ "LSW", LXLD, ALSW,
+ "STSW", LXST, ASTSW,
+
+ "ISYNC", LRETRN, AISYNC,
+ "SYNC", LRETRN, ASYNC,
+/* "TW", LADDW, ATW,*/
+
+ "WORD", LWORD, AWORD,
+ "SCHED", LSCHED, 0,
+ "NOSCHED", LSCHED, 0x80,
+
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ nullgen.xreg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+ ALLOCN(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ ALLOCN(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_CREG:
+ case D_FPSCR:
+ case D_MSR:
+ case D_SREG:
+ case D_OPT:
+ break;
+
+ case D_SPR:
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+ }
+}
+
+int
+outsim(Gen *g)
+{
+ Sym *s;
+ int sno, t;
+
+ s = g->sym;
+ if(s == S)
+ return 0;
+ sno = s->sym;
+ if(sno < 0 || sno >= NSYM)
+ sno = 0;
+ t = g->name;
+ if(h[sno].type == t && h[sno].sym == s)
+ return sno;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sno = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ return sno;
+}
+
+void
+outcode(int a, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st;
+
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+ if(pass == 1)
+ return;
+ if(g1->xreg != NREG) {
+ if(reg != NREG || g2->xreg != NREG)
+ yyerror("bad addressing modes");
+ reg = g1->xreg;
+ } else
+ if(g2->xreg != NREG) {
+ if(reg != NREG)
+ yyerror("bad addressing modes");
+ reg = g2->xreg;
+ }
+ do {
+ sf = outsim(g1);
+ st = outsim(g2);
+ } while(sf != 0 && st == sf);
+ Bputc(&obuf, a);
+ Bputc(&obuf, reg|nosched);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+}
+
+void
+outgcode(int a, Gen *g1, int reg, Gen *g2, Gen *g3)
+{
+ int s1, s2, s3, flag;
+
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+ if(pass == 1)
+ return;
+ do {
+ s1 = outsim(g1);
+ s2 = outsim(g2);
+ s3 = outsim(g3);
+ } while(s1 && (s2 && s1 == s2 || s3 && s1 == s3) || s2 && (s3 && s2 == s3));
+ flag = 0;
+ if(g2->type != D_NONE)
+ flag = 0x40; /* flags extra operand */
+ Bputc(&obuf, a);
+ Bputc(&obuf, reg | nosched | flag);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, s1);
+ if(flag)
+ zaddr(g2, s2);
+ zaddr(g3, s3);
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/qa/mkfile b/utils/qa/mkfile
new file mode 100644
index 00000000..255701f8
--- /dev/null
+++ b/utils/qa/mkfile
@@ -0,0 +1,29 @@
+<../../mkconfig
+
+TARG=qa
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../qc/q.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/qc/cgen.c b/utils/qc/cgen.c
new file mode 100644
index 00000000..8323466c
--- /dev/null
+++ b/utils/qc/cgen.c
@@ -0,0 +1,1091 @@
+#include "gc.h"
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o;
+ long v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED) {
+ if(nn != Z || r->addable < INDEXED) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OXOR:
+ if(nn != Z)
+ if(r->op == OCONST && r->vconst == -1){
+ cgen(l, nn);
+ gopcode(OCOM, nn, Z, nn);
+ break;
+ }
+
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OMUL:
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case ODIV:
+ case OMOD:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ if(debug['M'])
+ print("%L multiply\n", n->lineno);
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[r->type->etype])
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, n, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, n, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+ regalloc(&nod1, n, Z);
+ gopcode(OAS, &nod2, Z, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ regalloc(&nod3, r, Z);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ cgen(r, &nod3);
+ } else {
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(n->op, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ cgen(l, nn);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ if(n->op == OCONST) {
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ nodreg(&nod1, n, NREG+FREGZERO);
+ gopcode(o, &nod, Z, &nod1);
+ } else
+ gopcode(o, &nod, Z, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(sconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, Z, r);
+ regfree(&nod);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod1, Z, &nod);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1L), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0L), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no side effects
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regalloc(&nod2, &nod1, Z);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ /* prtree(&nod0, "hand craft"); /* */
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ /* BOTCH -- functions can clobber rathole */
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 5) {
+ layout(&nod1, &nod2, w, 0, Z);
+ goto out;
+ }
+
+ /*
+ * minimize space for unrolling loop
+ * 3,4,5 times. (6 or more is never minimum)
+ * if small structure, try 2 also.
+ */
+ c = 0; /* set */
+ m = 100;
+ i = 3;
+ if(w <= 15)
+ i = 2;
+ for(; i<=5; i++)
+ if(i + w%i <= m) {
+ c = i;
+ m = c + w%c;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ layout(&nod1, &nod2, w%c, w/c, &nod3);
+
+ pc1 = pc;
+ layout(&nod1, &nod2, c, 0, Z);
+
+ gopcode(OSUB, nodconst(1L), Z, &nod3);
+ nod1.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
+ nod2.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
+
+ gopcode(OGT, &nod3, Z, nodconst(0));
+ patch(p, pc1);
+
+ regfree(&nod3);
+out:
+ regfree(&nod1);
+ regfree(&nod2);
+}
+
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, &regnode, Z);
+ regalloc(&t2, &regnode, Z);
+ if(c > 0) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(cn != Z)
+ gopcode(OAS, nodconst(cv), Z, cn);
+ if(c > 1) {
+ gopcode(OAS, f, Z, &t2);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 0) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 1) {
+ gopcode(OAS, &t2, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
diff --git a/utils/qc/enam.c b/utils/qc/enam.c
new file mode 100644
index 00000000..70535f8a
--- /dev/null
+++ b/utils/qc/enam.c
@@ -0,0 +1,327 @@
+char *anames[] =
+{
+ "XXX",
+ "ADD",
+ "ADDCC",
+ "ADDV",
+ "ADDVCC",
+ "ADDC",
+ "ADDCCC",
+ "ADDCV",
+ "ADDCVCC",
+ "ADDME",
+ "ADDMECC",
+ "ADDMEVCC",
+ "ADDMEV",
+ "ADDE",
+ "ADDECC",
+ "ADDEVCC",
+ "ADDEV",
+ "ADDZE",
+ "ADDZECC",
+ "ADDZEVCC",
+ "ADDZEV",
+ "AND",
+ "ANDCC",
+ "ANDN",
+ "ANDNCC",
+ "BC",
+ "BCL",
+ "BEQ",
+ "BGE",
+ "BGT",
+ "BL",
+ "BLE",
+ "BLT",
+ "BNE",
+ "BR",
+ "BVC",
+ "BVS",
+ "CMP",
+ "CMPU",
+ "CNTLZW",
+ "CNTLZWCC",
+ "CRAND",
+ "CRANDN",
+ "CREQV",
+ "CRNAND",
+ "CRNOR",
+ "CROR",
+ "CRORN",
+ "CRXOR",
+ "DIVW",
+ "DIVWCC",
+ "DIVWVCC",
+ "DIVWV",
+ "DIVWU",
+ "DIVWUCC",
+ "DIVWUVCC",
+ "DIVWUV",
+ "EQV",
+ "EQVCC",
+ "EXTSB",
+ "EXTSBCC",
+ "EXTSH",
+ "EXTSHCC",
+ "FABS",
+ "FABSCC",
+ "FADD",
+ "FADDCC",
+ "FADDS",
+ "FADDSCC",
+ "FCMPO",
+ "FCMPU",
+ "FCTIW",
+ "FCTIWCC",
+ "FCTIWZ",
+ "FCTIWZCC",
+ "FDIV",
+ "FDIVCC",
+ "FDIVS",
+ "FDIVSCC",
+ "FMADD",
+ "FMADDCC",
+ "FMADDS",
+ "FMADDSCC",
+ "FMOVD",
+ "FMOVDCC",
+ "FMOVDU",
+ "FMOVS",
+ "FMOVSU",
+ "FMSUB",
+ "FMSUBCC",
+ "FMSUBS",
+ "FMSUBSCC",
+ "FMUL",
+ "FMULCC",
+ "FMULS",
+ "FMULSCC",
+ "FNABS",
+ "FNABSCC",
+ "FNEG",
+ "FNEGCC",
+ "FNMADD",
+ "FNMADDCC",
+ "FNMADDS",
+ "FNMADDSCC",
+ "FNMSUB",
+ "FNMSUBCC",
+ "FNMSUBS",
+ "FNMSUBSCC",
+ "FRSP",
+ "FRSPCC",
+ "FSUB",
+ "FSUBCC",
+ "FSUBS",
+ "FSUBSCC",
+ "MOVMW",
+ "LSW",
+ "LWAR",
+ "MOVWBR",
+ "MOVB",
+ "MOVBU",
+ "MOVBZ",
+ "MOVBZU",
+ "MOVH",
+ "MOVHBR",
+ "MOVHU",
+ "MOVHZ",
+ "MOVHZU",
+ "MOVW",
+ "MOVWU",
+ "MOVFL",
+ "MOVCRFXXX",
+ "MOVCRFS",
+ "MOVCRXRXXX",
+ "MOVFCRXXX",
+ "MFFSXXX",
+ "MFFSCCXXX",
+ "MTCRFXXX",
+ "MTFSB0",
+ "MTFSB0CC",
+ "MTFSB1",
+ "MTFSB1CC",
+ "MTFSFXXX",
+ "MTFSFCCXXX",
+ "MTFSFIXXX",
+ "MTFSFIXXXCC",
+ "MULHW",
+ "MULHWCC",
+ "MULHWU",
+ "MULHWUCC",
+ "MULLW",
+ "MULLWCC",
+ "MULLWVCC",
+ "MULLWV",
+ "NAND",
+ "NANDCC",
+ "NEG",
+ "NEGCC",
+ "NEGVCC",
+ "NEGV",
+ "NOR",
+ "NORCC",
+ "OR",
+ "ORCC",
+ "ORN",
+ "ORNCC",
+ "REM",
+ "REMCC",
+ "REMV",
+ "REMVCC",
+ "REMU",
+ "REMUCC",
+ "REMUV",
+ "REMUVCC",
+ "RFI",
+ "RLWMI",
+ "RLWMICC",
+ "RLWNM",
+ "RLWNMCC",
+ "SLW",
+ "SLWCC",
+ "SRW",
+ "SRAW",
+ "SRAWCC",
+ "SRWCC",
+ "ILLXXX1",
+ "STSW",
+ "STWBRXXX",
+ "STWCCC",
+ "SUB",
+ "SUBCC",
+ "SUBVCC",
+ "SUBC",
+ "SUBCCC",
+ "SUBCV",
+ "SUBCVCC",
+ "SUBME",
+ "SUBMECC",
+ "SUBMEVCC",
+ "SUBMEV",
+ "SUBV",
+ "SUBE",
+ "SUBECC",
+ "SUBEV",
+ "SUBEVCC",
+ "SUBZE",
+ "SUBZECC",
+ "SUBZEVCC",
+ "SUBZEV",
+ "SYNC",
+ "XOR",
+ "XORCC",
+ "DCBF",
+ "DCBI",
+ "DCBST",
+ "DCBT",
+ "DCBTST",
+ "DCBZ",
+ "ECIWX",
+ "ECOWX",
+ "EIEIO",
+ "ICBI",
+ "ISYNC",
+ "TLBIE",
+ "TW",
+ "SYSCALL",
+ "DATA",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "NAME",
+ "NOP",
+ "RETURN",
+ "TEXT",
+ "WORD",
+ "END",
+ "DYNT",
+ "INIT",
+ "SIGNAME",
+ "MACCHW",
+ "MACCHWCC",
+ "MACCHWS",
+ "MACCHWSCC",
+ "MACCHWSU",
+ "MACCHWSUCC",
+ "MACCHWSUV",
+ "MACCHWSUVCC",
+ "MACCHWSV",
+ "MACCHWSVCC",
+ "MACCHWU",
+ "MACCHWUCC",
+ "MACCHWUV",
+ "MACCHWUVCC",
+ "MACCHWV",
+ "MACCHWVCC",
+ "MACHHW",
+ "MACHHWCC",
+ "MACHHWV",
+ "MACHHWVCC",
+ "MACHHWS",
+ "MACHHWSCC",
+ "MACHHWSV",
+ "MACHHWSVCC",
+ "MACHHWSU",
+ "MACHHWSUCC",
+ "MACHHWSUV",
+ "MACHHWSUVCC",
+ "MACHHWU",
+ "MACHHWUCC",
+ "MACHHWUV",
+ "MACHHWUVCC",
+ "MACLHW",
+ "MACLHWCC",
+ "MACLHWS",
+ "MACLHWSCC",
+ "MACLHWSU",
+ "MACLHWSUCC",
+ "MACLHWSUV",
+ "MACLHWSUVCC",
+ "MACLHWSV",
+ "MACLHWSVCC",
+ "MACLHWU",
+ "MACLHWUCC",
+ "MACLHWUV",
+ "MACLHWUVCC",
+ "MACLHWV",
+ "MACLHWVCC",
+ "MULCHW",
+ "MULCHWCC",
+ "MULCHWU",
+ "MULCHWUCC",
+ "MULHHW",
+ "MULHHWCC",
+ "MULHHWU",
+ "MULHHWUCC",
+ "MULLHW",
+ "MULLHWCC",
+ "MULLHWU",
+ "MULLHWUCC",
+ "NMACCHW",
+ "NMACCHWCC",
+ "NMACCHWS",
+ "NMACCHWSCC",
+ "NMACCHWSV",
+ "NMACCHWSVCC",
+ "NMACCHWV",
+ "NMACCHWVCC",
+ "NMACHHW",
+ "NMACHHWCC",
+ "NMACHHWS",
+ "NMACHHWSCC",
+ "NMACHHWSV",
+ "NMACHHWSVCC",
+ "NMACHHWV",
+ "NMACHHWVCC",
+ "NMACLHW",
+ "NMACLHWCC",
+ "NMACLHWS",
+ "NMACLHWSCC",
+ "NMACLHWSV",
+ "NMACLHWSVCC",
+ "NMACLHWV",
+ "NMACLHWVCC",
+ "RFCI",
+ "LAST",
+};
diff --git a/utils/qc/gc.h b/utils/qc/gc.h
new file mode 100644
index 00000000..bf4e9091
--- /dev/null
+++ b/utils/qc/gc.h
@@ -0,0 +1,343 @@
+#include "../cc/cc.h"
+#include "../qc/q.out.h"
+
+/*
+ * qc/power
+ * powerpc
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Adr
+{
+ long offset;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr from3; /* third argument for fmadd, fmsub, ... */
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+ char reg;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ int active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN int hintabsize;
+EXTERN long maxargsafe;
+EXTERN Multab multab[20];
+EXTERN int mnstring;
+EXTERN int retok;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[NREG+NREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 5
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+EXTERN int suppress;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+#define R0ISZERO (debug['0']==0)
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void usedset(Node*, int);
+void noretval(int);
+void xcom(Node*);
+int bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+int sval(long);
+int uconst(Node*);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(void*, void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(Node*, long);
+int mulcon1(Node*, long, Node*);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(void*, void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+/*
+ * com64.c
+ */
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/utils/qc/list.c b/utils/qc/list.c
new file mode 100644
index 00000000..3538c621
--- /dev/null
+++ b/utils/qc/list.c
@@ -0,0 +1,229 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('B', Bconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a <= AEND)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(F%d)(REG)", a, a->reg);
+ break;
+
+ case D_CREG:
+ sprint(str, "C%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(C%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/qc/mkenam b/utils/qc/mkenam
new file mode 100644
index 00000000..6250da92
--- /dev/null
+++ b/utils/qc/mkenam
@@ -0,0 +1,18 @@
+ed - ../qc/q.out.h <<'!'
+v/^ A/d
+g/^ AEND/s//&,/
+g/^ ALAST/s//&,/
+g/[ ]*=.*,/s//,/
+v/,/p
+,s/^ A/ "/
+,s/,.*$/",/
+1i
+char *anames[] =
+{
+.
+,a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/qc/mkfile b/utils/qc/mkfile
new file mode 100644
index 00000000..21933876
--- /dev/null
+++ b/utils/qc/mkfile
@@ -0,0 +1,29 @@
+<../../mkconfig
+
+TARG=qc
+OFILES=\
+ cgen.$O\
+ reg.$O\
+ txt.$O\
+ peep.$O\
+ swt.$O\
+ sgen.$O\
+ list.$O\
+ enam.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ q.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/qc/mul.c b/utils/qc/mul.c
new file mode 100644
index 00000000..6918c1fe
--- /dev/null
+++ b/utils/qc/mul.c
@@ -0,0 +1,609 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(Node *n, long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("%L: multiply table failure %ld\n", n->lineno, v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=6; g++) {
+ if(g >= 6 && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("%L: multiply table failure (g=%d h=%s) %ld\n",
+ n->lineno, g, hint, v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(n, v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/utils/qc/peep.c b/utils/qc/peep.c
new file mode 100644
index 00000000..bb9a2b4f
--- /dev/null
+++ b/utils/qc/peep.c
@@ -0,0 +1,891 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVW || p->as == AFMOVS || p->as == AFMOVD)
+ if(regtyp(&p->to)) {
+ if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(regzer(&p->from))
+ if(p->to.type == D_REG) {
+ p->from.type = D_REG;
+ p->from.reg = REGZERO;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AMOVH:
+ case AMOVHZ:
+ case AMOVB:
+ case AMOVBZ:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+
+ if(debug['Q'] > 1)
+ return; /* allow following code improvement to be suppressed */
+
+ /*
+ * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
+ * when OP can set condition codes correctly
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case ACMP:
+ if(!regzer(&p->to))
+ continue;
+ r1 = r->s1;
+ if(r1 == R)
+ continue;
+ switch(r1->prog->as) {
+ default:
+ continue;
+ case ABCL:
+ case ABC:
+ /* the conditions can be complex and these are currently little used */
+ continue;
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABVC:
+ case ABVS:
+ break;
+ }
+ r1 = r;
+ do
+ r1 = uniqp(r1);
+ while (r1 != R && r1->prog->as == ANOP);
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->to.type != D_REG || p1->to.reg != p->from.reg)
+ continue;
+ switch(p1->as) {
+ case ASUB:
+ case AADD:
+ case AXOR:
+ case AOR:
+ /* irregular instructions */
+ if(p1->from.type == D_CONST)
+ continue;
+ break;
+ }
+ switch(p1->as) {
+ default:
+ continue;
+ case AMOVW:
+ if(p1->from.type != D_REG)
+ continue;
+ continue;
+ case AANDCC:
+ case AANDNCC:
+ case AORCC:
+ case AORNCC:
+ case AXORCC:
+ case ASUBCC:
+ case AADDCC:
+ t = p1->as;
+ break;
+ /* don't deal with floating point instructions for now */
+/*
+ case AFABS: t = AFABSCC; break;
+ case AFADD: t = AFADDCC; break;
+ case AFADDS: t = AFADDSCC; break;
+ case AFCTIW: t = AFCTIWCC; break;
+ case AFCTIWZ: t = AFCTIWZCC; break;
+ case AFDIV: t = AFDIVCC; break;
+ case AFDIVS: t = AFDIVSCC; break;
+ case AFMADD: t = AFMADDCC; break;
+ case AFMADDS: t = AFMADDSCC; break;
+ case AFMOVD: t = AFMOVDCC; break;
+ case AFMSUB: t = AFMSUBCC; break;
+ case AFMSUBS: t = AFMSUBSCC; break;
+ case AFMUL: t = AFMULCC; break;
+ case AFMULS: t = AFMULSCC; break;
+ case AFNABS: t = AFNABSCC; break;
+ case AFNEG: t = AFNEGCC; break;
+ case AFNMADD: t = AFNMADDCC; break;
+ case AFNMADDS: t = AFNMADDSCC; break;
+ case AFNMSUB: t = AFNMSUBCC; break;
+ case AFNMSUBS: t = AFNMSUBSCC; break;
+ case AFRSP: t = AFRSPCC; break;
+ case AFSUB: t = AFSUBCC; break;
+ case AFSUBS: t = AFSUBSCC; break;
+ case ACNTLZW: t = ACNTLZWCC; break;
+ case AMTFSB0: t = AMTFSB0CC; break;
+ case AMTFSB1: t = AMTFSB1CC; break;
+*/
+ case AADD: t = AADDCC; break;
+ case AADDV: t = AADDVCC; break;
+ case AADDC: t = AADDCCC; break;
+ case AADDCV: t = AADDCVCC; break;
+ case AADDME: t = AADDMECC; break;
+ case AADDMEV: t = AADDMEVCC; break;
+ case AADDE: t = AADDECC; break;
+ case AADDEV: t = AADDEVCC; break;
+ case AADDZE: t = AADDZECC; break;
+ case AADDZEV: t = AADDZEVCC; break;
+ case AAND: t = AANDCC; break;
+ case AANDN: t = AANDNCC; break;
+ case ADIVW: t = ADIVWCC; break;
+ case ADIVWV: t = ADIVWVCC; break;
+ case ADIVWU: t = ADIVWUCC; break;
+ case ADIVWUV: t = ADIVWUVCC; break;
+ case AEQV: t = AEQVCC; break;
+ case AEXTSB: t = AEXTSBCC; break;
+ case AEXTSH: t = AEXTSHCC; break;
+ case AMULHW: t = AMULHWCC; break;
+ case AMULHWU: t = AMULHWUCC; break;
+ case AMULLW: t = AMULLWCC; break;
+ case AMULLWV: t = AMULLWVCC; break;
+ case ANAND: t = ANANDCC; break;
+ case ANEG: t = ANEGCC; break;
+ case ANEGV: t = ANEGVCC; break;
+ case ANOR: t = ANORCC; break;
+ case AOR: t = AORCC; break;
+ case AORN: t = AORNCC; break;
+ case AREM: t = AREMCC; break;
+ case AREMV: t = AREMVCC; break;
+ case AREMU: t = AREMUCC; break;
+ case AREMUV: t = AREMUVCC; break;
+ case ARLWMI: t = ARLWMICC; break;
+ case ARLWNM: t = ARLWNMCC; break;
+ case ASLW: t = ASLWCC; break;
+ case ASRAW: t = ASRAWCC; break;
+ case ASRW: t = ASRWCC; break;
+ case ASUB: t = ASUBCC; break;
+ case ASUBV: t = ASUBVCC; break;
+ case ASUBC: t = ASUBCCC; break;
+ case ASUBCV: t = ASUBCVCC; break;
+ case ASUBME: t = ASUBMECC; break;
+ case ASUBMEV: t = ASUBMEVCC; break;
+ case ASUBE: t = ASUBECC; break;
+ case ASUBEV: t = ASUBEVCC; break;
+ case ASUBZE: t = ASUBZECC; break;
+ case ASUBZEV: t = ASUBZEVCC; break;
+ case AXOR: t = AXORCC; break;
+ break;
+ }
+ if(debug['Q'])
+ print("cmp %P; %P -> ", p1, p);
+ p1->as = t;
+ if(debug['Q'])
+ print("%P\n", p1);
+ excise(r);
+ continue;
+ }
+ }
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+/*
+ * if the system forces R0 to be zero,
+ * convert references to $0 to references to R0.
+ */
+regzer(Adr *a)
+{
+ if(R0ISZERO) {
+ if(a->type == D_CONST)
+ if(a->sym == S)
+ if(a->offset == 0)
+ return 1;
+ if(a->type == D_REG)
+ if(a->reg == REGZERO)
+ return 1;
+ }
+ return 0;
+}
+
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG) {
+ if(!R0ISZERO || a->reg != REGZERO)
+ return 1;
+ return 0;
+ }
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ABL:
+ return 0;
+
+ case AADD:
+ case ASUB:
+ case ASLW:
+ case ASRW:
+ case ASRAW:
+ case AOR:
+ case AORCC:
+ case AORN:
+ case AORNCC:
+ case AAND:
+ case AANDCC:
+ case AANDN:
+ case AANDNCC:
+ case ANAND:
+ case ANANDCC:
+ case ANOR:
+ case ANORCC:
+ case AXOR:
+ case AXORCC:
+ case AMULLW:
+ case ADIVW:
+ case ADIVWU:
+ case AREM:
+ case AREMU:
+ case ANEG:
+ case ANEGCC:
+
+ case AFADD:
+ case AFADDS:
+ case AFSUB:
+ case AFSUBS:
+ case AFMUL:
+ case AFMULS:
+ case AFDIV:
+ case AFDIVS:
+ case AFNEG:
+ case AFNEGCC:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AFMOVS:
+ case AFMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVH:
+ case AMOVHZ:
+ case AMOVB:
+ case AMOVBZ:
+
+ case ANEG:
+ case ANEGCC:
+
+ case AFCTIW:
+ case AFCTIWZ:
+ case AFMOVS:
+ case AFMOVD:
+ case AFRSP:
+ case AFNEG:
+ case AFNEGCC:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case AADD: /* read read write */
+ case ASUB:
+ case ASLW:
+ case ASRW:
+ case ASRAW:
+ case AOR:
+ case AORCC:
+ case AORN:
+ case AORNCC:
+ case AAND:
+ case AANDCC:
+ case AANDN:
+ case AANDNCC:
+ case ANAND:
+ case ANANDCC:
+ case ANOR:
+ case ANORCC:
+ case AXOR:
+ case AMULLW:
+ case ADIVW:
+ case ADIVWU:
+ case AREM:
+ case AREMU:
+
+ case AFADDS:
+ case AFADD:
+ case AFSUBS:
+ case AFSUB:
+ case AFMULS:
+ case AFMUL:
+ case AFDIVS:
+ case AFDIV:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ:
+ case ABGT:
+ case ABGE:
+ case ABLT:
+ case ABLE:
+ case ABNE:
+ case ABVC:
+ case ABVS:
+ break;
+
+ case ACMP: /* read read */
+ case ACMPU:
+ case AFCMPO:
+ case AFCMPU:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case ABR: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARETURN: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case ABL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG) {
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+ }
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+ case AADD:
+ case AADDCC:
+ case ASUB:
+ case ASUBCC:
+ case ASLW:
+ case ASLWCC:
+ case ASRW:
+ case ASRWCC:
+ case ASRAW:
+ case ASRAWCC:
+ case AOR:
+ case AORCC:
+ case AORN:
+ case AORNCC:
+ case AAND:
+ case AANDCC:
+ case AANDN:
+ case AANDNCC:
+ case AXOR:
+ case AXORCC:
+ case ANEG:
+ case ANEGCC:
+ case AMULLW:
+ case AMULLWCC:
+ case ADIVW:
+ case ADIVWCC:
+ case ADIVWU:
+ case ADIVWUCC:
+ case AREM:
+ case AREMCC:
+ case AREMU:
+ case AREMUCC:
+ case ANAND:
+ case ANANDCC:
+ case ANOR:
+ case ANORCC:
+ return D_REG;
+
+ case AFADDS:
+ case AFADDSCC:
+ case AFADD:
+ case AFADDCC:
+ case AFSUBS:
+ case AFSUBSCC:
+ case AFSUB:
+ case AFSUBCC:
+ case AFMULS:
+ case AFMULSCC:
+ case AFMUL:
+ case AFMULCC:
+ case AFDIVS:
+ case AFDIVSCC:
+ case AFDIV:
+ case AFDIVCC:
+ case AFNEG:
+ case AFNEGCC:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v))
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG)
+ if(a->type == D_OREG)
+ if(v->reg == a->reg)
+ return 1;
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v))
+ if(p->from.type == v->type || p->to.type == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v))
+ a->reg = s->reg;
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
diff --git a/utils/qc/q.out.h b/utils/qc/q.out.h
new file mode 100644
index 00000000..795da7f7
--- /dev/null
+++ b/utils/qc/q.out.h
@@ -0,0 +1,426 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 32
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+enum
+{
+ REGZERO = 0, /* set to zero */
+ REGSP = 1,
+ REGSB = 2,
+ REGRET = 3,
+ REGARG = 3,
+ REGMIN = 7, /* register variables allocated from here to REGMAX */
+ REGMAX = 27,
+ REGEXT = 30, /* external registers allocated from here down */
+ REGTMP = 31, /* used by the linker */
+
+ FREGRET = 0,
+ FREGMIN = 17, /* first register variable */
+ FREGEXT = 26, /* first external register */
+ FREGCVI = 27, /* floating conversion constant */
+ FREGZERO = 28, /* both float and double */
+ FREGHALF = 29, /* double */
+ FREGONE = 30, /* double */
+ FREGTWO = 31 /* double */
+/*
+ * GENERAL:
+ *
+ * compiler allocates R3 up as temps
+ * compiler allocates register variables R7-R27
+ * compiler allocates external registers R30 down
+ *
+ * compiler allocates register variables F17-F26
+ * compiler allocates external registers F26 down
+ */
+};
+
+enum as
+{
+ AXXX = 0,
+ AADD,
+ AADDCC,
+ AADDV,
+ AADDVCC,
+ AADDC,
+ AADDCCC,
+ AADDCV,
+ AADDCVCC,
+ AADDME,
+ AADDMECC,
+ AADDMEVCC,
+ AADDMEV,
+ AADDE,
+ AADDECC,
+ AADDEVCC,
+ AADDEV,
+ AADDZE,
+ AADDZECC,
+ AADDZEVCC,
+ AADDZEV,
+ AAND,
+ AANDCC,
+ AANDN,
+ AANDNCC,
+ ABC,
+ ABCL,
+ ABEQ,
+ ABGE,
+ ABGT,
+ ABL,
+ ABLE,
+ ABLT,
+ ABNE,
+ ABR,
+ ABVC,
+ ABVS,
+ ACMP,
+ ACMPU,
+ ACNTLZW,
+ ACNTLZWCC,
+ ACRAND,
+ ACRANDN,
+ ACREQV,
+ ACRNAND,
+ ACRNOR,
+ ACROR,
+ ACRORN,
+ ACRXOR,
+ ADIVW,
+ ADIVWCC,
+ ADIVWVCC,
+ ADIVWV,
+ ADIVWU,
+ ADIVWUCC,
+ ADIVWUVCC,
+ ADIVWUV,
+ AEQV,
+ AEQVCC,
+ AEXTSB,
+ AEXTSBCC,
+ AEXTSH,
+ AEXTSHCC,
+ AFABS,
+ AFABSCC,
+ AFADD,
+ AFADDCC,
+ AFADDS,
+ AFADDSCC,
+ AFCMPO,
+ AFCMPU,
+ AFCTIW,
+ AFCTIWCC,
+ AFCTIWZ,
+ AFCTIWZCC,
+ AFDIV,
+ AFDIVCC,
+ AFDIVS,
+ AFDIVSCC,
+ AFMADD,
+ AFMADDCC,
+ AFMADDS,
+ AFMADDSCC,
+ AFMOVD,
+ AFMOVDCC,
+ AFMOVDU,
+ AFMOVS,
+ AFMOVSU,
+ AFMSUB,
+ AFMSUBCC,
+ AFMSUBS,
+ AFMSUBSCC,
+ AFMUL,
+ AFMULCC,
+ AFMULS,
+ AFMULSCC,
+ AFNABS,
+ AFNABSCC,
+ AFNEG,
+ AFNEGCC,
+ AFNMADD,
+ AFNMADDCC,
+ AFNMADDS,
+ AFNMADDSCC,
+ AFNMSUB,
+ AFNMSUBCC,
+ AFNMSUBS,
+ AFNMSUBSCC,
+ AFRSP,
+ AFRSPCC,
+ AFSUB,
+ AFSUBCC,
+ AFSUBS,
+ AFSUBSCC,
+ AMOVMW,
+ ALSW,
+ ALWAR,
+ AMOVWBR,
+ AMOVB,
+ AMOVBU,
+ AMOVBZ,
+ AMOVBZU,
+ AMOVH,
+ AMOVHBR,
+ AMOVHU,
+ AMOVHZ,
+ AMOVHZU,
+ AMOVW,
+ AMOVWU,
+ AMOVFL,
+ AMOVCRFXXX,
+ AMOVCRFS,
+ AMOVCRXRXXX,
+ AMOVFCRXXX,
+ AMFFSXXX,
+ AMFFSCCXXX,
+ AMTCRFXXX,
+ AMTFSB0,
+ AMTFSB0CC,
+ AMTFSB1,
+ AMTFSB1CC,
+ AMTFSFXXX,
+ AMTFSFCCXXX,
+ AMTFSFIXXX,
+ AMTFSFIXXXCC,
+ AMULHW,
+ AMULHWCC,
+ AMULHWU,
+ AMULHWUCC,
+ AMULLW,
+ AMULLWCC,
+ AMULLWVCC,
+ AMULLWV,
+ ANAND,
+ ANANDCC,
+ ANEG,
+ ANEGCC,
+ ANEGVCC,
+ ANEGV,
+ ANOR,
+ ANORCC,
+ AOR,
+ AORCC,
+ AORN,
+ AORNCC,
+ AREM,
+ AREMCC,
+ AREMV,
+ AREMVCC,
+ AREMU,
+ AREMUCC,
+ AREMUV,
+ AREMUVCC,
+ ARFI,
+ ARLWMI,
+ ARLWMICC,
+ ARLWNM,
+ ARLWNMCC,
+ ASLW,
+ ASLWCC,
+ ASRW,
+ ASRAW,
+ ASRAWCC,
+ ASRWCC,
+ AILLXXX1,
+ ASTSW,
+ ASTWBRXXX,
+ ASTWCCC,
+ ASUB,
+ ASUBCC,
+ ASUBVCC,
+ ASUBC,
+ ASUBCCC,
+ ASUBCV,
+ ASUBCVCC,
+ ASUBME,
+ ASUBMECC,
+ ASUBMEVCC,
+ ASUBMEV,
+ ASUBV,
+ ASUBE,
+ ASUBECC,
+ ASUBEV,
+ ASUBEVCC,
+ ASUBZE,
+ ASUBZECC,
+ ASUBZEVCC,
+ ASUBZEV,
+ ASYNC,
+ AXOR,
+ AXORCC,
+
+ ADCBF,
+ ADCBI,
+ ADCBST,
+ ADCBT,
+ ADCBTST,
+ ADCBZ,
+ AECIWX,
+ AECOWX,
+ AEIEIO,
+ AICBI,
+ AISYNC,
+ ATLBIE,
+ ATW,
+
+ ASYSCALL,
+ ADATA,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ ANAME,
+ ANOP,
+ ARETURN,
+ ATEXT,
+ AWORD,
+ AEND,
+ ADYNT,
+ AINIT,
+ ASIGNAME,
+
+ /* IBM powerpc embedded; not portable */
+ AMACCHW,
+ AMACCHWCC,
+ AMACCHWS,
+ AMACCHWSCC,
+ AMACCHWSU,
+ AMACCHWSUCC,
+ AMACCHWSUV,
+ AMACCHWSUVCC,
+ AMACCHWSV,
+ AMACCHWSVCC,
+ AMACCHWU,
+ AMACCHWUCC,
+ AMACCHWUV,
+ AMACCHWUVCC,
+ AMACCHWV,
+ AMACCHWVCC,
+ AMACHHW,
+ AMACHHWCC,
+ AMACHHWV,
+ AMACHHWVCC,
+ AMACHHWS,
+ AMACHHWSCC,
+ AMACHHWSV,
+ AMACHHWSVCC,
+ AMACHHWSU,
+ AMACHHWSUCC,
+ AMACHHWSUV,
+ AMACHHWSUVCC,
+ AMACHHWU,
+ AMACHHWUCC,
+ AMACHHWUV,
+ AMACHHWUVCC,
+ AMACLHW,
+ AMACLHWCC,
+ AMACLHWS,
+ AMACLHWSCC,
+ AMACLHWSU,
+ AMACLHWSUCC,
+ AMACLHWSUV,
+ AMACLHWSUVCC,
+ AMACLHWSV,
+ AMACLHWSVCC,
+ AMACLHWU,
+ AMACLHWUCC,
+ AMACLHWUV,
+ AMACLHWUVCC,
+ AMACLHWV,
+ AMACLHWVCC,
+ AMULCHW,
+ AMULCHWCC,
+ AMULCHWU,
+ AMULCHWUCC,
+ AMULHHW,
+ AMULHHWCC,
+ AMULHHWU,
+ AMULHHWUCC,
+ AMULLHW,
+ AMULLHWCC,
+ AMULLHWU,
+ AMULLHWUCC,
+ ANMACCHW,
+ ANMACCHWCC,
+ ANMACCHWS,
+ ANMACCHWSCC,
+ ANMACCHWSV,
+ ANMACCHWSVCC,
+ ANMACCHWV,
+ ANMACCHWVCC,
+ ANMACHHW,
+ ANMACHHWCC,
+ ANMACHHWS,
+ ANMACHHWSCC,
+ ANMACHHWSV,
+ ANMACHHWSVCC,
+ ANMACHHWV,
+ ANMACHHWVCC,
+ ANMACLHW,
+ ANMACLHWCC,
+ ANMACLHWS,
+ ANMACLHWSCC,
+ ANMACLHWSV,
+ ANMACLHWSVCC,
+ ANMACLHWV,
+ ANMACLHWVCC,
+
+ ARFCI,
+
+ ALAST
+};
+
+/* type/name */
+enum
+{
+ D_GOK = 0,
+ D_NONE,
+
+/* name */
+ D_EXTERN,
+ D_STATIC,
+ D_AUTO,
+ D_PARAM,
+
+/* type */
+ D_BRANCH,
+ D_OREG,
+ D_CONST,
+ D_FCONST,
+ D_SCONST,
+ D_REG,
+ D_FPSCR,
+ D_MSR,
+ D_FREG,
+ D_CREG,
+ D_SPR,
+ D_SREG, /* segment register */
+ D_OPT, /* branch/trap option */
+ D_FILE,
+ D_FILE1,
+ D_DCR, /* device control register */
+
+/* reg names iff type is D_SPR */
+ D_XER = 1,
+ D_LR = 8,
+ D_CTR = 9
+ /* and many supervisor level registers */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/qc/reg.c b/utils/qc/reg.c
new file mode 100644
index 00000000..c1a900b0
--- /dev/null
+++ b/utils/qc/reg.c
@@ -0,0 +1,1122 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(void *a1, void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = a1;
+ p2 = a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARETURN:
+ case ABR:
+ case ARFI:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVBZ:
+ case AMOVBZU:
+ case AMOVH:
+ case AMOVHBR:
+ case AMOVHU:
+ case AMOVHZ:
+ case AMOVHZU:
+ case AMOVW:
+ case AMOVWU:
+ case AFMOVD:
+ case AFMOVDCC:
+ case AFMOVDU:
+ case AFMOVS:
+ case AFMOVSU:
+ case AFRSP:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] | r->set.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARETURN)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n set = %B; rah = %B; cal = %B\n",
+ r->prog, r->set, r->refahead, r->calahead);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set an not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L$%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L$%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L$%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AFMOVS;
+ if(v->etype == TDOUBLE)
+ p1->as = AFMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBZ;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHZ;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARETURN:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TVLONG:
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(p->to.type == D_FREG && p->as == AMOVW)
+ change = -CINF; /* cant go Rreg to Freg */
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(p->from.type == D_FREG && p->as == AMOVW)
+ change = -CINF; /* cant go Rreg to Freg */
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * track register variables including external registers:
+ * bit reg
+ * 0 R7
+ * 1 R8
+ * ... ...
+ * 21 R28
+ */
+long
+RtoB(int r)
+{
+
+ if(r >= REGMIN && r <= REGMAX)
+ return 1L << (r-REGMIN);
+ return 0;
+}
+
+int
+BtoR(long b)
+{
+ b &= 0x001fffffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + REGMIN;
+}
+
+/*
+ * bit reg
+ * 22 F17
+ * 23 F18
+ * ... ...
+ * 31 F26
+ */
+long
+FtoB(int f)
+{
+ if(f < FREGMIN || f > FREGEXT)
+ return 0;
+ return 1L << (f - FREGMIN + 22);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0xffc00000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 22 + FREGMIN;
+}
diff --git a/utils/qc/sgen.c b/utils/qc/sgen.c
new file mode 100644
index 00000000..d557d375
--- /dev/null
+++ b/utils/qc/sgen.c
@@ -0,0 +1,640 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ }
+ }
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int o, f;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->xoffset = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->xoffset) {
+ patch(p, n->xoffset);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ supgen(n->right->left);
+ gen(n->right->right);
+ }
+ else {
+ gen(n->right->left);
+ supgen(n->right->right);
+ }
+ }
+ else {
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int v;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASASHL;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASHL;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ v = vlog(l);
+ if(v >= 0) {
+ n->op = OASHL;
+ n->left = r;
+ n->right = l;
+ r = l;
+ l = n->left;
+ r->vconst = v;
+ r->type = types[TINT];
+ simplifyshift(n);
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASLSHR;
+ r->vconst = v;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OLSHR;
+ r->vconst = v;
+ r->type = types[TINT];
+ simplifyshift(n);
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ v = vlog(r);
+ if(v >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ simplifyshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+ return 0;
+}
diff --git a/utils/qc/swt.c b/utils/qc/swt.c
new file mode 100644
index 00000000..9bf0e58e
--- /dev/null
+++ b/utils/qc/swt.c
@@ -0,0 +1,722 @@
+#include "gc.h"
+
+int
+swcmp(void *a1, void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = a1;
+ p2 = a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+ Node tn;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ regalloc(&tn, &regnode, Z);
+ swit1(iq, nc, def, n, &tn);
+ regfree(&tn);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n, Node *tn)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(sval(q->val)) {
+ gopcode(OEQ, n, Z, nodconst(q->val));
+ } else {
+ gopcode(OSUB, nodconst(q->val), n, tn);
+ gopcode(OEQ, tn, Z, nodconst(0));
+ }
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(sval(r->val)) {
+ gopcode(OGT, n, Z, nodconst(r->val));
+ sp = p;
+ } else {
+ gopcode(OSUB, nodconst(r->val), n, tn);
+ gopcode(OGT, tn, Z, nodconst(0));
+ sp = p;
+ }
+ gbranch(OGOTO);
+ p->as = ABEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n, tn);
+
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n, tn);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(n, v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ if(v < 0)
+ gopcode(ONEG, &nod1, Z, &nod1);
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+ if(a->op == OCONST && typev[a->type->etype]) {
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+ long l;
+
+ bf[0] = p->as;
+ bf[1] = p->reg;
+ l = p->lineno;
+ bf[2] = l;
+ bf[3] = l>>8;
+ bf[4] = l>>16;
+ bf[5] = l>>24;
+ bp = zaddr(bf+6, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ ulong sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ long l;
+ Ieee e;
+
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_CREG:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ }
+ return bp;
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ o += SZ_LONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/utils/qc/txt.c b/utils/qc/txt.c
new file mode 100644
index 00000000..c14386ac
--- /dev/null
+++ b/utils/qc/txt.c
@@ -0,0 +1,1282 @@
+#include "gc.h"
+
+static int resvreg[nelem(reg)];
+
+
+void
+ginit(void)
+{
+ Type *t;
+
+ thechar = 'q';
+ thestring = "power";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = 0;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ memset(reg, 0, sizeof(reg));
+ reg[REGZERO] = 1; /* don't use */
+ reg[REGTMP] = 1;
+ reg[FREGCVI+NREG] = 1;
+ reg[FREGZERO+NREG] = 1;
+ reg[FREGHALF+NREG] = 1;
+ reg[FREGONE+NREG] = 1;
+ reg[FREGTWO+NREG] = 1;
+ memmove(resvreg, reg, sizeof(reg));
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(reg[i] && !resvreg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NREG; i++)
+ if(reg[i] && !resvreg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesuv[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gopcode(OAS, n, Z, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i > 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<NREG; i++) {
+ if(j >= NREG)
+ j = REGRET+1;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NREG)
+ goto out;
+ }
+ j = lasti + NREG;
+ for(i=NREG; i<NREG+NREG; i++) {
+ if(j >= NREG+NREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ lasti++;
+ if(lasti >= 5)
+ lasti = 0;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_LONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = REGZERO;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod, fxc0, fxc1, fxc2, fxrat;
+ Prog *p1;
+ double d;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0.0) {
+ a = FREGZERO;
+ goto ffreg;
+ }
+ if(d == 0.5) {
+ a = FREGHALF;
+ goto ffreg;
+ }
+ if(d == 1.0) {
+ a = FREGONE;
+ goto ffreg;
+ }
+ if(d == 2.0) {
+ a = FREGTWO;
+ goto ffreg;
+ }
+ if(d == -.5) {
+ fop(OSUB, FREGHALF, FREGZERO, t);
+ return;
+ }
+ if(d == -1.0) {
+ fop(OSUB, FREGONE, FREGZERO, t);
+ return;
+ }
+ if(d == -2.0) {
+ fop(OSUB, FREGTWO, FREGZERO, t);
+ return;
+ }
+ if(d == 1.5) {
+ fop(OADD, FREGONE, FREGHALF, t);
+ return;
+ }
+ if(d == 2.5) {
+ fop(OADD, FREGTWO, FREGHALF, t);
+ return;
+ }
+ if(d == 3.0) {
+ fop(OADD, FREGTWO, FREGONE, t);
+ return;
+ }
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0) {
+ a = FREGZERO;
+ ffreg:
+ nodreg(&nod, f, NREG+a);
+ gmove(&nod, t);
+ return;
+ }
+ }
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ a = AMOVW;
+ break;
+ case TFLOAT:
+ a = AFMOVS;
+ break;
+ case TDOUBLE:
+ a = AFMOVD;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBZ;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHZ;
+ break;
+ }
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBZ;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHZ;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AFMOVS;
+ break;
+ case TDOUBLE:
+ a = AFMOVD;
+ break;
+ }
+ if(R0ISZERO && !typefd[ft] && vconst(f) == 0) {
+ gins(a, f, t);
+ return;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TDOUBLE:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ a = AFMOVD;
+ if(ft == TFLOAT)
+ a = AFMOVS; /* AFMOVSD */
+ break;
+ case TFLOAT:
+ a = AFRSP;
+ if(ft == TFLOAT)
+ a = AFMOVS;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ /* BUG: not right for unsigned long */
+ regalloc(&nod, f, Z); /* should be type float */
+ regsalloc(&fxrat, f);
+ gins(AFCTIWZ, f, &nod);
+ gins(AFMOVD, &nod, &fxrat);
+ regfree(&nod);
+ fxrat.type = nodrat->type;
+ fxrat.etype = nodrat->etype;
+ fxrat.xoffset += 4;
+ gins(AMOVW, &fxrat, t);
+ gmove(t, t);
+ return;
+ }
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ switch(tt) {
+ case TDOUBLE:
+ case TFLOAT:
+ goto fxtofl;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TFLOAT:
+ goto fxtofl;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TFLOAT:
+ goto fxtofl;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVHZ;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TFLOAT:
+ goto fxtofl;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TFLOAT:
+ fxtofl:
+ /*
+ * rat[0] = 0x43300000; rat[1] = f^0x80000000;
+ * t = *(double*)rat - FREGCVI;
+ * is-unsigned(t) => if(t<0) t += 2^32;
+ * could be streamlined for int-to-float
+ */
+ regalloc(&fxc0, f, Z);
+ regalloc(&fxc2, f, Z);
+ regsalloc(&fxrat, t); /* should be type float */
+ gins(AMOVW, nodconst(0x43300000L), &fxc0);
+ gins(AMOVW, f, &fxc2);
+ gins(AMOVW, &fxc0, &fxrat);
+ gins(AXOR, nodconst(0x80000000L), &fxc2);
+ fxc1 = fxrat;
+ fxc1.type = nodrat->type;
+ fxc1.etype = nodrat->etype;
+ fxc1.xoffset += SZ_LONG;
+ gins(AMOVW, &fxc2, &fxc1);
+ regfree(&fxc2);
+ regfree(&fxc0);
+ regalloc(&nod, t, t); /* should be type float */
+ gins(AFMOVD, &fxrat, &nod);
+ nodreg(&fxc1, t, NREG+FREGCVI);
+ gins(AFSUB, &fxc1, &nod);
+ a = AFMOVD;
+ if(tt == TFLOAT)
+ a = AFRSP;
+ gins(a, &nod, t);
+ regfree(&nod);
+ if(ft == TULONG) {
+ regalloc(&nod, t, Z);
+ if(tt == TFLOAT) {
+ gins(AFCMPU, t, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGZERO;
+ gins(ABGE, Z, Z);
+ p1 = p;
+ gins(AFMOVS, nodfconst(4294967296.), &nod);
+ gins(AFADDS, &nod, t);
+ } else {
+ gins(AFCMPU, t, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGZERO;
+ gins(ABGE, Z, Z);
+ p1 = p;
+ gins(AFMOVD, nodfconst(4294967296.), &nod);
+ gins(AFADD, &nod, t);
+ }
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBZ;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AFMOVS || a == AFMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et;
+ Adr ta;
+ int uns;
+
+ uns = 0;
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADD;
+ if(et == TFLOAT)
+ a = AFADDS;
+ else
+ if(et == TDOUBLE)
+ a = AFADD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUB;
+ if(et == TFLOAT)
+ a = AFSUBS;
+ else
+ if(et == TDOUBLE)
+ a = AFSUB;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AOR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ if(f1->op == OCONST)
+ a = AANDCC;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRW;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRAW;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLW; /* BUG? */
+ break;
+
+ case OFUNC:
+ a = ABL;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT) {
+ a = AFMULS;
+ break;
+ } else
+ if(et == TDOUBLE) {
+ a = AFMUL;
+ break;
+ }
+ a = AMULLW;
+ break;
+
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = AFDIVS;
+ break;
+ } else
+ if(et == TDOUBLE) {
+ a = AFDIV;
+ break;
+ }
+ a = ADIVW;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ a = AREM;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ a = AREMU;
+ break;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVWU;
+ break;
+
+ case OCOM:
+ a = ANOR;
+ break;
+
+ case ONEG:
+ a = ANEG;
+ if(et == TFLOAT || et == TDOUBLE)
+ a = AFNEG;
+ break;
+
+ case OEQ:
+ a = ABEQ;
+ goto cmp;
+
+ case ONE:
+ a = ABNE;
+ goto cmp;
+
+ case OLT:
+ a = ABLT;
+ goto cmp;
+
+ case OLE:
+ a = ABLE;
+ goto cmp;
+
+ case OGE:
+ a = ABGE;
+ goto cmp;
+
+ case OGT:
+ a = ABGT;
+ goto cmp;
+
+ case OLO:
+ a = ABLT;
+ goto cmpu;
+
+ case OLS:
+ a = ABLE;
+ goto cmpu;
+
+ case OHS:
+ a = ABGE;
+ goto cmpu;
+
+ case OHI:
+ a = ABGT;
+ goto cmpu;
+
+ cmpu:
+ uns = 1;
+ cmp:
+ nextpc();
+ p->as = uns? ACMPU: ACMP;
+ if(et == TFLOAT)
+ p->as = AFCMPU;
+ else
+ if(et == TDOUBLE)
+ p->as = AFCMPU;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(f1 == Z || t == Z || f2 != Z)
+ diag(Z, "bad cmp in gopcode %O", o);
+ if(debug['g'])
+ print("%P\n", p);
+ f1 = Z;
+ f2 = Z;
+ t = Z;
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0) {
+ if(R0ISZERO)
+ p->reg = REGZERO;
+ else
+ diag(Z, "REGZERO in gopcode %O", o);
+ }
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARETURN;
+ break;
+ case OGOTO:
+ a = ABR;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ if(a == ATEXT)
+ p->reg = (profileflg ? 0 : NOPROF);
+ p->from.name = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sval(long v)
+{
+
+ if(v >= -(1<<15) && v < (1<<15))
+ return 1;
+ return 0;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+uconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= 0 && vv < (((vlong)1)<<16))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= 3)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 16)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/ql/Ins b/utils/ql/Ins
new file mode 100644
index 00000000..d113e845
--- /dev/null
+++ b/utils/ql/Ins
@@ -0,0 +1,203 @@
+a OR XO(31,10)
+abs OR XO(31,360)
+ae OR XO(31,138)
+ai 0 D(12) +
+
+ai. 0 D(13)
+ame OR XO(31,234)
+and R X(31,28)
+andc R X(31,60)
+
+andil. 0 D(28,0)
+andiu. 0 D(29,0)
+aze OR XO(31,202)
+cal 0 D(14)
+
+cau 0 D(15)
+cax OR XO(31,266)
+cmp 0 X(31,0)
+cmpi 0 D(11)
+
+cmpl 0 X(31,32)
+cmpli 0 D(10)
+cntlz R X(31,26)
+crand 0 XL(19,257)
+
+crandc 0 XL(19,129)
+creqv 0 XL(19,289)
+crnand 0 XL(19,225)
+crnor 0 XL(19,33)
+
+cror 0 XL(19,449)
+crorc 0 XL(19,417)
+crxor 0 XL(19,193)
+div OR XO(31,331)
+
+divs OR XO(31,331)
+doz OR XO(31,264)
+dozi 0 D(9)
+
+eqv R X(31,284)
+exts R X(31,922)
+fa R A(63,21)
+fabs R X(63,264)
+fcmpo 0 X(63,32)
+
+fcmpu 0 X(63,0)
+fd R A(63,8)
+fm R A(63,5)
+fma R A(63,29)
+
+fmr R X(63,72)
+fms R A(63,28)
+fnabs R X(63,136)
+fneg R X(63,40)
+
+fnma R A(63,31)
+fnms R A(63,30)
+frsp R X(63,12)
+fs R A(63,20)
+
+l 0 D(32)
+lbrx 0 X(31,534)
+lbz 0 D(34)
+lbzu 0 D(35)
+
+lbzux 0 X(31,119)
+lbzx 0 X(31,87)
+lfd 0 D(50)
+lfdu 0 D(51)
+
+lfdux 0 X(31,631)
+lfdx 0 X(31,599)
+lfs 0 D(48)
+lfsu 0 D(49)
+
+lfsux 0 X(31,567)
+lfsx 0 X(31,535)
+lha 0 D(42)
+lhau 0 D(43)
+
+lhaux 0 X(31,375)
+lhax 0 X(31,343)
+lhbrx 0 X(31,790)
+lhz 0 D(40)
+
+lhzu 0 D(41)
+lhzux 0 X(31,311)
+lhzx 0 X(31,279)
+lm 0 D(46)
+
+lscbx R X(31,277)
+lsi 0 X(31,597)
+lsx 0 X(31,533)
+lu 0 D(33)
+
+lux 0 X(31,55)
+lx 0 X(31,23)
+maskg R X(31,29)
+maskir R X(31,541)
+
+mcrf 0 XL(19,0)
+mcrfs 0 X(63,64)
+mcrxr 0 X(31,512)
+mfcr 0 X(31,19)
+
+mffs R X(63,583)
+mfmsr 0 X(31,83)
+mfspr 0 X(31,339)
+mtcrf 0 XFX(31,144)
+
+mtfsb0 R X(63,70)
+mtfsb1 R X(63,38)
+mtfsf R XFL(63,711)
+mtfsfi R X(63,134)
+
+mtspr 0 X(31,467)
+mul OR XO(31,107)
+muli 0 D(7)
+muls OR XO(31,235)
+
+nabs OR XO(31,488)
+nand R X(31,476)
+neg OR XO(31,104)
+
+nor R X(31,124)
+or R X(31,444)
+orc R X(31,412)
+oril 0 D(24)
+
+oriu 0 D(25)
+rlmi R M(20)
+rlinm R M(21)
+rlmi R M(22)
+
+rlnm R M(23)
+rrib R X(31,537)
+sf OR XO(31,8)
+sfe OR XO(31,36)
+
+sfi 0 D(8)
+sfme OR XO(31,232)
+sfze OR XO(31,200)
+sl R X(31,24)
+
+sle R X(31,153)
+sleq R X(31,217)
+sliq R X(31,184)
+slliq R X(31,248)
+
+sllq R X(31,216)
+slq R X(31,152)
+sr R X(31,536)
+sra R X(31,792)
+
+srai R X(31,824)
+sraiq R X(31,952)
+sraq R X(31,920)
+sre R X(31,665)
+
+srea R X(31,921)
+sreq R X(31,729)
+sriq R X(31,696)
+srliq R X(31,760)
+srlq R X(31,728)
+
+srq R X(31,664)
+st 0 D(36)
+stb 0 D(38)
+stbrx 0 X(31,662)
+
+stbu 0 D(39)
+stbux 0 X(31,247)
+stbx 0 X(31,215)
+stfd 0 D(54)
+
+stfdu 0 D(55)
+stfdux 0 X(31,759)
+stfdx 0 X(31,727)
+stfs 0 D(52)
+
+stfsu 0 D(53)
+stfsux 0 X(31,695)
+stfsx 0 X(31,663)
+sth 0 D(44)
+
+sthbrx 0 X(31,918)
+sthu 0 D(45)
+sthux 0 X(31,439)
+sthx 0 X(3,407)
+
+stm 0 D(47)
+stsi 0 X(31,725)
+stsx 0 X(31,661)
+stu 0 D(37)
+
+stux 0 X(31,183)
+stx 0 X(31,151)
+svc 0 SC(17)
+t 0 X(31,4)
+ti 0 D(3)
+xor R X(31,316)
+xoril 0 D(26)
+xoriu 0 D(27)
diff --git a/utils/ql/Notes b/utils/ql/Notes
new file mode 100644
index 00000000..1620b508
--- /dev/null
+++ b/utils/ql/Notes
@@ -0,0 +1,21 @@
+possible input transformations
+ adde $-1,X => addme X
+ adde $0,X => addze X
+ subw $s,X => addw $-s,X
+ orn $v,X => or $~v,X
+
+qa:
+ subc r1,$s,r2 => subc $s,r1,r2
+ movw sreg(Rn),Rm => movw sreg(NREG),Rn,Rm [and v.v.]
+
+others?
+ andn $m => and $~m
+ slw $sh,s,a => rliwnm
+ srw $sh,s,a => rliwnm
+
+support for C_LCON needed since addresses are literals?
+
+- moves
+- branch distance
+
+- could rewrite movwu x,d(r) as movw $d,tmp; movwu x,(tmp+d) when d is large?
diff --git a/utils/ql/Nt.c b/utils/ql/Nt.c
new file mode 100644
index 00000000..c6748abd
--- /dev/null
+++ b/utils/ql/Nt.c
@@ -0,0 +1,88 @@
+#include <windows.h>
+
+/*
+ * We can't include l.h, because Windoze wants to use some names
+ * like FLOAT and ABC which we declare. Define what we need here.
+ */
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+extern char *hunk;
+extern long nhunk;
+
+void gethunk(void);
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/ql/Plan9.c b/utils/ql/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/ql/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/ql/Posix.c b/utils/ql/Posix.c
new file mode 100644
index 00000000..0da0ee0c
--- /dev/null
+++ b/utils/ql/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fails if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
diff --git a/utils/ql/asm.c b/utils/ql/asm.c
new file mode 100644
index 00000000..6887a12b
--- /dev/null
+++ b/utils/ql/asm.c
@@ -0,0 +1,687 @@
+#include "l.h"
+
+#define KMASK 0xF0000000
+
+#define LPUT(c)\
+ {\
+ cbp[0] = (c)>>24;\
+ cbp[1] = (c)>>16;\
+ cbp[2] = (c)>>8;\
+ cbp[3] = (c);\
+ cbp += 4;\
+ cbc -= 4;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define CPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp++;\
+ cbc--;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+void strnput(char*, int);
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(dlm && s->type == SDATA)
+ return s->value+INITDAT;
+ if(s->type != STEXT && s->type != SLEAF)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long t;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asm\n", cputime());
+ Bflush(&bso);
+ seek(cout, HEADR, 0);
+ pc = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from3.type == D_CONST) {
+ for(; pc < p->pc; pc++)
+ CPUT(0);
+ }
+ }
+ if(p->pc != pc) {
+ diag("phase error %lux sb %lux",
+ p->pc, pc);
+ if(!debug['a'])
+ prasm(curp);
+ pc = p->pc;
+ }
+ curp = p;
+ o = oplook(p); /* could probably avoid this call */
+ if(asmout(p, o, 0)) {
+ p = p->link;
+ pc += 4;
+ }
+ pc += o->size;
+ }
+ if(debug['a'])
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ cflush();
+
+ curtext = P;
+ switch(HEADTYPE) {
+ case 0:
+ case 1:
+ case 2:
+ case 5:
+ seek(cout, HEADR+textsize, 0);
+ break;
+ case 3:
+ seek(cout, rnd(HEADR+textsize, 4), 0);
+ break;
+ case 4:
+ seek(cout, rnd(HEADR+textsize, 4096), 0);
+ break;
+ }
+
+ if(dlm){
+ char buf[8];
+
+ write(cout, buf, INITDAT-textsize);
+ textsize = INITDAT;
+ }
+
+ for(t = 0; t < datsize; t += sizeof(buf)-100) {
+ if(datsize-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100);
+ else
+ datblk(t, datsize-t);
+ }
+
+ symsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ case 0:
+ case 1:
+ case 2:
+ case 5:
+ seek(cout, HEADR+textsize+datsize, 0);
+ break;
+ case 3:
+ seek(cout, rnd(HEADR+textsize, 4)+datsize, 0);
+ break;
+ case 4:
+ seek(cout, rnd(HEADR+textsize, 4096)+datsize, 0);
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sp\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ if(dlm)
+ asmdyn();
+ if(HEADTYPE == 0 || HEADTYPE == 1) /* round up file length for boot image */
+ if((symsize+lcsize) & 1)
+ CPUT(0);
+ cflush();
+ }
+ else if(dlm){
+ asmdyn();
+ cflush();
+ }
+
+ seek(cout, 0L, 0);
+ switch(HEADTYPE) {
+ case 0:
+ lput(0x1030107); /* magic and sections */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case 1:
+ lput(0x4a6f7921); /* Joy! */
+ lput(0x70656666); /* peff */
+ lput(0x70777063); /* pwpc */
+ lput(1);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0x30002); /*YY*/
+ lput(0);
+ lput(~0);
+ lput(0);
+ lput(textsize+datsize);
+ lput(textsize+datsize);
+ lput(textsize+datsize);
+ lput(0xd0); /* header size */
+ lput(0x10400);
+ lput(~0);
+ lput(0);
+ lput(0xc);
+ lput(0xc);
+ lput(0xc);
+ lput(0xc0);
+ lput(0x01010400);
+ lput(~0);
+ lput(0);
+ lput(0x38);
+ lput(0x38);
+ lput(0x38);
+ lput(0x80);
+ lput(0x04040400);
+ lput(0);
+ lput(1);
+ lput(0);
+ lput(~0);
+ lput(0);
+ lput(~0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0);
+ lput(0x3100); /* load address */
+ lput(0);
+ lput(0);
+ lput(0); /* whew! */
+ break;
+ case 2:
+ if(dlm)
+ lput(0x80000000 | (4*21*21+7)); /* magic */
+ else
+ lput(4*21*21+7); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case 3:
+ break;
+ case 4:
+ lput((0x1DFL<<16)|3L); /* magic and sections */
+ lput(time(0)); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x48L<<16)|15L); /* size of optional hdr and flags */
+
+ lput((0413<<16)|01L); /* magic and version */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT); /* address of TOC */
+ lput((1L<<16)|1); /* sn(entry) | sn(text) */
+ lput((2L<<16)|1); /* sn(data) | sn(toc) */
+ lput((0L<<16)|3); /* sn(loader) | sn(bss) */
+ lput((3L<<16)|3); /* maxalign(text) | maxalign(data) */
+ lput(('1'<<24)|('L'<<16)|0); /* type field, and reserved */
+ lput(0); /* max stack allowed */
+ lput(0); /* max data allowed */
+ lput(0); lput(0); lput(0); /* reserved */
+
+ strnput(".text", 8); /* text segment */
+ lput(INITTEXT); /* address */
+ lput(INITTEXT);
+ lput(textsize);
+ lput(HEADR);
+ lput(0L);
+ lput(HEADR+textsize+datsize+symsize);
+ lput(lcsize); /* line number size */
+ lput(0x20L); /* flags */
+
+ strnput(".data", 8); /* data segment */
+ lput(INITDAT); /* address */
+ lput(INITDAT);
+ lput(datsize);
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0x40L); /* flags */
+
+ strnput(".bss", 8); /* bss segment */
+ lput(INITDAT+datsize); /* address */
+ lput(INITDAT+datsize);
+ lput(bsssize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0x80L); /* flags */
+ break;
+ case 5:
+ strnput("\177ELF", 4); /* e_ident */
+ CPUT(1); /* class = 32 bit */
+ CPUT(2); /* data = MSB */
+ CPUT(1); /* version = CURRENT */
+ strnput("", 9);
+ lput((2L<<16)|20L); /* type = EXEC; machine = PowerPC */
+ lput(1L); /* version = CURRENT */
+ lput(entryvalue() & ~KMASK); /* entry vaddr */
+ lput(52L); /* offset to first phdr */
+ lput(0L); /* offset to first shdr */
+ lput(0L); /* flags = PPC */
+ lput((52L<<16)|32L); /* Ehdr & Phdr sizes*/
+ lput((3L<<16)|0L); /* # Phdrs & Shdr size */
+ lput((0L<<16)|0L); /* # Shdrs & shdr string size */
+
+ lput(1L); /* text - type = PT_LOAD */
+ lput(HEADR); /* file offset */
+ lput(INITTEXT & ~KMASK); /* vaddr */
+ lput(INITTEXT); /* paddr */
+ lput(textsize); /* file size */
+ lput(textsize); /* memory size */
+ lput(0x05L); /* protections = RX */
+ lput(0x10000L); /* alignment code?? */
+
+ lput(1L); /* data - type = PT_LOAD */
+ lput(HEADR+textsize); /* file offset */
+ lput(INITDAT & ~KMASK); /* vaddr */
+ lput(INITDAT); /* paddr */
+ lput(datsize); /* file size */
+ lput(datsize); /* memory size */
+ lput(0x07L); /* protections = RWX */
+ lput(0x10000L); /* alignment code?? */
+
+ lput(0L); /* data - type = PT_NULL */
+ lput(HEADR+textsize+datsize); /* file offset */
+ lput(0L);
+ lput(0L);
+ lput(symsize); /* symbol table size */
+ lput(lcsize); /* line number size */
+ lput(0x04L); /* protections = R */
+ lput(0x04L); /* alignment code?? */
+ break;
+ }
+ cflush();
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s; s++){
+ CPUT(*s);
+ n--;
+ }
+ for(; n > 0; n--)
+ CPUT(0);
+}
+
+void
+cput(long l)
+{
+ CPUT(l);
+}
+
+void
+wput(long l)
+{
+ cbp[0] = l>>8;
+ cbp[1] = l;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+lput(long l)
+{
+
+ LPUT(l);
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->cond) {
+ s = p->from.sym;
+ if(s->type != STEXT && s->type != SLEAF)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->sym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->sym->name, 'Z', a->aoffset, 0);
+
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+ else
+ putsymb(s->name, 'L', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+4, 0);
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->sym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->sym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+putsymb(char *s, int t, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ LPUT(v);
+ if(ver)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ CPUT(s[i]);
+ CPUT(s[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ CPUT(s[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, s);
+ }
+}
+
+#define MINLC 4
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+void
+datblk(long s, long n)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j, d;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->reg;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ default:
+ diag("unknown mode in initialization\n%P", p);
+ break;
+
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (char*)&fl;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i+4]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)&p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.sval[i];
+ l++;
+ }
+ break;
+
+ case D_CONST:
+ d = p->to.offset;
+ if(p->to.sym) {
+ if(p->to.sym->type == SUNDEF){
+ ckoff(p->to.sym, d);
+ d += p->to.sym->value;
+ }
+ if(p->to.sym->type == STEXT ||
+ p->to.sym->type == SLEAF)
+ d += p->to.sym->value;
+ if(p->to.sym->type == SDATA)
+ d += p->to.sym->value + INITDAT;
+ if(p->to.sym->type == SBSS)
+ d += p->to.sym->value + INITDAT;
+ if(dlm)
+ dynreloc(p->to.sym, l+s+INITDAT, 1, 0, 0);
+ }
+ cast = (char*)&d;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
diff --git a/utils/ql/asmout.c b/utils/ql/asmout.c
new file mode 100644
index 00000000..e3d96694
--- /dev/null
+++ b/utils/ql/asmout.c
@@ -0,0 +1,1293 @@
+#include "l.h"
+
+#define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1))
+#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc))
+#define OP(o,xo) OPVCC((o),(xo),0,0)
+
+/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
+#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
+#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF))
+#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
+#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF))
+#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1))
+#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1))
+#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16))
+#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+ (((mb)&31L)<<6)|(((me)&31L)<<1))
+
+#define OP_ADD OPVCC(31,266,0,0)
+#define OP_ADDI OPVCC(14,0,0,0)
+#define OP_ADDIS OPVCC(15,0,0,0)
+#define OP_ANDI OPVCC(28,0,0,0)
+#define OP_EXTSB OPVCC(31,954,0,0)
+#define OP_EXTSH OPVCC(31,922,0,0)
+#define OP_MCRF OPVCC(19,0,0,0)
+#define OP_MCRFS OPVCC(63,64,0,0)
+#define OP_MCRXR OPVCC(31,512,0,0)
+#define OP_MFCR OPVCC(31,19,0,0)
+#define OP_MFFS OPVCC(63,583,0,0)
+#define OP_MFMSR OPVCC(31,83,0,0)
+#define OP_MFSPR OPVCC(31,339,0,0)
+#define OP_MFSR OPVCC(31,595,0,0)
+#define OP_MFSRIN OPVCC(31,659,0,0)
+#define OP_MTCRF OPVCC(31,144,0,0)
+#define OP_MTFSF OPVCC(63,711,0,0)
+#define OP_MTFSFI OPVCC(63,134,0,0)
+#define OP_MTMSR OPVCC(31,146,0,0)
+#define OP_MTSPR OPVCC(31,467,0,0)
+#define OP_MTSR OPVCC(31,210,0,0)
+#define OP_MTSRIN OPVCC(31,242,0,0)
+#define OP_MULLW OPVCC(31,235,0,0)
+#define OP_OR OPVCC(31,444,0,0)
+#define OP_ORI OPVCC(24,0,0,0)
+#define OP_RLWINM OPVCC(21,0,0,0)
+#define OP_SUBF OPVCC(31,40,0,0)
+
+#define oclass(v) ((v).class-1)
+
+long oprrr(int), opirr(int), opload(int), opstore(int), oploadx(int), opstorex(int);
+
+int
+getmask(uchar *m, ulong v)
+{
+ int i;
+
+ m[0] = m[1] = 0;
+ if(v != ~0L && v & (1<<31) && v & 1){ /* MB > ME */
+ if(getmask(m, ~v)){
+ i = m[0]; m[0] = m[1]+1; m[1] = i-1;
+ return 1;
+ }
+ return 0;
+ }
+ for(i=0; i<32; i++)
+ if(v & (1<<(31-i))){
+ m[0] = i;
+ do {
+ m[1] = i;
+ } while(++i<32 && (v & (1<<(31-i))) != 0);
+ for(; i<32; i++)
+ if(v & (1<<(31-i)))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+void
+maskgen(Prog *p, uchar *m, ulong v)
+{
+ if(!getmask(m, v))
+ diag("cannot generate mask #%lux\n%P", v, p);
+}
+
+static void
+reloc(Adr *a, long pc, int sext)
+{
+ if(a->name == D_EXTERN || a->name == D_STATIC)
+ dynreloc(a->sym, pc, 1, 1, sext);
+}
+
+int
+asmout(Prog *p, Optab *o, int aflag)
+{
+ long o1, o2, o3, o4, o5, v, t;
+ Prog *ct;
+ int r, a;
+ uchar mask[2];
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ switch(o->type) {
+ default:
+ if(aflag)
+ return 0;
+ diag("unknown type %d", o->type);
+ if(!debug['a'])
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ if(aflag) {
+ if(p->link) {
+ if(p->as == ATEXT) {
+ ct = curtext;
+ o2 = autosize;
+ curtext = p;
+ autosize = p->to.offset + 4;
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ curtext = ct;
+ autosize = o2;
+ } else
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ }
+ return o1;
+ }
+ break;
+
+ case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
+ if(p->to.reg == REGZERO && p->from.type == D_CONST) {
+ v = regoff(&p->from);
+ if(r0iszero && v != 0) {
+ nerrors--;
+ diag("literal operation on R0\n%P", p);
+ }
+ o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
+ break;
+ }
+ o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg);
+ break;
+
+ case 2: /* int/cr/fp op Rb,[Ra],Rd */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ a = OP_ADDI;
+ if(o->a1 == C_UCON) {
+ a = OP_ADDIS;
+ v >>= 16;
+ }
+ if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0))
+ diag("literal operation on R0\n%P", p);
+ o1 = AOP_IRR(a, p->to.reg, r, v);
+ break;
+
+ case 4: /* add/mul $scon,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ if(r0iszero && p->to.reg == 0)
+ diag("literal operation on R0\n%P", p);
+ o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v);
+ break;
+
+ case 5: /* syscall */
+ if(aflag)
+ return 0;
+ o1 = oprrr(p->as);
+ break;
+
+ case 6: /* logical op Rb,[Rs,]Ra; no literal */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 7: /* mov r, soreg ==> stw o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ if(p->to.type == D_OREG && p->reg != NREG) {
+ if(v)
+ diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(opstorex(p->as), p->from.reg, p->reg, r);
+ } else
+ o1 = AOP_IRR(opstore(p->as), p->from.reg, r, v);
+ break;
+
+ case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ if(p->from.type == D_OREG && p->reg != NREG) {
+ if(v)
+ diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r);
+ } else
+ o1 = AOP_IRR(opload(p->as), p->to.reg, r, v);
+ break;
+
+ case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ if(p->from.type == D_OREG && p->reg != NREG) {
+ if(v)
+ diag("illegal indexed instruction\n%P", p);
+ o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r);
+ } else
+ o1 = AOP_IRR(opload(p->as), p->to.reg, r, v);
+ o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ break;
+
+ case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, r);
+ break;
+
+ case 11: /* br/bl lbra */
+ if(aflag)
+ return 0;
+ v = 0;
+ if(p->cond == UP){
+ if(p->to.sym->type != SUNDEF)
+ diag("bad branch sym type");
+ v = (ulong)p->to.sym->value >> (Roffset-2);
+ dynreloc(p->to.sym, p->pc, 0, 0, 0);
+ }
+ else if(p->cond)
+ v = p->cond->pc - p->pc;
+ if(v & 03) {
+ diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ if(v < -(1L<<25) || v >= (1L<<25))
+ diag("branch too far\n%P", p);
+ o1 = OP_BR(opirr(p->as), v, 0);
+ break;
+
+ case 12: /* movb r,r (signed); extsb is on PowerPC but not POWER */
+ o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0);
+ break;
+
+ case 13: /* mov[bh]z r,r; uses rlwinm not andi. to avoid changing CC */
+ if(p->as == AMOVBZ)
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31);
+ else if(p->as == AMOVH)
+ o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0);
+ else if(p->as == AMOVHZ)
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31);
+ else
+ diag("internal: bad mov[bh]z\n%P", p);
+ break;
+
+/*14 */
+
+ case 17: /* bc bo,bi,lbra (same for now) */
+ case 16: /* bc bo,bi,sbra */
+ if(aflag)
+ return 0;
+ a = 0;
+ if(p->from.type == D_CONST)
+ a = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ v = 0;
+ if(p->cond)
+ v = p->cond->pc - p->pc;
+ if(v & 03) {
+ diag("odd branch target address\n%P", p);
+ v &= ~03;
+ }
+ if(v < -(1L<<16) || v >= (1L<<16))
+ diag("branch too far\n%P", p);
+ o1 = OP_BC(opirr(p->as), a, r, v, 0);
+ break;
+
+ case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
+ if(aflag)
+ return 0;
+ if(p->as == ABC || p->as == ABCL)
+ v = regoff(&p->to)&31L;
+ else
+ v = 20; /* unconditional */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11);
+ o2 = OPVCC(19, 16, 0, 0);
+ if(p->as == ABL || p->as == ABCL)
+ o2 |= 1;
+ o2 = OP_BCR(o2, v, r);
+ break;
+
+ case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
+ if(aflag)
+ return 0;
+ if(p->as == ABC || p->as == ABCL)
+ v = regoff(&p->from)&31L;
+ else
+ v = 20; /* unconditional */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ switch(oclass(p->to)) {
+ case C_CTR:
+ o1 = OPVCC(19, 528, 0, 0);
+ break;
+ case C_LR:
+ o1 = OPVCC(19, 16, 0, 0);
+ break;
+ default:
+ diag("bad optab entry (18): %d\n%P", p->to.class, p);
+ v = 0;
+ }
+ if(p->as == ABL || p->as == ABCL)
+ o1 |= 1;
+ o1 = OP_BCR(o1, v, r);
+ break;
+
+ case 19: /* mov $lcon,r ==> cau+or */
+ v = regoff(&p->from);
+ o1 = AOP_IRR(OP_ADDIS, p->to.reg, REGZERO, v>>16);
+ o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, v);
+ if(dlm)
+ reloc(&p->from, p->pc, 0);
+ break;
+
+ case 20: /* add $ucon,,r */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0))
+ diag("literal operation on R0\n%P", p);
+ o1 = AOP_IRR(opirr(p->as+AEND), p->to.reg, r, v>>16);
+ break;
+
+ case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = AOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r);
+ if(dlm)
+ reloc(&p->from, p->pc, 0);
+ break;
+
+ case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = LOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r);
+ if(dlm)
+ reloc(&p->from, p->pc, 0);
+ break;
+/*24*/
+
+ case 26: /* mov $lsext/auto/oreg,,r2 ==> cau+add */
+ v = regoff(&p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ if(p->to.reg == REGTMP)
+ diag("can't synthesize large constant\n%P", p);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v);
+ break;
+
+ case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
+ v = regoff(&p->from3);
+ r = p->from.reg;
+ o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v);
+ break;
+
+ case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
+ v = regoff(&p->from3);
+ if(p->to.reg == REGTMP || p->from.reg == REGTMP)
+ diag("can't synthesize large constant\n%P", p);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v);
+ o3 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, REGTMP);
+ if(dlm)
+ reloc(&p->from3, p->pc, 0);
+ break;
+
+/*29, 30, 31 */
+
+ case 32: /* fmul frc,fra,frd */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6);
+ break;
+
+ case 33: /* fabs [frb,]frd; fmr. frb,frd */
+ r = p->from.reg;
+ if(oclass(p->from) == C_NONE)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(p->as), p->to.reg, 0, r);
+ break;
+
+ case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c) */
+ o1 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, p->reg)|((p->from3.reg&31L)<<6);
+ break;
+
+ case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
+ v = regoff(&p->to);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opstore(p->as), p->from.reg, REGTMP, v);
+ break;
+
+ case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
+ v = regoff(&p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v);
+ break;
+
+ case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
+ v = regoff(&p->from);
+ if(v & 0x8000L)
+ v += 0x10000L;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16);
+ o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v);
+ o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ break;
+
+ case 40: /* word */
+ if(aflag)
+ return 0;
+ o1 = regoff(&p->from);
+ break;
+
+ case 41: /* stswi */
+ o1 = AOP_RRR(opirr(p->as), p->from.reg, p->to.reg, 0) | ((regoff(&p->from3)&0x7F)<<11);
+ break;
+
+ case 42: /* lswi */
+ o1 = AOP_RRR(opirr(p->as), p->to.reg, p->from.reg, 0) | ((regoff(&p->from3)&0x7F)<<11);
+ break;
+
+ case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(oprrr(p->as), 0, r, p->from.reg);
+ break;
+
+ case 44: /* indexed store */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(opstorex(p->as), p->from.reg, r, p->to.reg);
+ break;
+ case 45: /* indexed load */
+ r = p->reg;
+ if(r == NREG)
+ r = 0;
+ o1 = AOP_RRR(oploadx(p->as), p->to.reg, r, p->from.reg);
+ break;
+
+ case 46: /* plain op */
+ o1 = oprrr(p->as);
+ break;
+
+ case 47: /* op Ra, Rd; also op [Ra,] Rd */
+ r = p->from.reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, 0);
+ break;
+
+ case 48: /* op Rs, Ra */
+ r = p->from.reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, 0);
+ break;
+
+ case 49: /* op Rb */
+ o1 = AOP_RRR(oprrr(p->as), 0, 0, p->from.reg);
+ break;
+
+/*50*/
+
+ case 51: /* rem[u] r1[,r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ v = oprrr(p->as);
+ t = v & ((1<<10)|1); /* OE|Rc */
+ o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
+ o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, p->from.reg);
+ o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
+ break;
+
+ case 52: /* mtfsbNx cr(n) */
+ v = regoff(&p->from)&31L;
+ o1 = AOP_RRR(oprrr(p->as), v, 0, 0);
+ break;
+
+ case 53: /* mffsX ,fr1 */
+ o1 = AOP_RRR(OP_MFFS, p->to.reg, 0, 0);
+ break;
+
+ case 54: /* mov msr,r1; mov r1, msr*/
+ if(oclass(p->from) == C_REG)
+ o1 = AOP_RRR(OP_MTMSR, p->from.reg, 0, 0);
+ else
+ o1 = AOP_RRR(OP_MFMSR, p->to.reg, 0, 0);
+ break;
+
+ case 55: /* mov sreg,r1; mov r1,sreg */
+ v = 0;
+ if(p->from.type == D_SREG) {
+ r = p->from.reg;
+ o1 = OP_MFSR;
+ if(r == NREG && p->reg != NREG) {
+ r = 0;
+ v = p->reg;
+ o1 = OP_MFSRIN;
+ }
+ o1 = AOP_RRR(o1, p->to.reg, r&15L, v);
+ } else {
+ r = p->to.reg;
+ o1 = OP_MTSR;
+ if(r == NREG && p->reg != NREG) {
+ r = 0;
+ v = p->reg;
+ o1 = OP_MTSRIN;
+ }
+ o1 = AOP_RRR(o1, p->from.reg, r&15L, v);
+ }
+ if(r == NREG)
+ diag("illegal move indirect to/from segment register\n%P", p);
+ break;
+
+ case 56: /* sra $sh,[s,]a */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = AOP_RRR(opirr(p->as), r, p->to.reg, v&31L);
+ break;
+
+ case 57: /* slw $sh,[s,]a -> rlwinm ... */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ /*
+ * Let user (gs) shoot himself in the foot.
+ * qc has already complained.
+ *
+ if(v < 0 || v > 31)
+ diag("illegal shift %ld\n%P", v, p);
+ */
+ if(v < 0)
+ v = 0;
+ else if(v > 32)
+ v = 32;
+ if(p->as == ASRW || p->as == ASRWCC) { /* shift right */
+ mask[0] = v;
+ mask[1] = 31;
+ v = 32-v;
+ } else {
+ mask[0] = 0;
+ mask[1] = 31-v;
+ }
+ o1 = OP_RLW(OP_RLWINM, p->to.reg, r, v, mask[0], mask[1]);
+ if(p->as == ASLWCC || p->as == ASRWCC)
+ o1 |= 1; /* Rc */
+ break;
+
+ case 58: /* logical $andcon,[s],a */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_IRR(opirr(p->as), p->to.reg, r, v);
+ break;
+
+ case 59: /* or/and $ucon,,r */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = LOP_IRR(opirr(p->as+AEND), p->to.reg, r, v>>16); /* oris, xoris, andis */
+ break;
+
+ case 60: /* tw to,a,b */
+ r = regoff(&p->from)&31L;
+ o1 = AOP_RRR(oprrr(p->as), r, p->reg, p->to.reg);
+ break;
+
+ case 61: /* tw to,a,$simm */
+ r = regoff(&p->from)&31L;
+ v = regoff(&p->to);
+ o1 = AOP_IRR(opirr(p->as), r, p->reg, v);
+ break;
+
+ case 62: /* rlwmi $sh,s,$mask,a */
+ v = regoff(&p->from);
+ maskgen(p, mask, regoff(&p->from3));
+ o1 = AOP_RRR(opirr(p->as), p->reg, p->to.reg, v);
+ o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
+ break;
+
+ case 63: /* rlwmi b,s,$mask,a */
+ maskgen(p, mask, regoff(&p->from3));
+ o1 = AOP_RRR(opirr(p->as), p->reg, p->to.reg, p->from.reg);
+ o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
+ break;
+
+ case 64: /* mtfsf fr[, $m] {,fpcsr} */
+ if(p->from3.type != D_NONE)
+ v = regoff(&p->from3)&255L;
+ else
+ v = 255;
+ o1 = OP_MTFSF | (v<<17) | (p->from.reg<<11);
+ break;
+
+ case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
+ if(p->to.reg == NREG)
+ diag("must specify FPSCR(n)\n%P", p);
+ o1 = OP_MTFSFI | ((p->to.reg&15L)<<23) | ((regoff(&p->from)&31L)<<12);
+ break;
+
+ case 66: /* mov spr,r1; mov r1,spr, also dcr */
+ if(p->from.type == D_REG) {
+ r = p->from.reg;
+ v = p->to.offset;
+ if(p->to.type == D_DCR)
+ o1 = OPVCC(31,451,0,0); /* mtdcr */
+ else
+ o1 = OPVCC(31,467,0,0); /* mtspr */
+ } else {
+ r = p->to.reg;
+ v = p->from.offset;
+ if(p->from.type == D_DCR)
+ o1 = OPVCC(31,323,0,0); /* mfdcr */
+ else
+ o1 = OPVCC(31,339,0,0); /* mfspr */
+ }
+ o1 = AOP_RRR(o1, r, 0, 0) | ((v&0x1f)<<16) | (((v>>5)&0x1f)<<11);
+ break;
+
+ case 67: /* mcrf crfD,crfS */
+ if(p->from.type != D_CREG || p->from.reg == NREG ||
+ p->to.type != D_CREG || p->to.reg == NREG)
+ diag("illegal CR field number\n%P", p);
+ o1 = AOP_RRR(OP_MCRF, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
+ break;
+
+ case 68: /* mfcr rD */
+ if(p->from.type == D_CREG && p->from.reg != NREG)
+ diag("must move whole CR to register\n%P", p);
+ o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0);
+ break;
+
+ case 69: /* mtcrf CRM,rS */
+ if(p->from3.type != D_NONE) {
+ if(p->to.reg != NREG)
+ diag("can't use both mask and CR(n)\n%P", p);
+ v = regoff(&p->from3) & 0xff;
+ } else {
+ if(p->to.reg == NREG)
+ v = 0xff; /* CR */
+ else
+ v = 1<<(7-(p->to.reg&7)); /* CR(n) */
+ }
+ o1 = AOP_RRR(OP_MTCRF, p->from.reg, 0, 0) | (v<<12);
+ break;
+
+ case 70: /* [f]cmp r,r,cr*/
+ if(p->reg == NREG)
+ r = 0;
+ else
+ r = (p->reg&7)<<2;
+ o1 = AOP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg);
+ break;
+
+ case 71: /* cmp[l] r,i,cr*/
+ if(p->reg == NREG)
+ r = 0;
+ else
+ r = (p->reg&7)<<2;
+ o1 = AOP_RRR(opirr(p->as), r, p->from.reg, 0) | (regoff(&p->to)&0xffff);
+ break;
+
+ case 72: /* mcrxr crfD */
+ if(p->to.reg == NREG)
+ diag("must move XER to CR(n)\n%P", p);
+ o1 = AOP_RRR(OP_MCRXR, ((p->to.reg&7L)<<2), 0, 0);
+ break;
+
+ case 73: /* mcrfs crfD,crfS */
+ if(p->from.type != D_FPSCR || p->from.reg == NREG ||
+ p->to.type != D_CREG || p->to.reg == NREG)
+ diag("illegal FPSCR/CR field number\n%P", p);
+ o1 = AOP_RRR(OP_MCRFS, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
+ break;
+
+ /* relocation operations */
+
+ case 74:
+ v = regoff(&p->to);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = AOP_IRR(opstore(p->as), p->from.reg, REGTMP, v);
+ if(dlm)
+ reloc(&p->to, p->pc, 1);
+ break;
+
+ case 75:
+ v = regoff(&p->from);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v);
+ if(dlm)
+ reloc(&p->from, p->pc, 1);
+ break;
+
+ case 76:
+ v = regoff(&p->from);
+ o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
+ o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v);
+ o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
+ if(dlm)
+ reloc(&p->from, p->pc, 1);
+ break;
+
+ }
+ if(aflag)
+ return o1;
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ lput(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ lput(o1);
+ lput(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lput(o1);
+ lput(o2);
+ lput(o3);
+ lput(o4);
+ lput(o5);
+ break;
+ }
+ return 0;
+}
+
+long
+oprrr(int a)
+{
+ switch(a) {
+ case AADD: return OPVCC(31,266,0,0);
+ case AADDCC: return OPVCC(31,266,0,1);
+ case AADDV: return OPVCC(31,266,1,0);
+ case AADDVCC: return OPVCC(31,266,1,1);
+ case AADDC: return OPVCC(31,10,0,0);
+ case AADDCCC: return OPVCC(31,10,0,1);
+ case AADDCV: return OPVCC(31,10,1,0);
+ case AADDCVCC: return OPVCC(31,10,1,1);
+ case AADDE: return OPVCC(31,138,0,0);
+ case AADDECC: return OPVCC(31,138,0,1);
+ case AADDEV: return OPVCC(31,138,1,0);
+ case AADDEVCC: return OPVCC(31,138,1,1);
+ case AADDME: return OPVCC(31,234,0,0);
+ case AADDMECC: return OPVCC(31,234,0,1);
+ case AADDMEV: return OPVCC(31,234,1,0);
+ case AADDMEVCC: return OPVCC(31,234,1,1);
+ case AADDZE: return OPVCC(31,202,0,0);
+ case AADDZECC: return OPVCC(31,202,0,1);
+ case AADDZEV: return OPVCC(31,202,1,0);
+ case AADDZEVCC: return OPVCC(31,202,1,1);
+
+ case AAND: return OPVCC(31,28,0,0);
+ case AANDCC: return OPVCC(31,28,0,1);
+ case AANDN: return OPVCC(31,60,0,0);
+ case AANDNCC: return OPVCC(31,60,0,1);
+
+ case ACMP: return OPVCC(31,0,0,0);
+ case ACMPU: return OPVCC(31,32,0,0);
+
+ case ACNTLZW: return OPVCC(31,26,0,0);
+ case ACNTLZWCC: return OPVCC(31,26,0,1);
+
+ case ACRAND: return OPVCC(19,257,0,0);
+ case ACRANDN: return OPVCC(19,129,0,0);
+ case ACREQV: return OPVCC(19,289,0,0);
+ case ACRNAND: return OPVCC(19,225,0,0);
+ case ACRNOR: return OPVCC(19,33,0,0);
+ case ACROR: return OPVCC(19,449,0,0);
+ case ACRORN: return OPVCC(19,417,0,0);
+ case ACRXOR: return OPVCC(19,193,0,0);
+
+ case ADCBF: return OPVCC(31,86,0,0);
+ case ADCBI: return OPVCC(31,470,0,0);
+ case ADCBST: return OPVCC(31,54,0,0);
+ case ADCBT: return OPVCC(31,278,0,0);
+ case ADCBTST: return OPVCC(31,246,0,0);
+ case ADCBZ: return OPVCC(31,1014,0,0);
+
+ case AREM:
+ case ADIVW: return OPVCC(31,491,0,0);
+ case AREMCC:
+ case ADIVWCC: return OPVCC(31,491,0,1);
+ case AREMV:
+ case ADIVWV: return OPVCC(31,491,1,0);
+ case AREMVCC:
+ case ADIVWVCC: return OPVCC(31,491,1,1);
+ case AREMU:
+ case ADIVWU: return OPVCC(31,459,0,0);
+ case AREMUCC:
+ case ADIVWUCC: return OPVCC(31,459,0,1);
+ case AREMUV:
+ case ADIVWUV: return OPVCC(31,459,1,0);
+ case AREMUVCC:
+ case ADIVWUVCC: return OPVCC(31,459,1,1);
+
+ case AEIEIO: return OPVCC(31,854,0,0);
+
+ case AEQV: return OPVCC(31,284,0,0);
+ case AEQVCC: return OPVCC(31,284,0,1);
+
+ case AEXTSB: return OPVCC(31,954,0,0);
+ case AEXTSBCC: return OPVCC(31,954,0,1);
+ case AEXTSH: return OPVCC(31,922,0,0);
+ case AEXTSHCC: return OPVCC(31,922,0,1);
+
+ case AFABS: return OPVCC(63,264,0,0);
+ case AFABSCC: return OPVCC(63,264,0,1);
+ case AFADD: return OPVCC(63,21,0,0);
+ case AFADDCC: return OPVCC(63,21,0,1);
+ case AFADDS: return OPVCC(59,21,0,0);
+ case AFADDSCC: return OPVCC(59,21,0,1);
+ case AFCMPO: return OPVCC(63,32,0,0);
+ case AFCMPU: return OPVCC(63,0,0,0);
+ case AFCTIW: return OPVCC(63,14,0,0);
+ case AFCTIWCC: return OPVCC(63,14,0,1);
+ case AFCTIWZ: return OPVCC(63,15,0,0);
+ case AFCTIWZCC: return OPVCC(63,15,0,1);
+ case AFDIV: return OPVCC(63,18,0,0);
+ case AFDIVCC: return OPVCC(63,18,0,1);
+ case AFDIVS: return OPVCC(59,18,0,0);
+ case AFDIVSCC: return OPVCC(59,18,0,1);
+ case AFMADD: return OPVCC(63,29,0,0);
+ case AFMADDCC: return OPVCC(63,29,0,1);
+ case AFMADDS: return OPVCC(59,29,0,0);
+ case AFMADDSCC: return OPVCC(59,29,0,1);
+ case AFMOVS:
+ case AFMOVD: return OPVCC(63,72,0,0); /* load */
+ case AFMOVDCC: return OPVCC(63,72,0,1);
+ case AFMSUB: return OPVCC(63,28,0,0);
+ case AFMSUBCC: return OPVCC(63,28,0,1);
+ case AFMSUBS: return OPVCC(59,28,0,0);
+ case AFMSUBSCC: return OPVCC(59,28,0,1);
+ case AFMUL: return OPVCC(63,25,0,0);
+ case AFMULCC: return OPVCC(63,25,0,1);
+ case AFMULS: return OPVCC(59,25,0,0);
+ case AFMULSCC: return OPVCC(59,25,0,1);
+ case AFNABS: return OPVCC(63,136,0,0);
+ case AFNABSCC: return OPVCC(63,136,0,1);
+ case AFNEG: return OPVCC(63,40,0,0);
+ case AFNEGCC: return OPVCC(63,40,0,1);
+ case AFNMADD: return OPVCC(63,31,0,0);
+ case AFNMADDCC: return OPVCC(63,31,0,1);
+ case AFNMADDS: return OPVCC(59,31,0,0);
+ case AFNMADDSCC: return OPVCC(59,31,0,1);
+ case AFNMSUB: return OPVCC(63,30,0,0);
+ case AFNMSUBCC: return OPVCC(63,30,0,1);
+ case AFNMSUBS: return OPVCC(59,30,0,0);
+ case AFNMSUBSCC: return OPVCC(59,30,0,1);
+ case AFRSP: return OPVCC(63,12,0,0);
+ case AFRSPCC: return OPVCC(63,12,0,1);
+ case AFSUB: return OPVCC(63,20,0,0);
+ case AFSUBCC: return OPVCC(63,20,0,1);
+ case AFSUBS: return OPVCC(59,20,0,0);
+ case AFSUBSCC: return OPVCC(59,20,0,1);
+
+ case AICBI: return OPVCC(31,982,0,0);
+ case AISYNC: return OPVCC(19,150,0,0);
+
+ /* lscb etc are not PowerPC instructions */
+
+ case AMTFSB0: return OPVCC(63,70,0,0);
+ case AMTFSB0CC: return OPVCC(63,70,0,1);
+ case AMTFSB1: return OPVCC(63,38,0,0);
+ case AMTFSB1CC: return OPVCC(63,38,0,1);
+
+ case AMULHW: return OPVCC(31,75,0,0);
+ case AMULHWCC: return OPVCC(31,75,0,1);
+ case AMULHWU: return OPVCC(31,11,0,0);
+ case AMULHWUCC: return OPVCC(31,11,0,1);
+ case AMULLW: return OPVCC(31,235,0,0);
+ case AMULLWCC: return OPVCC(31,235,0,1);
+ case AMULLWV: return OPVCC(31,235,1,0);
+ case AMULLWVCC: return OPVCC(31,235,1,1);
+
+ /* the following group is only available on IBM embedded powerpc */
+ case AMACCHW: return OPVCC(4,172,0,0);
+ case AMACCHWCC: return OPVCC(4,172,0,1);
+ case AMACCHWS: return OPVCC(4,236,0,0);
+ case AMACCHWSCC: return OPVCC(4,236,0,1);
+ case AMACCHWSU: return OPVCC(4,204,0,0);
+ case AMACCHWSUCC: return OPVCC(4,204,0,1);
+ case AMACCHWSUV: return OPVCC(4,204,1,0);
+ case AMACCHWSUVCC: return OPVCC(4,204,1,1);
+ case AMACCHWSV: return OPVCC(4,236,1,0);
+ case AMACCHWSVCC: return OPVCC(4,236,1,1);
+ case AMACCHWU: return OPVCC(4,140,0,0);
+ case AMACCHWUCC: return OPVCC(4,140,0,1);
+ case AMACCHWUV: return OPVCC(4,140,1,0);
+ case AMACCHWUVCC: return OPVCC(4,140,1,1);
+ case AMACCHWV: return OPVCC(4,172,1,0);
+ case AMACCHWVCC: return OPVCC(4,172,1,1);
+ case AMACHHW: return OPVCC(4,44,0,0);
+ case AMACHHWCC: return OPVCC(4,44,0,1);
+ case AMACHHWS: return OPVCC(4,108,0,0);
+ case AMACHHWSCC: return OPVCC(4,108,0,1);
+ case AMACHHWSU: return OPVCC(4,76,0,0);
+ case AMACHHWSUCC: return OPVCC(4,76,0,1);
+ case AMACHHWSUV: return OPVCC(4,76,1,0);
+ case AMACHHWSUVCC: return OPVCC(4,76,1,1);
+ case AMACHHWSV: return OPVCC(4,108,1,0);
+ case AMACHHWSVCC: return OPVCC(4,108,1,1);
+ case AMACHHWU: return OPVCC(4,12,0,0);
+ case AMACHHWUCC: return OPVCC(4,12,0,1);
+ case AMACHHWUV: return OPVCC(4,12,1,0);
+ case AMACHHWUVCC: return OPVCC(4,12,1,1);
+ case AMACHHWV: return OPVCC(4,44,1,0);
+ case AMACHHWVCC: return OPVCC(4,44,1,1);
+ case AMACLHW: return OPVCC(4,428,0,0);
+ case AMACLHWCC: return OPVCC(4,428,0,1);
+ case AMACLHWS: return OPVCC(4,492,0,0);
+ case AMACLHWSCC: return OPVCC(4,492,0,1);
+ case AMACLHWSU: return OPVCC(4,460,0,0);
+ case AMACLHWSUCC: return OPVCC(4,460,0,1);
+ case AMACLHWSUV: return OPVCC(4,460,1,0);
+ case AMACLHWSUVCC: return OPVCC(4,460,1,1);
+ case AMACLHWSV: return OPVCC(4,492,1,0);
+ case AMACLHWSVCC: return OPVCC(4,492,1,1);
+ case AMACLHWU: return OPVCC(4,396,0,0);
+ case AMACLHWUCC: return OPVCC(4,396,0,1);
+ case AMACLHWUV: return OPVCC(4,396,1,0);
+ case AMACLHWUVCC: return OPVCC(4,396,1,1);
+ case AMACLHWV: return OPVCC(4,428,1,0);
+ case AMACLHWVCC: return OPVCC(4,428,1,1);
+ case AMULCHW: return OPVCC(4,168,0,0);
+ case AMULCHWCC: return OPVCC(4,168,0,1);
+ case AMULCHWU: return OPVCC(4,136,0,0);
+ case AMULCHWUCC: return OPVCC(4,136,0,1);
+ case AMULHHW: return OPVCC(4,40,0,0);
+ case AMULHHWCC: return OPVCC(4,40,0,1);
+ case AMULHHWU: return OPVCC(4,8,0,0);
+ case AMULHHWUCC: return OPVCC(4,8,0,1);
+ case AMULLHW: return OPVCC(4,424,0,0);
+ case AMULLHWCC: return OPVCC(4,424,0,1);
+ case AMULLHWU: return OPVCC(4,392,0,0);
+ case AMULLHWUCC: return OPVCC(4,392,0,1);
+ case ANMACCHW: return OPVCC(4,174,0,0);
+ case ANMACCHWCC: return OPVCC(4,174,0,1);
+ case ANMACCHWS: return OPVCC(4,238,0,0);
+ case ANMACCHWSCC: return OPVCC(4,238,0,1);
+ case ANMACCHWSV: return OPVCC(4,238,1,0);
+ case ANMACCHWSVCC: return OPVCC(4,238,1,1);
+ case ANMACCHWV: return OPVCC(4,174,1,0);
+ case ANMACCHWVCC: return OPVCC(4,174,1,1);
+ case ANMACHHW: return OPVCC(4,46,0,0);
+ case ANMACHHWCC: return OPVCC(4,46,0,1);
+ case ANMACHHWS: return OPVCC(4,110,0,0);
+ case ANMACHHWSCC: return OPVCC(4,110,0,1);
+ case ANMACHHWSV: return OPVCC(4,110,1,0);
+ case ANMACHHWSVCC: return OPVCC(4,110,1,1);
+ case ANMACHHWV: return OPVCC(4,46,1,0);
+ case ANMACHHWVCC: return OPVCC(4,46,1,1);
+ case ANMACLHW: return OPVCC(4,430,0,0);
+ case ANMACLHWCC: return OPVCC(4,430,0,1);
+ case ANMACLHWS: return OPVCC(4,494,0,0);
+ case ANMACLHWSCC: return OPVCC(4,494,0,1);
+ case ANMACLHWSV: return OPVCC(4,494,1,0);
+ case ANMACLHWSVCC: return OPVCC(4,494,1,1);
+ case ANMACLHWV: return OPVCC(4,430,1,0);
+ case ANMACLHWVCC: return OPVCC(4,430,1,1);
+
+ case ANAND: return OPVCC(31,476,0,0);
+ case ANANDCC: return OPVCC(31,476,0,1);
+ case ANEG: return OPVCC(31,104,0,0);
+ case ANEGCC: return OPVCC(31,104,0,1);
+ case ANEGV: return OPVCC(31,104,1,0);
+ case ANEGVCC: return OPVCC(31,104,1,1);
+ case ANOR: return OPVCC(31,124,0,0);
+ case ANORCC: return OPVCC(31,124,0,1);
+ case AOR: return OPVCC(31,444,0,0);
+ case AORCC: return OPVCC(31,444,0,1);
+ case AORN: return OPVCC(31,412,0,0);
+ case AORNCC: return OPVCC(31,412,0,1);
+
+ case ARFI: return OPVCC(19,50,0,0);
+ case ARFCI: return OPVCC(19,51,0,0);
+
+ case ARLWMI: return OPVCC(20,0,0,0);
+ case ARLWMICC: return OPVCC(20,0,0,1);
+ case ARLWNM: return OPVCC(23,0,0,0);
+ case ARLWNMCC: return OPVCC(23,0,0,1);
+
+ case ASYSCALL: return OPVCC(17,1,0,0);
+
+ case ASLW: return OPVCC(31,24,0,0);
+ case ASLWCC: return OPVCC(31,24,0,1);
+
+ case ASRAW: return OPVCC(31,792,0,0);
+ case ASRAWCC: return OPVCC(31,792,0,1);
+
+ case ASRW: return OPVCC(31,536,0,0);
+ case ASRWCC: return OPVCC(31,536,0,1);
+
+ case ASUB: return OPVCC(31,40,0,0);
+ case ASUBCC: return OPVCC(31,40,0,1);
+ case ASUBV: return OPVCC(31,40,1,0);
+ case ASUBVCC: return OPVCC(31,40,1,1);
+ case ASUBC: return OPVCC(31,8,0,0);
+ case ASUBCCC: return OPVCC(31,8,0,1);
+ case ASUBCV: return OPVCC(31,8,1,0);
+ case ASUBCVCC: return OPVCC(31,8,1,1);
+ case ASUBE: return OPVCC(31,136,0,0);
+ case ASUBECC: return OPVCC(31,136,0,1);
+ case ASUBEV: return OPVCC(31,136,1,0);
+ case ASUBEVCC: return OPVCC(31,136,1,1);
+ case ASUBME: return OPVCC(31,232,0,0);
+ case ASUBMECC: return OPVCC(31,232,0,1);
+ case ASUBMEV: return OPVCC(31,232,1,0);
+ case ASUBMEVCC: return OPVCC(31,232,1,1);
+ case ASUBZE: return OPVCC(31,200,0,0);
+ case ASUBZECC: return OPVCC(31,200,0,1);
+ case ASUBZEV: return OPVCC(31,200,1,0);
+ case ASUBZEVCC: return OPVCC(31,200,1,1);
+
+ case ASYNC: return OPVCC(31,598,0,0);
+ case ATLBIE: return OPVCC(31,306,0,0);
+ case ATW: return OPVCC(31,4,0,0);
+
+ case AXOR: return OPVCC(31,316,0,0);
+ case AXORCC: return OPVCC(31,316,0,1);
+ }
+ diag("bad r/r opcode %A", a);
+ return 0;
+}
+
+long
+opirr(int a)
+{
+ switch(a) {
+ case AADD: return OPVCC(14,0,0,0);
+ case AADDC: return OPVCC(12,0,0,0);
+ case AADDCCC: return OPVCC(13,0,0,0);
+ case AADD+AEND: return OPVCC(15,0,0,0); /* ADDIS/CAU */
+
+ case AANDCC: return OPVCC(28,0,0,0);
+ case AANDCC+AEND: return OPVCC(29,0,0,0); /* ANDIS./ANDIU. */
+
+ case ABR: return OPVCC(18,0,0,0);
+ case ABL: return OPVCC(18,0,0,0) | 1;
+ case ABC: return OPVCC(16,0,0,0);
+ case ABCL: return OPVCC(16,0,0,0) | 1;
+
+ case ABEQ: return AOP_RRR(16<<26,12,2,0);
+ case ABGE: return AOP_RRR(16<<26,4,0,0);
+ case ABGT: return AOP_RRR(16<<26,12,1,0);
+ case ABLE: return AOP_RRR(16<<26,4,1,0);
+ case ABLT: return AOP_RRR(16<<26,12,0,0);
+ case ABNE: return AOP_RRR(16<<26,4,2,0);
+ case ABVC: return AOP_RRR(16<<26,4,3,0);
+ case ABVS: return AOP_RRR(16<<26,12,3,0);
+
+ case ACMP: return OPVCC(11,0,0,0);
+ case ACMPU: return OPVCC(10,0,0,0);
+ case ALSW: return OPVCC(31,597,0,0);
+
+ case AMULLW: return OPVCC(7,0,0,0);
+
+ case AOR: return OPVCC(24,0,0,0);
+ case AOR+AEND: return OPVCC(25,0,0,0); /* ORIS/ORIU */
+
+ case ARLWMI: return OPVCC(20,0,0,0); /* rlwimi */
+ case ARLWMICC: return OPVCC(20,0,0,1);
+
+ case ARLWNM: return OPVCC(21,0,0,0); /* rlwinm */
+ case ARLWNMCC: return OPVCC(21,0,0,1);
+
+ case ASRAW: return OPVCC(31,824,0,0);
+ case ASRAWCC: return OPVCC(31,824,0,1);
+
+ case ASTSW: return OPVCC(31,725,0,0);
+
+ case ASUBC: return OPVCC(8,0,0,0);
+
+ case ATW: return OPVCC(3,0,0,0);
+
+ case AXOR: return OPVCC(26,0,0,0); /* XORIL */
+ case AXOR+AEND: return OPVCC(27,0,0,0); /* XORIU */
+ }
+ diag("bad opcode i/r %A", a);
+ return 0;
+}
+
+/*
+ * load o(a),d
+ */
+long
+opload(int a)
+{
+ switch(a) {
+ case AMOVW: return OPVCC(32,0,0,0); /* lwz */
+ case AMOVWU: return OPVCC(33,0,0,0); /* lwzu */
+ case AMOVB:
+ case AMOVBZ: return OPVCC(34,0,0,0); /* load */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(35,0,0,0);
+ case AFMOVD: return OPVCC(50,0,0,0);
+ case AFMOVDU: return OPVCC(51,0,0,0);
+ case AFMOVS: return OPVCC(48,0,0,0);
+ case AFMOVSU: return OPVCC(49,0,0,0);
+ case AMOVH: return OPVCC(42,0,0,0);
+ case AMOVHU: return OPVCC(43,0,0,0);
+ case AMOVHZ: return OPVCC(40,0,0,0);
+ case AMOVHZU: return OPVCC(41,0,0,0);
+ case AMOVMW: return OPVCC(46,0,0,0); /* lmw */
+ }
+ diag("bad load opcode %A", a);
+ return 0;
+}
+
+/*
+ * indexed load a(b),d
+ */
+long
+oploadx(int a)
+{
+ switch(a) {
+ case AMOVW: return OPVCC(31,23,0,0); /* lwzx */
+ case AMOVWU: return OPVCC(31,55,0,0); /* lwzux */
+ case AMOVB:
+ case AMOVBZ: return OPVCC(31,87,0,0); /* lbzx */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(31,119,0,0); /* lbzux */
+ case AFMOVD: return OPVCC(31,599,0,0); /* lfdx */
+ case AFMOVDU: return OPVCC(31,631,0,0); /* lfdux */
+ case AFMOVS: return OPVCC(31,535,0,0); /* lfsx */
+ case AFMOVSU: return OPVCC(31,567,0,0); /* lfsux */
+ case AMOVH: return OPVCC(31,343,0,0); /* lhax */
+ case AMOVHU: return OPVCC(31,375,0,0); /* lhaux */
+ case AMOVHBR: return OPVCC(31,790,0,0); /* lhbrx */
+ case AMOVWBR: return OPVCC(31,534,0,0); /* lwbrx */
+ case AMOVHZ: return OPVCC(31,279,0,0); /* lhzx */
+ case AMOVHZU: return OPVCC(31,311,0,0); /* lhzux */
+ case AECIWX: return OPVCC(31,310,0,0); /* eciwx */
+ case ALWAR: return OPVCC(31,20,0,0); /* lwarx */
+ case ALSW: return OPVCC(31,533,0,0); /* lswx */
+ }
+ diag("bad loadx opcode %A", a);
+ return 0;
+}
+
+/*
+ * store s,o(d)
+ */
+long
+opstore(int a)
+{
+ switch(a) {
+ case AMOVB:
+ case AMOVBZ: return OPVCC(38,0,0,0); /* stb */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(39,0,0,0); /* stbu */
+ case AFMOVD: return OPVCC(54,0,0,0); /* stfd */
+ case AFMOVDU: return OPVCC(55,0,0,0); /* stfdu */
+ case AFMOVS: return OPVCC(52,0,0,0); /* stfs */
+ case AFMOVSU: return OPVCC(53,0,0,0); /* stfsu */
+ case AMOVHZ:
+ case AMOVH: return OPVCC(44,0,0,0); /* sth */
+ case AMOVHZU:
+ case AMOVHU: return OPVCC(45,0,0,0); /* sthu */
+ case AMOVMW: return OPVCC(47,0,0,0); /* stmw */
+ case ASTSW: return OPVCC(31,725,0,0); /* stswi */
+ case AMOVW: return OPVCC(36,0,0,0); /* stw */
+ case AMOVWU: return OPVCC(37,0,0,0); /* stwu */
+ }
+ diag("unknown store opcode %A", a);
+ return 0;
+}
+
+/*
+ * indexed store s,a(b)
+ */
+long
+opstorex(int a)
+{
+ switch(a) {
+ case AMOVB:
+ case AMOVBZ: return OPVCC(31,215,0,0); /* stbx */
+ case AMOVBU:
+ case AMOVBZU: return OPVCC(31,247,0,0); /* stbux */
+ case AFMOVD: return OPVCC(31,727,0,0); /* stfdx */
+ case AFMOVDU: return OPVCC(31,759,0,0); /* stfdux */
+ case AFMOVS: return OPVCC(31,663,0,0); /* stfsx */
+ case AFMOVSU: return OPVCC(31,695,0,0); /* stfsux */
+ case AMOVHZ:
+ case AMOVH: return OPVCC(31,407,0,0); /* sthx */
+ case AMOVHBR: return OPVCC(31,918,0,0); /* sthbrx */
+ case AMOVHZU:
+ case AMOVHU: return OPVCC(31,439,0,0); /* sthux */
+ case AMOVW: return OPVCC(31,151,0,0); /* stwx */
+ case AMOVWU: return OPVCC(31,183,0,0); /* stwux */
+ case ASTSW: return OPVCC(31,661,0,0); /* stswx */
+ case AMOVWBR: return OPVCC(31,662,0,0); /* stwbrx */
+ case ASTWCCC: return OPVCC(31,150,0,1); /* stwcx. */
+ case AECOWX: return OPVCC(31,438,0,0); /* ecowx */
+ }
+ diag("unknown storex opcode %A", a);
+ return 0;
+}
diff --git a/utils/ql/cnam.c b/utils/ql/cnam.c
new file mode 100644
index 00000000..bc6d8c2b
--- /dev/null
+++ b/utils/ql/cnam.c
@@ -0,0 +1,37 @@
+char *cnames[] =
+{
+ "NONE",
+ "REG",
+ "FREG",
+ "CREG",
+ "SPR",
+ "SREG",
+ "ZCON",
+ "SCON",
+ "UCON",
+ "ADDCON",
+ "ANDCON",
+ "LCON",
+ "SACON",
+ "SECON",
+ "LACON",
+ "LECON",
+ "SBRA",
+ "LBRA",
+ "SAUTO",
+ "LAUTO",
+ "SEXT",
+ "LEXT",
+ "ZOREG",
+ "SOREG",
+ "LOREG",
+ "FPSCR",
+ "MSR",
+ "XER",
+ "LR",
+ "CTR",
+ "ANY",
+ "GOK",
+ "ADDR",
+ "NCLASS",
+};
diff --git a/utils/ql/l.h b/utils/ql/l.h
new file mode 100644
index 00000000..7ec4aa60
--- /dev/null
+++ b/utils/ql/l.h
@@ -0,0 +1,335 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../qc/q.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Adr Adr;
+typedef struct Sym Sym;
+typedef struct Autom Auto;
+typedef struct Prog Prog;
+typedef struct Optab Optab;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ long u0offset;
+ char u0sval[NSNAME];
+ Ieee u0ieee;
+ }u0;
+ Sym *sym;
+ Auto *autom;
+ char type;
+ uchar reg;
+ char name;
+ char class;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define ieee u0.u0ieee
+
+struct Prog
+{
+ Adr from;
+ Adr from3; /* fma and rlwm */
+ Adr to;
+ Prog *forwd;
+ Prog *cond;
+ Prog *link;
+ long pc;
+ long regused;
+ short line;
+ short mark;
+ short optab; /* could be uchar */
+ uchar as;
+ char reg;
+};
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ uchar subtype;
+ ushort file;
+ long value;
+ long sig;
+ Sym *link;
+};
+struct Autom
+{
+ Sym *sym;
+ Auto *link;
+ long aoffset;
+ short type;
+};
+struct Optab
+{
+ uchar as;
+ char a1;
+ char a2;
+ char a3;
+ char a4;
+ char type;
+ char size;
+ char param;
+};
+struct
+{
+ Optab* start;
+ Optab* stop;
+} oprange[ALAST];
+
+enum
+{
+ FPCHIP = 1,
+ BIG = 32768-8,
+ STRINGSZ = 200,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+ DATBLK = 1024,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ NSCHED = 20,
+
+/* mark flags */
+ LABEL = 1<<0,
+ LEAF = 1<<1,
+ FLOAT = 1<<2,
+ BRANCH = 1<<3,
+ LOAD = 1<<4,
+ FCMP = 1<<5,
+ SYNC = 1<<6,
+ LIST = 1<<7,
+ FOLL = 1<<8,
+ NOSCHED = 1<<9,
+
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SLEAF,
+ SFILE,
+ SCONST,
+ SUNDEF,
+
+ SIMPORT,
+ SEXPORT,
+
+ C_NONE = 0,
+ C_REG,
+ C_FREG,
+ C_CREG,
+ C_SPR, /* special processor register */
+ C_SREG, /* segment register (32 bit implementations only) */
+ C_ZCON,
+ C_SCON, /* 16 bit signed */
+ C_UCON, /* low 16 bits 0 */
+ C_ADDCON, /* -0x8000 <= v < 0 */
+ C_ANDCON, /* 0 < v <= 0xFFFF */
+ C_LCON, /* other */
+ C_SACON,
+ C_SECON,
+ C_LACON,
+ C_LECON,
+ C_SBRA,
+ C_LBRA,
+ C_SAUTO,
+ C_LAUTO,
+ C_SEXT,
+ C_LEXT,
+ C_ZOREG,
+ C_SOREG,
+ C_LOREG,
+ C_FPSCR,
+ C_MSR,
+ C_XER,
+ C_LR,
+ C_CTR,
+ C_ANY,
+ C_GOK,
+ C_ADDR,
+
+ C_NCLASS,
+
+ Roffset = 22, /* no. bits for offset in relocation address */
+ Rindex = 10 /* no. bits for index in relocation address */
+};
+
+EXTERN union
+{
+ struct
+ {
+ uchar obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+EXTERN long HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN long INITDAT; /* data location */
+EXTERN long INITRND; /* data round above text location */
+EXTERN long INITTEXT; /* text location */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN long autosize;
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN uchar* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN Prog* prog_movsw;
+EXTERN Prog* prog_movdw;
+EXTERN Prog* prog_movws;
+EXTERN Prog* prog_movwd;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* firstp;
+EXTERN char fnuxi8[8];
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN char* noname;
+EXTERN long instoffset;
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN int r0iszero;
+EXTERN long symsize;
+EXTERN long staticgen;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long tothunk;
+EXTERN char xcmp[C_NCLASS][C_NCLASS];
+EXTERN int version;
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+EXTERN int doexp, dlm;
+EXTERN int imports, nimports;
+EXTERN int exports, nexports;
+EXTERN char* EXPTAB;
+EXTERN Prog undefp;
+
+#define UP (&undefp)
+
+extern Optab optab[];
+extern char* anames[];
+extern char* cnames[];
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Nconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int Rconv(Fmt*);
+int aclass(Adr*);
+void addhist(long, int);
+void histtoauto(void);
+void addnop(Prog*);
+void append(Prog*, Prog*);
+void asmb(void);
+void asmdyn(void);
+void asmlc(void);
+int asmout(Prog*, Optab*, int);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void cflush(void);
+void ckoff(Sym*, long);
+int cmp(int, int);
+void cput(long);
+int compound(Prog*);
+double cputime(void);
+void datblk(long, long);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+void dynreloc(Sym*, long, int, int, int);
+long entryvalue(void);
+void errorexit(void);
+void exchange(Prog*);
+void export(void);
+int find1(long, int);
+void follow(void);
+void gethunk(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+void import(void);
+int isnop(Prog*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+void initmuldiv(void);
+Sym* lookup(char*, int);
+void lput(long);
+void mkfwd(void);
+void* mysbrk(ulong);
+void names(void);
+void nocache(Prog*);
+void noops(void);
+void nuxiinit(void);
+void objfile(char*);
+int ocmp(void*, void*);
+long opcode(int);
+Optab* oplook(Prog*);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+void putsymb(char*, int, long, int);
+void readundefs(char*, int);
+long regoff(Adr*);
+int relinv(int);
+long rnd(long, long);
+void sched(Prog*, Prog*);
+void span(void);
+void undef(void);
+void undefsym(Sym*);
+void wput(long);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+void zerosig(char*);
+
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "A" int
+#pragma varargck type "S" char*
diff --git a/utils/ql/list.c b/utils/ql/list.c
new file mode 100644
index 00000000..28578779
--- /dev/null
+++ b/utils/ql/list.c
@@ -0,0 +1,311 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('R', Rconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ if(a == ADATA || a == AINIT || a == ADYNT)
+ sprint(str, "(%d) %A %D/%d,%D", p->line, a, &p->from, p->reg, &p->to);
+ else {
+ s = str;
+ if(p->mark & NOSCHED)
+ s += sprint(s, "*");
+ if(p->reg == NREG && p->from3.type == D_NONE)
+ sprint(s, "(%d) %A %D,%D", p->line, a, &p->from, &p->to);
+ else
+ if(a != ATEXT && p->from.type == D_OREG) {
+ sprint(s, "(%d) %A %ld(R%d+R%d),%D", p->line, a,
+ p->from.offset, p->from.reg, p->reg, &p->to);
+ } else
+ if(p->to.type == D_OREG) {
+ sprint(s, "(%d) %A %D,%ld(R%d+R%d)", p->line, a,
+ &p->from, p->to.offset, p->to.reg, p->reg);
+ } else {
+ s += sprint(s, "(%d) %A %D", p->line, a, &p->from);
+ if(p->reg != NREG)
+ s += sprint(s, ",%c%d", p->from.type==D_FREG?'F':'R', p->reg);
+ if(p->from3.type != D_NONE)
+ s += sprint(s, ",%D", &p->from3);
+ sprint(s, ",%D", &p->to);
+ }
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ long v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(F%d)(REG)", a, a->reg);
+ break;
+
+ case D_CREG:
+ if(a->reg == NREG)
+ strcpy(str, "CR");
+ else
+ sprint(str, "CR%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(C%d)(REG)", a, a->reg);
+ break;
+
+ case D_SPR:
+ if(a->name == D_NONE && a->sym == S) {
+ switch(a->offset) {
+ case D_XER: sprint(str, "XER"); break;
+ case D_LR: sprint(str, "LR"); break;
+ case D_CTR: sprint(str, "CTR"); break;
+ default: sprint(str, "SPR(%ld)", a->offset); break;
+ }
+ break;
+ }
+ sprint(str, "SPR-GOK(%d)", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(SPR-GOK%d)(REG)", a, a->reg);
+ break;
+
+ case D_DCR:
+ if(a->name == D_NONE && a->sym == S) {
+ sprint(str, "DCR(%ld)", a->offset);
+ break;
+ }
+ sprint(str, "DCR-GOK(%d)", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(DCR-GOK%d)(REG)", a, a->reg);
+ break;
+
+ case D_OPT:
+ sprint(str, "OPT(%d)", a->reg);
+ break;
+
+ case D_FPSCR:
+ if(a->reg == NREG)
+ strcpy(str, "FPSCR");
+ else
+ sprint(str, "FPSCR(%d)", a->reg);
+ break;
+
+ case D_MSR:
+ sprint(str, "MSR");
+ break;
+
+ case D_SREG:
+ sprint(str, "SREG(%d)", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(SREG%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH:
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(v >= INITTEXT)
+ v -= INITTEXT-HEADR;
+ if(a->sym != S)
+ sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5lux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%ld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "C_??";
+ if(a >= C_NONE && a <= C_NCLASS)
+ s = cnames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(long); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/ql/mkcname b/utils/ql/mkcname
new file mode 100644
index 00000000..cc93d9db
--- /dev/null
+++ b/utils/ql/mkcname
@@ -0,0 +1,17 @@
+ed - ../ql/l.h <<'!'
+v/^ C_/d
+g/^ C_NCLASS/s//&,/
+g/[ ]*=.*,/s//,/
+v/,/p
+,s/^ C_/ "/
+,s/,.*$/",/
+1i
+char *cnames[] =
+{
+.
+,a
+};
+.
+w cnam.c
+Q
+!
diff --git a/utils/ql/mkfile b/utils/ql/mkfile
new file mode 100644
index 00000000..19391282
--- /dev/null
+++ b/utils/ql/mkfile
@@ -0,0 +1,33 @@
+<../../mkconfig
+
+TARG=ql
+
+OFILES=\
+ asm.$O\
+ list.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ enam.$O\
+ noop.$O\
+ asmout.$O\
+ cnam.$O\
+ sched.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../qc/q.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+enam.$O: ../qc/enam.c
+ $CC $CFLAGS ../qc/enam.c
diff --git a/utils/ql/noop.c b/utils/ql/noop.c
new file mode 100644
index 00000000..abb35057
--- /dev/null
+++ b/utils/ql/noop.c
@@ -0,0 +1,513 @@
+#include "l.h"
+
+void
+noops(void)
+{
+ Prog *p, *p1, *q, *q1;
+ int o, mov, aoffset, curframe, curbecome, maxbecome;
+
+ /*
+ * find leaf subroutines
+ * become sizes
+ * frame sizes
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+ q = P;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == D_OREG && p->to.reg == REGSP)
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ /* too hard, just leave alone */
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ q = p;
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ curtext = p;
+ break;
+
+ case ANOR:
+ q = p;
+ if(p->to.type == D_REG)
+ if(p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ALWAR:
+ case ASTWCCC:
+ case AECIWX:
+ case AECOWX:
+ case AEIEIO:
+ case AICBI:
+ case AISYNC:
+ case ATLBIE:
+ case ADCBF:
+ case ADCBI:
+ case ADCBST:
+ case ADCBT:
+ case ADCBTST:
+ case ADCBZ:
+ case ASYNC:
+ case ATW:
+ case AWORD:
+ case ARFI:
+ case ARFCI:
+ q = p;
+ p->mark |= LABEL|SYNC;
+ continue;
+
+ case AMOVW:
+ q = p;
+ switch(p->from.type) {
+ case D_MSR:
+ case D_SREG:
+ case D_SPR:
+ case D_FPSCR:
+ case D_CREG:
+ case D_DCR:
+ p->mark |= LABEL|SYNC;
+ }
+ switch(p->to.type) {
+ case D_MSR:
+ case D_SREG:
+ case D_SPR:
+ case D_FPSCR:
+ case D_CREG:
+ case D_DCR:
+ p->mark |= LABEL|SYNC;
+ }
+ continue;
+
+ case AFABS:
+ case AFABSCC:
+ case AFADD:
+ case AFADDCC:
+ case AFCTIW:
+ case AFCTIWCC:
+ case AFCTIWZ:
+ case AFCTIWZCC:
+ case AFDIV:
+ case AFDIVCC:
+ case AFMADD:
+ case AFMADDCC:
+ case AFMOVD:
+ case AFMOVDU:
+ /* case AFMOVDS: */
+ case AFMOVS:
+ case AFMOVSU:
+ /* case AFMOVSD: */
+ case AFMSUB:
+ case AFMSUBCC:
+ case AFMUL:
+ case AFMULCC:
+ case AFNABS:
+ case AFNABSCC:
+ case AFNEG:
+ case AFNEGCC:
+ case AFNMADD:
+ case AFNMADDCC:
+ case AFNMSUB:
+ case AFNMSUBCC:
+ case AFRSP:
+ case AFRSPCC:
+ case AFSUB:
+ case AFSUBCC:
+ q = p;
+ p->mark |= FLOAT;
+ continue;
+
+ case ABL:
+ case ABCL:
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+
+ case ABC:
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABR:
+ case ABVC:
+ case ABVS:
+
+ p->mark |= BRANCH;
+ q = p;
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != P)
+ q1->mark |= LABEL;
+ continue;
+
+ case AFCMPO:
+ case AFCMPU:
+ q = p;
+ p->mark |= FCMP|FLOAT;
+ continue;
+
+ case ARETURN:
+ /* special form of RETURN is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+
+ q = p;
+ if(p->link != P)
+ p->link->mark |= LABEL;
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ default:
+ q = p;
+ continue;
+ }
+ }
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+
+ case ABL: /* ABCL? */
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ o = maxbecome - curtext->from.sym->frame;
+ if(o <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += o;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, o);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ curtext = P;
+ for(p = firstp; p != P; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ mov = AMOVW;
+ aoffset = 0;
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if((p->mark & LEAF) && autosize <= 4)
+ autosize = 0;
+ else
+ if(autosize & 4)
+ autosize += 4;
+ p->to.offset = autosize - 4;
+
+ q = p;
+ if(autosize) {
+ /* use MOVWU to adjust R1 when saving R31, if autosize is small */
+ if(!(curtext->mark & LEAF) && autosize >= -BIG && autosize <= BIG) {
+ mov = AMOVWU;
+ aoffset = -autosize;
+ } else {
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = -autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+ } else
+ if(!(curtext->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ curtext->from.sym->name);
+ curtext->mark |= LEAF;
+ }
+
+ if(curtext->mark & LEAF) {
+ if(curtext->from.sym)
+ curtext->from.sym->type = SLEAF;
+ break;
+ }
+
+ q1 = prg();
+ q1->as = mov;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMP;
+ q1->to.type = D_OREG;
+ q1->to.offset = aoffset;
+ q1->to.reg = REGSP;
+
+ q1->link = q->link;
+ q->link = q1;
+
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_SPR;
+ q1->from.offset = D_LR;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMP;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case ARETURN:
+ if(p->from.type == D_CONST)
+ goto become;
+ if(curtext->mark & LEAF) {
+ if(!autosize) {
+ p->as = ABR;
+ p->from = zprg.from;
+ p->to.type = D_SPR;
+ p->to.offset = D_LR;
+ p->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ q = prg();
+ q->as = ABR;
+ q->line = p->line;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+ q->mark |= BRANCH;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGTMP;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ if(autosize) {
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = prg();
+ q1->as = ABR;
+ q1->line = p->line;
+ q1->to.type = D_SPR;
+ q1->to.offset = D_LR;
+ q1->mark |= BRANCH;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ become:
+ if(curtext->mark & LEAF) {
+
+ q = prg();
+ q->line = p->line;
+ q->as = ABR;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ p->as = AADD;
+ p->from = zprg.from;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ break;
+ }
+ q = prg();
+ q->line = p->line;
+ q->as = ABR;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->mark |= BRANCH;
+ q->link = p->link;
+ p->link = q;
+
+ q = prg();
+ q->line = p->line;
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+
+ q = prg();
+ q->line = p->line;
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGTMP;
+ q->to.type = D_SPR;
+ q->to.offset = D_LR;
+ q->link = p->link;
+ p->link = q;
+
+ p->as = AMOVW;
+ p->from = zprg.from;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ break;
+ }
+ }
+
+ if(debug['Q'] == 0)
+ return;
+
+ curtext = P;
+ q = P; /* p - 1 */
+ q1 = firstp; /* top of block */
+ o = 0; /* count of instructions */
+ for(p = firstp; p != P; p = p1) {
+ p1 = p->link;
+ o++;
+ if(p->mark & NOSCHED){
+ if(q1 != p){
+ sched(q1, q);
+ }
+ for(; p != P; p = p->link){
+ if(!(p->mark & NOSCHED))
+ break;
+ q = p;
+ }
+ p1 = p;
+ q1 = p;
+ o = 0;
+ continue;
+ }
+ if(p->mark & (LABEL|SYNC)) {
+ if(q1 != p)
+ sched(q1, q);
+ q1 = p;
+ o = 1;
+ }
+ if(p->mark & (BRANCH|SYNC)) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ if(o >= NSCHED) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ q = p;
+ }
+}
+
+void
+addnop(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = ANOR;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGZERO;
+ q->to.type = D_REG;
+ q->to.reg = REGZERO;
+
+ q->link = p->link;
+ p->link = q;
+}
diff --git a/utils/ql/obj.c b/utils/ql/obj.c
new file mode 100644
index 00000000..a4e76c1c
--- /dev/null
+++ b/utils/ql/obj.c
@@ -0,0 +1,1465 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = 'q';
+char *thestring = "power";
+
+/*
+ * -H0 -T0x200000 -R0 is boot
+ * -H1 -T0x100000 -R4 is Be boot
+ * -H2 -T4128 -R4096 is plan9 format
+ * -H3 -T0x02010000 -D0x00001000 is raw
+ * -H4 -T0x1000200 -D0x20000e00 -R4 is aix xcoff executable
+ * -H5 -T0x80010000 -t0x10000 ELF, phys = 10000, vaddr = 0x8001...
+ */
+
+static int
+isobjfile(char *f)
+{
+ int n, v;
+ Biobuf *b;
+ char buf1[5], buf2[SARMAG];
+
+ b = Bopen(f, OREAD);
+ if(b == nil)
+ return 0;
+ n = Bread(b, buf1, 5);
+ if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
+ v = 1; /* good enough for our purposes */
+ else{
+ Bseek(b, 0, 0);
+ n = Bread(b, buf2, SARMAG);
+ v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
+ }
+ Bterm(b);
+ return v;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ outfile = 0;
+ nerrors = 0;
+ curtext = P;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'x': /* produce export table */
+ doexp = 1;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SEXPORT);
+ break;
+ case 'u': /* produce dynamically loadable module */
+ dlm = 1;
+ if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+ readundefs(ARGF(), SIMPORT);
+ break;
+ } ARGEND
+ USED(argc);
+ if(*argv == 0) {
+ diag("usage: ql [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ r0iszero = debug['0'] == 0;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 0;
+ if(debug['B'])
+ HEADTYPE = 1;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case 0: /* boot */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x200000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096L;
+ break;
+ case 1: /* Be boot format (PEF) */
+ HEADR = 208L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x100000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* raw */
+ HEADR = 0;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1) {
+ INITDAT = 0;
+ INITRND = 4;
+ }
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 4: /* aix unix xcoff executable */
+ HEADR = 20L+72L+3*40L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x1000000L+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0x20000000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 5: /* elf executable */
+ HEADR = rnd(52L+3*32L, 16);
+ if(INITTEXT == -1)
+ INITTEXT = 0x00400000L+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%x -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.from3 = zprg.from;
+ zprg.to = zprg.from;
+ buildop();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ dtype = 4;
+ if(outfile == 0)
+ outfile = "q.out";
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("%s: cannot create", outfile);
+ errorexit();
+ }
+ nuxiinit();
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ goto out;
+ if(doexp || dlm){
+ EXPTAB = "_exporttab";
+ zerosig(EXPTAB);
+ zerosig("etext");
+ zerosig("edata");
+ zerosig("end");
+ if(dlm){
+ import();
+ HEADTYPE = 2;
+ INITTEXT = INITDAT = 0;
+ INITRND = 8;
+ INITENTRY = EXPTAB;
+ }
+ export();
+ }
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ dodata();
+ follow();
+ if(firstp == P)
+ goto out;
+ noops();
+ span();
+ asmb();
+ undef();
+
+out:
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld memory used\n", tothunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ Bflush(&bso);
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int i, c;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ c = p[2];
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ p[0] = AEND+1;
+ return 0;
+ }
+ a->type = p[0];
+ a->reg = p[1];
+ a->sym = h[c];
+ a->name = p[3];
+ c = 4;
+
+ if(a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ p[0] = AEND+1;
+ return 0; /* force real diagnostic */
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ p[0] = AEND+1;
+ return 0; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_CREG:
+ case D_FPSCR:
+ case D_MSR:
+ case D_SREG:
+ case D_OPT:
+ break;
+
+ case D_SPR:
+ case D_DCR:
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ a->offset = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ c += 4;
+ break;
+
+ case D_SCONST:
+ memmove(a->sval, p+4, NSNAME);
+ c += NSNAME;
+ break;
+
+ case D_FCONST:
+ a->ieee.l = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ a->ieee.h = p[8] | (p[9]<<8) |
+ (p[10]<<16) | (p[11]<<24);
+ c += 8;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto out;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ goto out;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->sym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ goto out;
+ }
+
+ u = malloc(sizeof(Auto));
+
+ u->link = curauto;
+ curauto = u;
+ u->sym = s;
+ u->aoffset = l;
+ u->type = i;
+out:
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->sym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ Prog *p, *t;
+ Sym *h[NSYM], *s, *di;
+ int v, o, r, skip;
+ long ipc;
+ uchar *bloc, *bsize, *stop;
+ ulong sig;
+ static int files;
+ static char **filen;
+ char **nfilen;
+
+ if((files&15) == 0){
+ nfilen = malloc((files+16)*sizeof(char*));
+ memmove(nfilen, filen, files*sizeof(char*));
+ free(filen);
+ filen = nfilen;
+ }
+ filen[files++] = strdup(pn);
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ histfrogp = 0;
+ version++;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0]; /* as */
+ if(o <= 0 || o >= ALAST) {
+ diag("%s: opcode out of range %d", pn, o);
+ print(" probably not a .q file\n");
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME) {
+ sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24);
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[1]; /* type */
+ o = bloc[2]; /* sym */
+ bloc += 3;
+ c -= 3;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
+ s->sig = sig;
+ s->file = files-1;
+ }
+
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ if(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->reg = bloc[1] & 0x3f;
+ if(bloc[1] & 0x80)
+ p->mark = NOSCHED;
+ p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ if(bloc[1] & 0x40)
+ r += zaddr(bloc+r, &p->from3, h);
+ else
+ p->from3 = zprg.from3;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(p->reg < 0 || p->reg > NREG)
+ diag("register out of range %d", p->reg);
+
+ p->link = P;
+ p->cond = P;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ break;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->reg = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_CONST;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case ADATA:
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ curtext = p;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
+ s = p->from.sym;
+ if(s == S) {
+ diag("TEXT must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->reg & DUPOK) {
+ skip = 1;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P", s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ if(textp != P) {
+ for(t = textp; t->cond != P; t = t->cond)
+ ;
+ t->cond = p;
+ } else
+ textp = p;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+
+ case AFMOVS:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 4;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AFMOVD:
+ if(skip)
+ goto casedef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee.l, p->from.ieee.h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case ASUBC:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADDC;
+ }
+ goto casedef;
+
+ case ASUBCCC:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADDCCC;
+ }
+ goto casedef;
+
+ case ASUB:
+ if(p->from.type == D_CONST) {
+ p->from.offset = -p->from.offset;
+ p->as = AADD;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ hash[h] = s;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+ int n;
+
+ n = (sizeof(Prog) + 3) & ~3;
+ while(nhunk < n)
+ gethunk();
+
+ p = (Prog*)hunk;
+ nhunk -= n;
+ hunk += n;
+
+ *p = zprg;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(tothunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(tothunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char *)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+
+ hunk = h;
+ nhunk = nh;
+ tothunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ p->reg = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->reg = 1;
+ ps4 = p;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+
+ if(p->reg & NOPROF) { /* dont profile */
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * BL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARETURN) {
+
+ /*
+ * RETURN
+ */
+ q = prg();
+ q->as = ARETURN;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BL profout
+ */
+ p->as = ABL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x01020304L, i+1);
+ if(i >= 2)
+ inuxi2[i-2] = c;
+ if(i >= 3)
+ inuxi1[i-3] = c;
+ inuxi4[i] = c;
+
+ fnuxi8[i] = c+4;
+ fnuxi8[i+4] = c;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+long
+ieeedtof(Ieee *ieeep)
+{
+ int exp;
+ long v;
+
+ if(ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (ieeep->h & 0xfffffL) << 3;
+ v |= (ieeep->l >> 29) & 0x7L;
+ if((ieeep->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= ieeep->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
+
+void
+undefsym(Sym *s)
+{
+ int n;
+
+ n = imports;
+ if(s->value != 0)
+ diag("value != 0 on SXREF");
+ if(n >= 1<<Rindex)
+ diag("import index %d out of range", n);
+ s->value = n<<Roffset;
+ s->type = SUNDEF;
+ imports++;
+}
+
+void
+zerosig(char *sp)
+{
+ Sym *s;
+
+ s = lookup(sp, 0);
+ s->sig = 0;
+}
+
+void
+readundefs(char *f, int t)
+{
+ int i, n;
+ Sym *s;
+ Biobuf *b;
+ char *l, buf[256], *fields[64];
+
+ if(f == nil)
+ return;
+ b = Bopen(f, OREAD);
+ if(b == nil){
+ diag("could not open %s: %r", f);
+ errorexit();
+ }
+ while((l = Brdline(b, '\n')) != nil){
+ n = Blinelen(b);
+ if(n >= sizeof(buf)){
+ diag("%s: line too long", f);
+ errorexit();
+ }
+ memmove(buf, l, n);
+ buf[n-1] = '\0';
+ n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
+ if(n == nelem(fields)){
+ diag("%s: bad format", f);
+ errorexit();
+ }
+ for(i = 0; i < n; i++){
+ s = lookup(fields[i], 0);
+ s->type = SXREF;
+ s->subtype = t;
+ if(t == SIMPORT)
+ nimports++;
+ else
+ nexports++;
+ }
+ }
+ Bterm(b);
+}
diff --git a/utils/ql/optab.c b/utils/ql/optab.c
new file mode 100644
index 00000000..8a9de1bb
--- /dev/null
+++ b/utils/ql/optab.c
@@ -0,0 +1,289 @@
+#include "l.h"
+
+Optab optab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_NONE, C_LCON, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_LCON, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, C_LCON, 0, 0, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
+
+ { AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AADD, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0 },
+ { AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
+ { AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
+
+ { AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AADDC, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AADDC, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
+ { AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
+
+ { AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, no literal */
+ { AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+
+ { AANDCC, C_ANDCON,C_NONE, C_NONE, C_REG, 58, 4, 0 },
+ { AANDCC, C_ANDCON,C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
+ { AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
+ { AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
+ { AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
+
+ { AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { AMULLW, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ANDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0 },
+ { AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+ { AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+
+ { ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0 },
+ { ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0},
+
+ { AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, literal not cc (or/xor) */
+ { AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0 },
+ { AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
+ { AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
+ { AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
+ { AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
+
+ { ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op r1[,r2],r3 */
+ { ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
+ { ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 }, /* op r2[,r1],r3 */
+ { ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
+
+ { ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0 },
+ { ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0 },
+
+ { ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
+ { ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
+ { ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
+
+ { ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0 },
+ { ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0 },
+
+ { AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0 },
+ { AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0 },
+ { AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+ { AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
+
+ { AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0 },
+ { AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0 },
+ { AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0 },
+
+ { AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AMOVW, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZU, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVBU, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVBZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVB, C_SAUTO,C_NONE, C_NONE, C_REG, 9, 8, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBZU, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
+ { AMOVBU, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+ { AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+
+ { AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
+ { AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVBZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
+ { AMOVB, C_LAUTO,C_NONE, C_NONE, C_REG, 37, 12, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVBZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
+ { AMOVB, C_LOREG,C_NONE, C_NONE, C_REG, 37, 12, REGZERO },
+ { AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
+ { AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0 },
+
+ { AMOVW, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVW, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
+ { AMOVW, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
+ { AMOVW, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+
+ { AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
+ { AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
+
+ { AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
+ { AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+ { AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+
+ { ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
+ { ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
+
+ { ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+
+ { ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0 },
+
+ { ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0 },
+ { ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
+ { ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
+
+ { ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0 },
+ { ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0 },
+ { ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0 },
+ { ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
+
+ { AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB },
+ { AFMOVD, C_SAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP },
+ { AFMOVD, C_SOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO },
+
+ { AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB },
+ { AFMOVD, C_LAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP },
+ { AFMOVD, C_LOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO },
+ { AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0 },
+
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 7, 4, REGSB },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 7, 4, REGSP },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 7, 4, REGZERO },
+ { AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
+
+ { ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
+ { AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0 },
+
+ { AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+
+ { AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0 },
+ { AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0 },
+
+ { ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+ { ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0 },
+
+ { AREM, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 },
+ { AREM, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 },
+
+ { AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0 },
+ { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0 },
+ { AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0 },
+ { AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0 },
+ { AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 },
+ { AMOVW, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0 },
+
+ { AMOVW, C_SREG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SREG, 55, 4, 0 },
+ { AMOVW, C_SREG, C_REG, C_NONE, C_REG, 55, 4, 0 }, /* MOVW SR(Rn), Rm and v.v.*/
+ { AMOVW, C_REG, C_REG, C_NONE, C_SREG, 55, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
+ { AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVW, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVW, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+ { AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
+
+ { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0 },
+ { AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0 },
+ { AMOVW, C_XER, C_NONE, C_NONE, C_CREG, 72, 4, 0 },
+ { AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
+ { AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0 },
+ { AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
+
+ { ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
+ { ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0 },
+
+ { ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
+ { ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
+ { ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0 },
+ { ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0 },
+
+ { AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0 },
+ { AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0 },
+
+ { ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0 },
+ { ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0 },
+
+ { ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0 },
+ { ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0 },
+
+ { AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
+ { AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+ { AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+
+ { AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
+ { ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0 },
+
+ { ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
+ { ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0 },
+ { ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
+ { ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0 },
+
+ { AMACCHW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op rb,ra,rt */
+
+ { AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
diff --git a/utils/ql/pass.c b/utils/ql/pass.c
new file mode 100644
index 00000000..1a4fc7b0
--- /dev/null
+++ b/utils/ql/pass.c
@@ -0,0 +1,667 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i, t;
+ Sym *s;
+ Prog *p, *p1;
+ long orig, orig1, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ v = p->from.offset + p->reg;
+ if(v > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ /*
+ * pass 1
+ * assign 'small' variables to data segment
+ * (rational is that data segment is more easily
+ * addressed through offset on REGSB)
+ */
+ orig = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA && t != SBSS)
+ continue;
+ v = s->value;
+ if(v == 0) {
+ diag("%s: no size", s->name);
+ v = 1;
+ }
+ while(v & 3)
+ v++;
+ s->value = v;
+ if(v > MINSIZ)
+ continue;
+ if(v >= 8)
+ while(orig & 7)
+ orig++;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+ orig1 = orig;
+
+ /*
+ * pass 2
+ * assign 'data' variables to data segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA) {
+ if(t == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ v = s->value;
+ if(v >= 8)
+ while(orig & 7)
+ orig++;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+
+ while(orig & 7)
+ orig++;
+ datsize = orig;
+
+ /*
+ * pass 3
+ * everything else to bss segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ v = s->value;
+ if(v >= 8)
+ while(orig & 7)
+ orig++;
+ s->value = orig;
+ orig += v;
+ }
+ while(orig & 7)
+ orig++;
+ bsssize = orig-datsize;
+
+ /*
+ * pass 4
+ * add literals to all large values.
+ * at this time:
+ * small data is allocated DATA
+ * large data is allocated DATA1
+ * large bss is allocated BSS
+ * the new literals are loaded between
+ * small data and large data.
+ */
+ orig = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as != AMOVW)
+ continue;
+ if(p->from.type != D_CONST)
+ continue;
+ if(s = p->from.sym) {
+ t = s->type;
+ if(t != SDATA && t != SDATA1 && t != SBSS)
+ continue;
+ t = p->from.name;
+ if(t != D_EXTERN && t != D_STATIC)
+ continue;
+ v = s->value + p->from.offset;
+ if(v >= 0 && v <= 0xffff)
+ continue;
+ if(!strcmp(s->name, "setSB"))
+ continue;
+ /* size should be 19 max */
+ if(strlen(s->name) >= 10) /* has loader address */
+ sprint(literal, "$%p.%lux", s, p->from.offset);
+ else
+ sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset);
+ } else {
+ if(p->from.name != D_NONE)
+ continue;
+ if(p->from.reg != NREG)
+ continue;
+ v = p->from.offset;
+ if(v >= -0x7fff-1 && v <= 0x7fff)
+ continue;
+ if(!(v & 0xffff))
+ continue;
+ if(v)
+ continue; /* quicker to build it than load it */
+ /* size should be 9 max */
+ sprint(literal, "$%lux", v);
+ }
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ s->value = orig1+orig;
+ orig += 4;
+ p1 = prg();
+ p1->as = ADATA;
+ p1->line = p->line;
+ p1->from.type = D_OREG;
+ p1->from.sym = s;
+ p1->from.name = D_EXTERN;
+ p1->reg = 4;
+ p1->to = p->from;
+ p1->link = datap;
+ datap = p1;
+ }
+ if(s->type != SDATA)
+ diag("literal not data: %s", s->name);
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ continue;
+ }
+ while(orig & 7)
+ orig++;
+ /*
+ * pass 5
+ * re-adjust offsets
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t == SBSS) {
+ s->value += orig;
+ continue;
+ }
+ if(t == SDATA1) {
+ s->type = SDATA;
+ s->value += orig;
+ continue;
+ }
+ }
+ datsize += orig;
+ xdefine("setSB", SDATA, 0L+BIG);
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+ xdefine("etext", STEXT, 0L);
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+int
+relinv(int a)
+{
+
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+
+ case ABVC: return ABVS;
+ case ABVS: return ABVC;
+ }
+ return 0;
+}
+
+void
+follow(void)
+{
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ firstp = prg();
+ lastp = firstp;
+
+ xfol(textp);
+
+ firstp = firstp->link;
+ lastp->link = P;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q, *r;
+ int a, b, i;
+
+loop:
+ if(p == P)
+ return;
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(a == ABR) {
+ q = p->cond;
+ if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ p = p->link;
+ xfol(p);
+ p = q;
+ if(p && !(p->mark & FOLL))
+ goto loop;
+ return;
+ }
+ if(q != P) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == lastp || (q->mark&NOSCHED))
+ break;
+ b = 0; /* set */
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI)
+ goto copy;
+ if(!q->cond || (q->cond->mark&FOLL))
+ continue;
+ b = relinv(a);
+ if(!b)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ lastp->link = r;
+ lastp = r;
+ continue;
+ }
+ lastp->link = r;
+ lastp = r;
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI)
+ return;
+ r->as = b;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+
+ a = ABR;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI){
+ if(p->mark & NOSCHED){
+ p = p->link;
+ goto loop;
+ }
+ return;
+ }
+ if(p->cond != P)
+ if(a != ABL && p->link != P) {
+ xfol(p->link);
+ p = p->cond;
+ if(p == P || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ long c, vexit;
+ Prog *p, *q;
+ Sym *s;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if((a == ABL || a == ARETURN) && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT && s->type != SUNDEF) {
+ diag("undefined: %s\n%P", s->name, p);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ if(s->type == SUNDEF){
+ p->to.offset = 0;
+ p->cond = UP;
+ }
+ else
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH || p->cond == UP)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range %ld\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ p->mark = 0; /* initialization for follow */
+ if(p->cond != P && p->cond != UP) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ long dwn[LOG], cnt[LOG], i;
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != ABR || (p->mark&NOSCHED))
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
+
+void
+import(void)
+{
+ int i;
+ Sym *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
+ undefsym(s);
+ Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
+ }
+}
+
+void
+ckoff(Sym *s, long v)
+{
+ if(v < 0 || v >= 1<<Roffset)
+ diag("relocation offset %ld for %s out of range", v, s->name);
+}
+
+static Prog*
+newdata(Sym *s, int o, int w, int t)
+{
+ Prog *p;
+
+ p = prg();
+ p->link = datap;
+ datap = p;
+ p->as = ADATA;
+ p->reg = w;
+ p->from.type = D_OREG;
+ p->from.name = t;
+ p->from.sym = s;
+ p->from.offset = o;
+ p->to.type = D_CONST;
+ p->to.name = D_NONE;
+ return p;
+}
+
+void
+export(void)
+{
+ int i, j, n, off, nb, sv, ne;
+ Sym *s, *et, *str, **esyms;
+ Prog *p;
+ char buf[NSNAME], *t;
+
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ n++;
+ esyms = malloc(n*sizeof(Sym*));
+ ne = n;
+ n = 0;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+ esyms[n++] = s;
+ for(i = 0; i < ne-1; i++)
+ for(j = i+1; j < ne; j++)
+ if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
+ s = esyms[i];
+ esyms[i] = esyms[j];
+ esyms[j] = s;
+ }
+
+ nb = 0;
+ off = 0;
+ et = lookup(EXPTAB, 0);
+ if(et->type != 0 && et->type != SXREF)
+ diag("%s already defined", EXPTAB);
+ et->type = SDATA;
+ str = lookup(".string", 0);
+ if(str->type == 0)
+ str->type = SDATA;
+ sv = str->value;
+ for(i = 0; i < ne; i++){
+ s = esyms[i];
+ Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type);
+
+ /* signature */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.offset = s->sig;
+
+ /* address */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+
+ /* string */
+ t = s->name;
+ n = strlen(t)+1;
+ for(;;){
+ buf[nb++] = *t;
+ sv++;
+ if(nb >= NSNAME){
+ p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, buf, NSNAME);
+ nb = 0;
+ }
+ if(*t++ == 0)
+ break;
+ }
+
+ /* name */
+ p = newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ p->to.name = D_STATIC;
+ p->to.sym = str;
+ p->to.offset = sv-n;
+ }
+
+ if(nb > 0){
+ p = newdata(str, sv-nb, nb, D_STATIC);
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, buf, nb);
+ }
+
+ for(i = 0; i < 3; i++){
+ newdata(et, off, sizeof(long), D_EXTERN);
+ off += sizeof(long);
+ }
+ et->value = off;
+ if(sv == 0)
+ sv = 1;
+ str->value = sv;
+ exports = ne;
+ free(esyms);
+}
diff --git a/utils/ql/sched.c b/utils/ql/sched.c
new file mode 100644
index 00000000..ea6c99af
--- /dev/null
+++ b/utils/ql/sched.c
@@ -0,0 +1,801 @@
+#include "l.h"
+
+enum
+{
+ E_ICC = 1<<0,
+ E_FCC = 1<<1,
+ E_MEM = 1<<2,
+ E_MEMSP = 1<<3, /* uses offset and size */
+ E_MEMSB = 1<<4, /* uses offset and size */
+ E_LR = 1<<5,
+ E_CR = 1<<6,
+ E_CTR = 1<<7,
+ E_XER = 1<<8,
+
+ E_CR0 = 0xF<<0,
+ E_CR1 = 0xF<<4,
+
+ ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
+ ALL = ~0,
+};
+
+typedef struct Sch Sch;
+typedef struct Dep Dep;
+
+struct Dep
+{
+ ulong ireg;
+ ulong freg;
+ ulong cc;
+ ulong cr;
+};
+struct Sch
+{
+ Prog p;
+ Dep set;
+ Dep used;
+ long soffset;
+ char size;
+ char comp;
+};
+
+void regused(Sch*, Prog*);
+int depend(Sch*, Sch*);
+int conflict(Sch*, Sch*);
+int offoverlap(Sch*, Sch*);
+void dumpbits(Sch*, Dep*);
+
+void
+sched(Prog *p0, Prog *pe)
+{
+ Prog *p, *q;
+ Sch sch[NSCHED], *s, *t, *u, *se, stmp;
+
+ if(!debug['Q'])
+ return;
+ /*
+ * build side structure
+ */
+ s = sch;
+ for(p=p0;; p=p->link) {
+ memset(s, 0, sizeof(*s));
+ s->p = *p;
+ regused(s, p);
+ if(debug['X']) {
+ Bprint(&bso, "%P\tset", &s->p);
+ dumpbits(s, &s->set);
+ Bprint(&bso, "; used");
+ dumpbits(s, &s->used);
+ if(s->comp)
+ Bprint(&bso, "; compound");
+ if(s->p.mark & LOAD)
+ Bprint(&bso, "; load");
+ if(s->p.mark & BRANCH)
+ Bprint(&bso, "; branch");
+ if(s->p.mark & FCMP)
+ Bprint(&bso, "; fcmp");
+ Bprint(&bso, "\n");
+ }
+ s++;
+ if(p == pe)
+ break;
+ }
+ se = s;
+
+ for(s=se-1; s>=sch; s--) {
+
+ /*
+ * load delay. interlocked.
+ */
+ if(s->p.mark & LOAD) {
+ if(s >= se-1)
+ continue;
+ if(!conflict(s, (s+1)))
+ continue;
+ /*
+ * s is load, s+1 is immediate use of result
+ * t is the trial instruction to insert between s and s+1
+ */
+ for(t=s-1; t>=sch; t--) {
+ if(t->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & FCMP)
+ if((s+1)->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & LOAD)
+ if(conflict(t, (s+1)))
+ goto no2;
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no2;
+ goto out2;
+ no2:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?l%P\n", &s->p);
+ continue;
+ out2:
+ if(debug['X']) {
+ Bprint(&bso, "!l%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+
+ /*
+ * fop2 delay.
+ */
+ if(s->p.mark & FCMP) {
+ if(s >= se-1)
+ continue;
+ if(!((s+1)->p.mark & BRANCH))
+ continue;
+ /* t is the trial instruction to use */
+ for(t=s-1; t>=sch; t--) {
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no3;
+ goto out3;
+ no3:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?f%P\n", &s->p);
+ continue;
+ out3:
+ if(debug['X']) {
+ Bprint(&bso, "!f%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+ continue;
+ }
+ }
+
+ /*
+ * put it all back
+ */
+ for(s=sch, p=p0; s<se; s++, p=q) {
+ q = p->link;
+ if(q != s->p.link) {
+ *p = s->p;
+ p->link = q;
+ }
+ }
+ if(debug['X'])
+ Bprint(&bso, "\n");
+}
+
+void
+regused(Sch *s, Prog *realp)
+{
+ int c, ar, ad, ld, sz, nr, upd;
+ ulong m;
+ Prog *p;
+
+ p = &s->p;
+ s->comp = compound(p);
+ if(s->comp) {
+ s->set.ireg |= 1<<REGTMP;
+ s->used.ireg |= 1<<REGTMP;
+ }
+ ar = 0; /* dest is really reference */
+ ad = 0; /* source/dest is really address */
+ ld = 0; /* opcode is load instruction */
+ sz = 32*4; /* size of load/store for overlap computation */
+ nr = 0; /* source/dest is not really reg */
+ upd = 0; /* move with update; changes reg */
+
+/*
+ * flags based on opcode
+ */
+ switch(p->as) {
+ case ATEXT:
+ curtext = realp;
+ autosize = p->to.offset + 4;
+ ad = 1;
+ break;
+ case ABL:
+ s->set.cc |= E_LR;
+ ar = 1;
+ ad = 1;
+ break;
+ case ABR:
+ ar = 1;
+ ad = 1;
+ break;
+ case ACMP:
+ s->set.cc |= E_ICC;
+ if(p->reg == 0)
+ s->set.cr |= E_CR0;
+ else
+ s->set.cr |= (0xF<<((p->reg&7)*4));
+ ar = 1;
+ break;
+ case AFCMPO:
+ case AFCMPU:
+ s->set.cc |= E_FCC;
+ if(p->reg == 0)
+ s->set.cr |= E_CR0;
+ else
+ s->set.cr |= (0xF<<((p->reg&7)*4));
+ ar = 1;
+ break;
+ case ACRAND:
+ case ACRANDN:
+ case ACREQV:
+ case ACRNAND:
+ case ACRNOR:
+ case ACROR:
+ case ACRORN:
+ case ACRXOR:
+ s->used.cr |= 1<<p->from.reg;
+ s->set.cr |= 1<<p->to.reg;
+ nr = 1;
+ break;
+ case ABCL: /* tricky */
+ s->used.cc |= E_FCC|E_ICC;
+ s->used.cr = ALL;
+ s->set.cc |= E_LR;
+ ar = 1;
+ break;
+ case ABC: /* tricky */
+ s->used.cc |= E_FCC|E_ICC;
+ s->used.cr = ALL;
+ ar = 1;
+ break;
+ case ABEQ:
+ case ABGE:
+ case ABGT:
+ case ABLE:
+ case ABLT:
+ case ABNE:
+ case ABVC:
+ case ABVS:
+ s->used.cc |= E_ICC;
+ s->used.cr |= E_CR0;
+ ar = 1;
+ break;
+ case ALSW:
+ case AMOVMW:
+ /* could do better */
+ sz = 32*4;
+ ld = 1;
+ break;
+ case AMOVBU:
+ case AMOVBZU:
+ upd = 1;
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVB:
+ case AMOVBZ:
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVHU:
+ case AMOVHZU:
+ upd = 1;
+ sz = 2;
+ ld = 1;
+ break;
+ case AMOVH:
+ case AMOVHBR:
+ case AMOVHZ:
+ sz = 2;
+ ld = 1;
+ break;
+ case AFMOVSU:
+ case AMOVWU:
+ upd = 1;
+ sz = 4;
+ ld = 1;
+ break;
+ case AFMOVS:
+ case AMOVW:
+ case AMOVWBR:
+ case ALWAR:
+ sz = 4;
+ ld = 1;
+ break;
+ case AFMOVDU:
+ upd = 1;
+ sz = 8;
+ ld = 1;
+ break;
+ case AFMOVD:
+ sz = 8;
+ ld = 1;
+ break;
+ case AFMOVDCC:
+ sz = 8;
+ ld = 1;
+ s->set.cc |= E_FCC;
+ s->set.cr |= E_CR1;
+ break;
+ case AMOVFL:
+ case AMOVCRFS:
+ case AMTFSB0:
+ case AMTFSB0CC:
+ case AMTFSB1:
+ case AMTFSB1CC:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ s->set.cr = ALL;
+ break;
+ case AADDCC:
+ case AADDVCC:
+ case AADDCCC:
+ case AADDCVCC:
+ case AADDMECC:
+ case AADDMEVCC:
+ case AADDECC:
+ case AADDEVCC:
+ case AADDZECC:
+ case AADDZEVCC:
+ case AANDCC:
+ case AANDNCC:
+ case ACNTLZWCC:
+ case ADIVWCC:
+ case ADIVWVCC:
+ case ADIVWUCC:
+ case ADIVWUVCC:
+ case AEQVCC:
+ case AEXTSBCC:
+ case AEXTSHCC:
+ case AMULHWCC:
+ case AMULHWUCC:
+ case AMULLWCC:
+ case AMULLWVCC:
+ case ANANDCC:
+ case ANEGCC:
+ case ANEGVCC:
+ case ANORCC:
+ case AORCC:
+ case AORNCC:
+ case AREMCC:
+ case AREMVCC:
+ case AREMUCC:
+ case AREMUVCC:
+ case ARLWMICC:
+ case ARLWNMCC:
+ case ASLWCC:
+ case ASRAWCC:
+ case ASRWCC:
+ case ASTWCCC:
+ case ASUBCC:
+ case ASUBVCC:
+ case ASUBCCC:
+ case ASUBCVCC:
+ case ASUBMECC:
+ case ASUBMEVCC:
+ case ASUBECC:
+ case ASUBEVCC:
+ case ASUBZECC:
+ case ASUBZEVCC:
+ case AXORCC:
+ s->set.cc |= E_ICC;
+ s->set.cr |= E_CR0;
+ break;
+ case AFABSCC:
+ case AFADDCC:
+ case AFADDSCC:
+ case AFCTIWCC:
+ case AFCTIWZCC:
+ case AFDIVCC:
+ case AFDIVSCC:
+ case AFMADDCC:
+ case AFMADDSCC:
+ case AFMSUBCC:
+ case AFMSUBSCC:
+ case AFMULCC:
+ case AFMULSCC:
+ case AFNABSCC:
+ case AFNEGCC:
+ case AFNMADDCC:
+ case AFNMADDSCC:
+ case AFNMSUBCC:
+ case AFNMSUBSCC:
+ case AFRSPCC:
+ case AFSUBCC:
+ case AFSUBSCC:
+ s->set.cc |= E_FCC;
+ s->set.cr |= E_CR1;
+ break;
+ }
+
+/*
+ * flags based on 'to' field
+ */
+ c = p->to.class;
+ if(c == 0) {
+ c = aclass(&p->to) + 1;
+ p->to.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->to);
+
+ case C_NONE:
+ case C_ZCON:
+ case C_SCON:
+ case C_UCON:
+ case C_LCON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+ case C_CREG:
+ c = p->to.reg;
+ if(c == NREG)
+ s->set.cr = ALL;
+ else
+ s->set.cr |= (0xF << ((p->from.reg&7)*4));
+ s->set.cc = ALL;
+ break;
+ case C_SPR:
+ case C_SREG:
+ case C_FPSCR:
+ case C_MSR:
+ case C_XER:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ s->set.cr = ALL;
+ break;
+ case C_LR:
+ s->set.cc |= E_LR;
+ break;
+ case C_CTR:
+ s->set.cc |= E_CTR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->to.reg;
+ s->used.ireg |= 1<<c;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ if(ar)
+ s->used.cc |= m;
+ else
+ s->set.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ break;
+ case C_REG:
+ if(nr)
+ break;
+ if(ar)
+ s->used.ireg |= 1<<p->to.reg;
+ else
+ s->set.ireg |= 1<<p->to.reg;
+ break;
+ case C_FREG:
+ if(ar)
+ s->used.freg |= 1<<p->to.reg;
+ else
+ s->set.freg |= 1<<p->to.reg;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSP;
+ else
+ s->set.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(upd)
+ s->set.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSB;
+ else
+ s->set.cc |= E_MEMSB;
+ break;
+ }
+
+/*
+ * flags based on 'from' field
+ */
+ c = p->from.class;
+ if(c == 0) {
+ c = aclass(&p->from) + 1;
+ p->from.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->from);
+
+ case C_NONE:
+ case C_ZCON:
+ case C_SCON:
+ case C_UCON:
+ case C_LCON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_SBRA:
+ case C_LBRA:
+ c = p->from.reg;
+ if(c != NREG)
+ s->used.ireg |= 1<<c;
+ break;
+ case C_CREG:
+ c = p->from.reg;
+ if(c == NREG)
+ s->used.cr = ALL;
+ else
+ s->used.cr |= (0xF << ((p->from.reg&7)*4));
+ s->used.cc = ALL;
+ break;
+ case C_SPR:
+ case C_SREG:
+ case C_FPSCR:
+ case C_MSR:
+ case C_XER:
+ s->set.ireg = ALL;
+ s->set.freg = ALL;
+ s->set.cc = ALL;
+ s->set.cr = ALL;
+ break;
+ case C_LR:
+ s->used.cc |= E_LR;
+ break;
+ case C_CTR:
+ s->used.cc |= E_CTR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->from.reg;
+ s->used.ireg |= 1<<c;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ s->used.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ if(nr)
+ break;
+ s->used.ireg |= 1<<p->from.reg;
+ break;
+ case C_FREG:
+ s->used.freg |= 1<<p->from.reg;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSB;
+ break;
+ }
+
+ c = p->reg;
+ if(c != NREG) {
+ if(p->from.type == D_FREG || p->to.type == D_FREG)
+ s->used.freg |= 1<<c;
+ else
+ s->used.ireg |= 1<<c;
+ }
+}
+
+/*
+ * test to see if 2 instrictions can be
+ * interchanged without changing semantics
+ */
+int
+depend(Sch *sa, Sch *sb)
+{
+ ulong x;
+
+ if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
+ return 1;
+ if(sb->set.ireg & sa->used.ireg)
+ return 1;
+
+ if(sa->set.freg & (sb->set.freg|sb->used.freg))
+ return 1;
+ if(sb->set.freg & sa->used.freg)
+ return 1;
+
+ if(sa->set.cr & (sb->set.cr|sb->used.cr))
+ return 1;
+ if(sb->set.cr & sa->used.cr)
+ return 1;
+
+
+ x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
+ (sb->set.cc & sa->used.cc);
+ if(x) {
+ /*
+ * allow SB and SP to pass each other.
+ * allow SB to pass SB iff doffsets are ok
+ * anything else conflicts
+ */
+ if(x != E_MEMSP && x != E_MEMSB)
+ return 1;
+ x = sa->set.cc | sb->set.cc |
+ sa->used.cc | sb->used.cc;
+ if(x & E_MEM)
+ return 1;
+ if(offoverlap(sa, sb))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+offoverlap(Sch *sa, Sch *sb)
+{
+
+ if(sa->soffset < sb->soffset) {
+ if(sa->soffset+sa->size > sb->soffset)
+ return 1;
+ return 0;
+ }
+ if(sb->soffset+sb->size > sa->soffset)
+ return 1;
+ return 0;
+}
+
+/*
+ * test 2 adjacent instructions
+ * and find out if inserted instructions
+ * are desired to prevent stalls.
+ * first instruction is a load instruction.
+ */
+int
+conflict(Sch *sa, Sch *sb)
+{
+
+ if(sa->set.ireg & sb->used.ireg)
+ return 1;
+ if(sa->set.freg & sb->used.freg)
+ return 1;
+ if(sa->set.cr & sb->used.cr)
+ return 1;
+ return 0;
+}
+
+int
+compound(Prog *p)
+{
+ Optab *o;
+
+ o = oplook(p);
+ if(o->size != 4)
+ return 1;
+ if(p->to.type == D_REG && p->to.reg == REGSB)
+ return 1;
+ return 0;
+}
+
+void
+dumpbits(Sch *s, Dep *d)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(d->ireg & (1<<i))
+ Bprint(&bso, " R%d", i);
+ for(i=0; i<32; i++)
+ if(d->freg & (1<<i))
+ Bprint(&bso, " F%d", i);
+ for(i=0; i<32; i++)
+ if(d->cr & (1<<i))
+ Bprint(&bso, " C%d", i);
+ for(i=0; i<32; i++)
+ switch(d->cc & (1<<i)) {
+ default:
+ break;
+ case E_ICC:
+ Bprint(&bso, " ICC");
+ break;
+ case E_FCC:
+ Bprint(&bso, " FCC");
+ break;
+ case E_LR:
+ Bprint(&bso, " LR");
+ break;
+ case E_CR:
+ Bprint(&bso, " CR");
+ break;
+ case E_CTR:
+ Bprint(&bso, " CTR");
+ break;
+ case E_XER:
+ Bprint(&bso, " XER");
+ break;
+ case E_MEM:
+ Bprint(&bso, " MEM%d", s->size);
+ break;
+ case E_MEMSB:
+ Bprint(&bso, " SB%d", s->size);
+ break;
+ case E_MEMSP:
+ Bprint(&bso, " SP%d", s->size);
+ break;
+ }
+}
diff --git a/utils/ql/span.c b/utils/ql/span.c
new file mode 100644
index 00000000..b3ae1dd4
--- /dev/null
+++ b/utils/ql/span.c
@@ -0,0 +1,928 @@
+#include "l.h"
+#define r0iszero 1
+
+void
+span(void)
+{
+ Prog *p;
+ Sym *setext;
+ Optab *o;
+ int m;
+ long c;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from3.type == D_CONST) {
+ if(p->from3.offset & 3)
+ diag("illegal origin\n%P", p);
+ if(c > p->from3.offset)
+ diag("passed origin (#%lux)\n%P", c, p);
+ else
+ c = p->from3.offset;
+ p->pc = c;
+ }
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ if(p->as != ANOP)
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ c = rnd(c, 4);
+
+ setext = lookup("etext", 0);
+ if(setext != S) {
+ setext->value = c;
+ textsize = c - INITTEXT;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "tsize = %lux\n", textsize);
+ Bflush(&bso);
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+}
+
+long
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+int
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_CREG:
+ return C_CREG;
+
+ case D_SPR:
+ if(a->offset == D_LR)
+ return C_LR;
+ if(a->offset == D_XER)
+ return C_XER;
+ if(a->offset == D_CTR)
+ return C_CTR;
+ return C_SPR;
+
+ case D_DCR:
+ return C_SPR;
+
+ case D_SREG:
+ return C_SREG;
+
+ case D_FPSCR:
+ return C_FPSCR;
+
+ case D_MSR:
+ return C_MSR;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == S)
+ break;
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ if(dlm){
+ instoffset = a->sym->value + a->offset;
+ switch(a->sym->type){
+ case STEXT:
+ case SLEAF:
+ case SCONST:
+ case SUNDEF:
+ break;
+ default:
+ instoffset += INITDAT;
+ }
+ return C_ADDR;
+ }
+ instoffset = a->sym->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SEXT;
+ return C_LEXT;
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ if(instoffset == 0)
+ return C_ZOREG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_OPT:
+ instoffset = a->offset & 31L;
+ if(a->name == D_NONE)
+ return C_SCON;
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+
+ case D_NONE:
+ instoffset = a->offset;
+ consize:
+ if(instoffset >= 0) {
+ if(r0iszero && instoffset == 0)
+ return C_ZCON;
+ if(instoffset <= 0x7fff)
+ return C_SCON;
+ if(instoffset <= 0xffff)
+ return C_ANDCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+ }
+ if(instoffset >= -0x8000)
+ return C_ADDCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) {
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ if(s->type == SCONST) {
+ instoffset = s->value + a->offset;
+ if(dlm)
+ return C_LCON;
+ goto consize;
+ }
+ if(!dlm){
+ instoffset = s->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG && instoffset != 0)
+ return C_SECON;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ if(dlm)
+ return C_LCON;
+/* not sure why this barfs */
+return C_LCON;
+ if(instoffset == 0)
+ return C_ZCON;
+ if(instoffset >= -0x8000 && instoffset <= 0xffff)
+ return C_SCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, a4, r;
+ char *c1, *c3, *c4;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->from3.class;
+ if(a3 == 0) {
+ a3 = aclass(&p->from3) + 1;
+ p->from3.class = a3;
+ }
+ a3--;
+ a4 = p->to.class;
+ if(a4 == 0) {
+ a4 = aclass(&p->to) + 1;
+ p->to.class = a4;
+ }
+ a4--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0)
+ o = oprange[r].stop; /* just generate an error */
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ c4 = xcmp[a4];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3])
+ if(c4[o->a4]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ diag("illegal combination %A %R %R %R %R",
+ p->as, a1, a2, a3, a4);
+ if(1||!debug['a'])
+ prasm(p);
+ if(o == 0)
+ errorexit();
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON)
+ return 1;
+ break;
+ case C_ADDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_ANDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_SPR:
+ if(b == C_LR || b == C_XER || b == C_CTR)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(r0iszero && b == C_ZCON)
+ return 1;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+
+ case C_ANY:
+ return 1;
+ }
+ return 0;
+}
+
+int
+ocmp(void *a1, void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = a1;
+ p2 = a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ n = p1->a4 - p2->a4;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ for(i=0; i<C_NCLASS; i++)
+ for(n=0; n<C_NCLASS; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A", r);
+ errorexit();
+ case ADCBF: /* unary indexed: op (b+a); op (b) */
+ oprange[ADCBI] = oprange[r];
+ oprange[ADCBST] = oprange[r];
+ oprange[ADCBT] = oprange[r];
+ oprange[ADCBTST] = oprange[r];
+ oprange[ADCBZ] = oprange[r];
+ oprange[AICBI] = oprange[r];
+ break;
+ case AECOWX: /* indexed store: op s,(b+a); op s,(b) */
+ oprange[ASTWCCC] = oprange[r];
+ break;
+ case AREM: /* macro */
+ oprange[AREMCC] = oprange[r];
+ oprange[AREMV] = oprange[r];
+ oprange[AREMVCC] = oprange[r];
+ oprange[AREMU] = oprange[r];
+ oprange[AREMUCC] = oprange[r];
+ oprange[AREMUV] = oprange[r];
+ oprange[AREMUVCC] = oprange[r];
+ break;
+ case ADIVW: /* op Rb[,Ra],Rd */
+ oprange[AMULHW] = oprange[r];
+ oprange[AMULHWCC] = oprange[r];
+ oprange[AMULHWU] = oprange[r];
+ oprange[AMULHWUCC] = oprange[r];
+ oprange[AMULLWCC] = oprange[r];
+ oprange[AMULLWVCC] = oprange[r];
+ oprange[AMULLWV] = oprange[r];
+ oprange[ADIVWCC] = oprange[r];
+ oprange[ADIVWV] = oprange[r];
+ oprange[ADIVWVCC] = oprange[r];
+ oprange[ADIVWU] = oprange[r];
+ oprange[ADIVWUCC] = oprange[r];
+ oprange[ADIVWUV] = oprange[r];
+ oprange[ADIVWUVCC] = oprange[r];
+ oprange[AADDCC] = oprange[r];
+ oprange[AADDCV] = oprange[r];
+ oprange[AADDCVCC] = oprange[r];
+ oprange[AADDV] = oprange[r];
+ oprange[AADDVCC] = oprange[r];
+ oprange[AADDE] = oprange[r];
+ oprange[AADDECC] = oprange[r];
+ oprange[AADDEV] = oprange[r];
+ oprange[AADDEVCC] = oprange[r];
+ oprange[ACRAND] = oprange[r];
+ oprange[ACRANDN] = oprange[r];
+ oprange[ACREQV] = oprange[r];
+ oprange[ACRNAND] = oprange[r];
+ oprange[ACRNOR] = oprange[r];
+ oprange[ACROR] = oprange[r];
+ oprange[ACRORN] = oprange[r];
+ oprange[ACRXOR] = oprange[r];
+ oprange[AMULCHW] = oprange[r];
+ oprange[AMULCHWCC] = oprange[r];
+ oprange[AMULCHWU] = oprange[r];
+ oprange[AMULCHWUCC] = oprange[r];
+ oprange[AMULHHW] = oprange[r];
+ oprange[AMULHHWCC] = oprange[r];
+ oprange[AMULHHWU] = oprange[r];
+ oprange[AMULHHWUCC] = oprange[r];
+ oprange[AMULLHW] = oprange[r];
+ oprange[AMULLHWCC] = oprange[r];
+ oprange[AMULLHWU] = oprange[r];
+ oprange[AMULLHWUCC] = oprange[r];
+ break;
+ case AMACCHW: /* strictly 3 registers */
+ oprange[AMACCHWCC] = oprange[r];
+ oprange[AMACCHWS] = oprange[r];
+ oprange[AMACCHWSCC] = oprange[r];
+ oprange[AMACCHWSU] = oprange[r];
+ oprange[AMACCHWSUCC] = oprange[r];
+ oprange[AMACCHWSUV] = oprange[r];
+ oprange[AMACCHWSUVCC] = oprange[r];
+ oprange[AMACCHWSV] = oprange[r];
+ oprange[AMACCHWSVCC] = oprange[r];
+ oprange[AMACCHWU] = oprange[r];
+ oprange[AMACCHWUCC] = oprange[r];
+ oprange[AMACCHWUV] = oprange[r];
+ oprange[AMACCHWUVCC] = oprange[r];
+ oprange[AMACCHWV] = oprange[r];
+ oprange[AMACCHWVCC] = oprange[r];
+ oprange[AMACHHW] = oprange[r];
+ oprange[AMACHHWCC] = oprange[r];
+ oprange[AMACHHWS] = oprange[r];
+ oprange[AMACHHWSCC] = oprange[r];
+ oprange[AMACHHWSU] = oprange[r];
+ oprange[AMACHHWSUCC] = oprange[r];
+ oprange[AMACHHWSUV] = oprange[r];
+ oprange[AMACHHWSUVCC] = oprange[r];
+ oprange[AMACHHWSV] = oprange[r];
+ oprange[AMACHHWSVCC] = oprange[r];
+ oprange[AMACHHWU] = oprange[r];
+ oprange[AMACHHWUCC] = oprange[r];
+ oprange[AMACHHWUV] = oprange[r];
+ oprange[AMACHHWUVCC] = oprange[r];
+ oprange[AMACHHWV] = oprange[r];
+ oprange[AMACHHWVCC] = oprange[r];
+ oprange[AMACLHW] = oprange[r];
+ oprange[AMACLHWCC] = oprange[r];
+ oprange[AMACLHWS] = oprange[r];
+ oprange[AMACLHWSCC] = oprange[r];
+ oprange[AMACLHWSU] = oprange[r];
+ oprange[AMACLHWSUCC] = oprange[r];
+ oprange[AMACLHWSUV] = oprange[r];
+ oprange[AMACLHWSUVCC] = oprange[r];
+ oprange[AMACLHWSV] = oprange[r];
+ oprange[AMACLHWSVCC] = oprange[r];
+ oprange[AMACLHWU] = oprange[r];
+ oprange[AMACLHWUCC] = oprange[r];
+ oprange[AMACLHWUV] = oprange[r];
+ oprange[AMACLHWUVCC] = oprange[r];
+ oprange[AMACLHWV] = oprange[r];
+ oprange[AMACLHWVCC] = oprange[r];
+ oprange[ANMACCHW] = oprange[r];
+ oprange[ANMACCHWCC] = oprange[r];
+ oprange[ANMACCHWS] = oprange[r];
+ oprange[ANMACCHWSCC] = oprange[r];
+ oprange[ANMACCHWSV] = oprange[r];
+ oprange[ANMACCHWSVCC] = oprange[r];
+ oprange[ANMACCHWV] = oprange[r];
+ oprange[ANMACCHWVCC] = oprange[r];
+ oprange[ANMACHHW] = oprange[r];
+ oprange[ANMACHHWCC] = oprange[r];
+ oprange[ANMACHHWS] = oprange[r];
+ oprange[ANMACHHWSCC] = oprange[r];
+ oprange[ANMACHHWSV] = oprange[r];
+ oprange[ANMACHHWSVCC] = oprange[r];
+ oprange[ANMACHHWV] = oprange[r];
+ oprange[ANMACHHWVCC] = oprange[r];
+ oprange[ANMACLHW] = oprange[r];
+ oprange[ANMACLHWCC] = oprange[r];
+ oprange[ANMACLHWS] = oprange[r];
+ oprange[ANMACLHWSCC] = oprange[r];
+ oprange[ANMACLHWSV] = oprange[r];
+ oprange[ANMACLHWSVCC] = oprange[r];
+ oprange[ANMACLHWV] = oprange[r];
+ oprange[ANMACLHWVCC] = oprange[r];
+ break;
+/* floating point move *//*
+ oprange[AFMR] = oprange[r];
+ oprange[AFMRCC] = oprange[r];
+*/
+/**/
+ case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
+ oprange[AMOVH] = oprange[r];
+ oprange[AMOVHZ] = oprange[r];
+ break;
+ case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x */
+ oprange[AMOVHU] = oprange[r];
+ oprange[AMOVHZU] = oprange[r];
+ oprange[AMOVWU] = oprange[r];
+ oprange[AMOVMW] = oprange[r];
+ break;
+ case AAND: /* logical op Rb,Rs,Ra; no literal */
+ oprange[AANDN] = oprange[r];
+ oprange[AANDNCC] = oprange[r];
+ oprange[AEQV] = oprange[r];
+ oprange[AEQVCC] = oprange[r];
+ oprange[ANAND] = oprange[r];
+ oprange[ANANDCC] = oprange[r];
+ oprange[ANOR] = oprange[r];
+ oprange[ANORCC] = oprange[r];
+ oprange[AORCC] = oprange[r];
+ oprange[AORN] = oprange[r];
+ oprange[AORNCC] = oprange[r];
+ oprange[AXORCC] = oprange[r];
+ break;
+ case AADDME: /* op Ra, Rd */
+ oprange[AADDMECC] = oprange[r];
+ oprange[AADDMEV] = oprange[r];
+ oprange[AADDMEVCC] = oprange[r];
+ oprange[AADDZE] = oprange[r];
+ oprange[AADDZECC] = oprange[r];
+ oprange[AADDZEV] = oprange[r];
+ oprange[AADDZEVCC] = oprange[r];
+ oprange[ASUBME] = oprange[r];
+ oprange[ASUBMECC] = oprange[r];
+ oprange[ASUBMEV] = oprange[r];
+ oprange[ASUBMEVCC] = oprange[r];
+ oprange[ASUBZE] = oprange[r];
+ oprange[ASUBZECC] = oprange[r];
+ oprange[ASUBZEV] = oprange[r];
+ oprange[ASUBZEVCC] = oprange[r];
+ break;
+ case AADDC:
+ oprange[AADDCCC] = oprange[r];
+ break;
+ case ABEQ:
+ oprange[ABGE] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABNE] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ break;
+ case ABR:
+ oprange[ABL] = oprange[r];
+ break;
+ case ABC:
+ oprange[ABCL] = oprange[r];
+ break;
+ case AEXTSB: /* op Rs, Ra */
+ oprange[AEXTSBCC] = oprange[r];
+ oprange[AEXTSH] = oprange[r];
+ oprange[AEXTSHCC] = oprange[r];
+ oprange[ACNTLZW] = oprange[r];
+ oprange[ACNTLZWCC] = oprange[r];
+ break;
+ case AFABS: /* fop [s,]d */
+ oprange[AFABSCC] = oprange[r];
+ oprange[AFNABS] = oprange[r];
+ oprange[AFNABSCC] = oprange[r];
+ oprange[AFNEG] = oprange[r];
+ oprange[AFNEGCC] = oprange[r];
+ oprange[AFRSP] = oprange[r];
+ oprange[AFRSPCC] = oprange[r];
+ oprange[AFCTIW] = oprange[r];
+ oprange[AFCTIWCC] = oprange[r];
+ oprange[AFCTIWZ] = oprange[r];
+ oprange[AFCTIWZCC] = oprange[r];
+ break;
+ case AFADD:
+ oprange[AFADDS] = oprange[r];
+ oprange[AFADDCC] = oprange[r];
+ oprange[AFADDSCC] = oprange[r];
+ oprange[AFDIV] = oprange[r];
+ oprange[AFDIVS] = oprange[r];
+ oprange[AFDIVCC] = oprange[r];
+ oprange[AFDIVSCC] = oprange[r];
+ oprange[AFSUB] = oprange[r];
+ oprange[AFSUBS] = oprange[r];
+ oprange[AFSUBCC] = oprange[r];
+ oprange[AFSUBSCC] = oprange[r];
+ break;
+ case AFMADD:
+ oprange[AFMADDCC] = oprange[r];
+ oprange[AFMADDS] = oprange[r];
+ oprange[AFMADDSCC] = oprange[r];
+ oprange[AFMSUB] = oprange[r];
+ oprange[AFMSUBCC] = oprange[r];
+ oprange[AFMSUBS] = oprange[r];
+ oprange[AFMSUBSCC] = oprange[r];
+ oprange[AFNMADD] = oprange[r];
+ oprange[AFNMADDCC] = oprange[r];
+ oprange[AFNMADDS] = oprange[r];
+ oprange[AFNMADDSCC] = oprange[r];
+ oprange[AFNMSUB] = oprange[r];
+ oprange[AFNMSUBCC] = oprange[r];
+ oprange[AFNMSUBS] = oprange[r];
+ oprange[AFNMSUBSCC] = oprange[r];
+ break;
+ case AFMUL:
+ oprange[AFMULS] = oprange[r];
+ oprange[AFMULCC] = oprange[r];
+ oprange[AFMULSCC] = oprange[r];
+ break;
+ case AFCMPO:
+ oprange[AFCMPU] = oprange[r];
+ break;
+ case AMTFSB0:
+ oprange[AMTFSB0CC] = oprange[r];
+ oprange[AMTFSB1] = oprange[r];
+ oprange[AMTFSB1CC] = oprange[r];
+ break;
+ case ANEG: /* op [Ra,] Rd */
+ oprange[ANEGCC] = oprange[r];
+ oprange[ANEGV] = oprange[r];
+ oprange[ANEGVCC] = oprange[r];
+ break;
+ case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */
+ oprange[AXOR] = oprange[r];
+ break;
+ case ASLW:
+ oprange[ASLWCC] = oprange[r];
+ oprange[ASRW] = oprange[r];
+ oprange[ASRWCC] = oprange[r];
+ break;
+ case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+ oprange[ASRAWCC] = oprange[r];
+ break;
+ case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
+ oprange[ASUB] = oprange[r];
+ oprange[ASUBCC] = oprange[r];
+ oprange[ASUBV] = oprange[r];
+ oprange[ASUBVCC] = oprange[r];
+ oprange[ASUBCCC] = oprange[r];
+ oprange[ASUBCV] = oprange[r];
+ oprange[ASUBCVCC] = oprange[r];
+ oprange[ASUBE] = oprange[r];
+ oprange[ASUBECC] = oprange[r];
+ oprange[ASUBEV] = oprange[r];
+ oprange[ASUBEVCC] = oprange[r];
+ break;
+ case ASYNC:
+ oprange[AISYNC] = oprange[r];
+ break;
+ case ARLWMI:
+ oprange[ARLWMICC] = oprange[r];
+ oprange[ARLWNM] = oprange[r];
+ oprange[ARLWNMCC] = oprange[r];
+ break;
+ case AFMOVD:
+ oprange[AFMOVDCC] = oprange[r];
+ oprange[AFMOVDU] = oprange[r];
+ oprange[AFMOVS] = oprange[r];
+ oprange[AFMOVSU] = oprange[r];
+ break;
+ case AECIWX:
+ oprange[ALWAR] = oprange[r];
+ break;
+ case ASYSCALL: /* just the op; flow of control */
+ oprange[ARFI] = oprange[r];
+ oprange[ARFCI] = oprange[r];
+ break;
+ case AMOVHBR:
+ oprange[AMOVWBR] = oprange[r];
+ break;
+ case AADD:
+ case AANDCC: /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
+ case ACMP:
+ case ACMPU:
+ case AEIEIO:
+ case ALSW:
+ case AMOVB: /* macro: move byte with sign extension */
+ case AMOVBU: /* macro: move byte with sign extension & update */
+ case AMOVW:
+ case AMOVFL:
+ case AMULLW: /* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
+ case ASUBC: /* op r1,$s,r3; op r1[,r2],r3 */
+ case ASTSW:
+ case ATLBIE:
+ case ATW:
+ case AWORD:
+ case ANOP:
+ case ATEXT:
+ break;
+ }
+ }
+}
+
+enum{
+ ABSD = 0,
+ ABSU = 1,
+ RELD = 2,
+ RELU = 3,
+};
+
+int modemap[8] = { 0, 1, -1, 2, 3, 4, 5, 6};
+
+typedef struct Reloc Reloc;
+
+struct Reloc
+{
+ int n;
+ int t;
+ uchar *m;
+ ulong *a;
+};
+
+Reloc rels;
+
+static void
+grow(Reloc *r)
+{
+ int t;
+ uchar *m, *nm;
+ ulong *a, *na;
+
+ t = r->t;
+ r->t += 64;
+ m = r->m;
+ a = r->a;
+ r->m = nm = malloc(r->t*sizeof(uchar));
+ r->a = na = malloc(r->t*sizeof(ulong));
+ memmove(nm, m, t*sizeof(uchar));
+ memmove(na, a, t*sizeof(ulong));
+ free(m);
+ free(a);
+}
+
+void
+dynreloc(Sym *s, long v, int abs, int split, int sext)
+{
+ int i, k, n;
+ uchar *m;
+ ulong *a;
+ Reloc *r;
+
+ if(v&3)
+ diag("bad relocation address");
+ v >>= 2;
+ if(s->type == SUNDEF)
+ k = abs ? ABSU : RELU;
+ else
+ k = abs ? ABSD : RELD;
+ if(split)
+ k += 4;
+ if(sext)
+ k += 2;
+ /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
+ k = modemap[k];
+ r = &rels;
+ n = r->n;
+ if(n >= r->t)
+ grow(r);
+ m = r->m;
+ a = r->a;
+ for(i = n; i > 0; i--){
+ if(v < a[i-1]){ /* happens occasionally for data */
+ m[i] = m[i-1];
+ a[i] = a[i-1];
+ }
+ else
+ break;
+ }
+ m[i] = k;
+ a[i] = v;
+ r->n++;
+}
+
+static int
+sput(char *s)
+{
+ char *p;
+
+ p = s;
+ while(*s)
+ cput(*s++);
+ cput(0);
+ return s-p+1;
+}
+
+void
+asmdyn()
+{
+ int i, n, t, c;
+ Sym *s;
+ ulong la, ra, *a;
+ vlong off;
+ uchar *m;
+ Reloc *r;
+
+ cflush();
+ off = seek(cout, 0, 1);
+ lput(0);
+ t = 0;
+ lput(imports);
+ t += 4;
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SUNDEF){
+ lput(s->sig);
+ t += 4;
+ t += sput(s->name);
+ }
+
+ la = 0;
+ r = &rels;
+ n = r->n;
+ m = r->m;
+ a = r->a;
+ lput(n);
+ t += 4;
+ for(i = 0; i < n; i++){
+ ra = *a-la;
+ if(*a < la)
+ diag("bad relocation order");
+ if(ra < 256)
+ c = 0;
+ else if(ra < 65536)
+ c = 1;
+ else
+ c = 2;
+ cput((c<<6)|*m++);
+ t++;
+ if(c == 0){
+ cput(ra);
+ t++;
+ }
+ else if(c == 1){
+ wput(ra);
+ t += 2;
+ }
+ else{
+ lput(ra);
+ t += 4;
+ }
+ la = *a++;
+ }
+
+ cflush();
+ seek(cout, off, 0);
+ lput(t);
+
+ if(debug['v']){
+ Bprint(&bso, "import table entries = %d\n", imports);
+ Bprint(&bso, "export table entries = %d\n", exports);
+ }
+}
diff --git a/utils/rcsh/Nt.c b/utils/rcsh/Nt.c
new file mode 100644
index 00000000..dc6ad8a9
--- /dev/null
+++ b/utils/rcsh/Nt.c
@@ -0,0 +1,549 @@
+#include "rc.h"
+#include <windows.h>
+
+enum {
+ Nchild = 100,
+};
+
+typedef struct Child Child;
+
+struct Child {
+ int pid;
+ HANDLE handle;
+};
+
+static Child child[Nchild];
+
+static void
+winerror(void)
+{
+ int e, r;
+ char buf[100], *p, *q;
+
+ e = GetLastError();
+
+ r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf, sizeof(buf), 0);
+
+ if(r == 0)
+ snprint(buf, sizeof(buf), "windows error %d", e);
+
+ for(p=q=buf; *p; p++) {
+ if(*p == '\r')
+ continue;
+ if(*p == '\n')
+ *q++ = ' ';
+ else
+ *q++ = *p;
+ }
+ *q = 0;
+ errstr(buf, sizeof buf);
+}
+
+static int
+badentry(char *filename)
+{
+ if(*filename == 0)
+ return 1;
+ if(filename[0] == '.'){
+ if(filename[1] == 0)
+ return 1;
+ if(filename[1] == '.' && filename[2] == 0)
+ return 1;
+ }
+ return 0;
+}
+
+Direntry*
+readdirect(char *path)
+{
+ long n;
+ HANDLE h;
+ Direntry *d;
+ char fullpath[MAX_PATH];
+ WIN32_FIND_DATA data;
+
+ snprint(fullpath, MAX_PATH, "%s\\*.*", path);
+
+ h = FindFirstFile(fullpath, &data);
+ if(h == INVALID_HANDLE_VALUE)
+ return 0;
+
+ n = 0;
+ d = 0;
+ for(;;){
+ if(!badentry(data.cFileName)){
+ d = realloc(d, (n+2)*sizeof(Direntry));
+ if(d == 0){
+ werrstr("memory allocation");
+ return 0;
+ }
+ d[n].name = malloc(strlen(data.cFileName)+1);
+ if(d[n].name == 0){
+ werrstr("memory allocation");
+ return 0;
+ }
+ strcpy(d[n].name, data.cFileName);
+ if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ d[n].isdir = 1;
+ else
+ d[n].isdir = 0;
+ n++;
+ }
+ if(FindNextFile(h, &data) == 0)
+ break;
+ }
+ FindClose(h);
+ if(d){
+ d[n].name = 0;
+ d[n].isdir = 0;
+ }
+ return d;
+}
+
+void
+fatal(char *fmt, ...)
+{
+ char buf[512];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+
+ fprint(2, "rc: %s\n", buf);
+ _exits(buf);
+}
+
+static int
+tas(int *p)
+{
+ int v;
+
+ _asm {
+ mov eax, p
+ mov ebx, 1
+ xchg ebx, [eax]
+ mov v, ebx
+ }
+
+ return v;
+}
+
+static void
+lock(Lock *lk)
+{
+ int i;
+
+ /* easy case */
+ if(!tas(&lk->val))
+ return;
+
+ /* for muli processor machines */
+ for(i=0; i<100; i++)
+ if(!tas(&lk->val))
+ return;
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ for(;;) {
+ for(i=0; i<10000; i++) {
+ Sleep(0);
+ if(!tas(&lk->val)) {
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+ return;
+ }
+ }
+ }
+}
+
+static void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
+
+int
+refinc(Ref *r)
+{
+ int i;
+
+ lock(&r->lk);
+ i = r->ref;
+ r->ref++;
+ unlock(&r->lk);
+ return i;
+}
+
+int
+refdec(Ref *r)
+{
+ int i;
+
+ lock(&r->lk);
+ r->ref--;
+ i = r->ref;
+ unlock(&r->lk);
+
+ return i;
+}
+
+/*
+ * windows quoting rules - I think
+ * Words are seperated by space or tab
+ * Words containing a space or tab can be quoted using "
+ * 2N backslashes + " ==> N backslashes and end quote
+ * 2N+1 backslashes + " ==> N backslashes + literal "
+ * N backslashes not followed by " ==> N backslashes
+ */
+static char *
+dblquote(char *cmd, char *s)
+{
+ int nb;
+ char *p;
+
+ for(p=s; *p; p++)
+ if(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '"')
+ break;
+
+ if(*p == 0){ /* easy case */
+ strcpy(cmd, s);
+ return cmd+(p-s);
+ }
+
+ *cmd++ = '"';
+ for(;;) {
+ for(nb=0; *s=='\\'; nb++)
+ *cmd++ = *s++;
+
+ if(*s == 0) { /* trailing backslashes -> 2N */
+ while(nb-- > 0)
+ *cmd++ = '\\';
+ break;
+ }
+
+ if(*s == '"') { /* literal quote -> 2N+1 backslashes */
+ while(nb-- > 0)
+ *cmd++ = '\\';
+ *cmd++ = '\\'; /* escape the quote */
+ }
+ *cmd++ = *s++;
+ }
+
+ *cmd++ = '"';
+ *cmd = 0;
+
+ return cmd;
+}
+
+static char *
+proccmd(char **argv)
+{
+ int i, n;
+ char *cmd, *p;
+
+ /* conservatively calculate length of command;
+ * backslash expansion can cause growth in dblquote().
+ */
+ for(i=0,n=0; argv[i]; i++) {
+ n += 2*strlen(argv[i]);
+ }
+ n++;
+
+ cmd = malloc(n);
+ for(i=0,p=cmd; argv[i]; i++) {
+ p = dblquote(p, argv[i]);
+ *p++ = ' ';
+ }
+ if(p != cmd)
+ p--;
+ *p = 0;
+
+ return cmd;
+}
+
+static char *
+exportenv(char **e)
+{
+ int i, j, n;
+ char *buf;
+
+ if(e == 0 || *e == 0)
+ return 0;
+
+ buf = 0;
+ n = 0;
+ for(i = 0; *e; e++, i++) {
+ j = strlen(*e)+1;
+ buf = realloc(buf, n+j);
+ strcpy(buf+n, *e);
+ n += j;
+ }
+ /* final null */
+ buf = realloc(buf, n+1);
+ buf[n] = 0;
+
+ return buf;
+}
+
+static int
+setpath(char *path, char *file)
+{
+ char *p, *last, tmp[MAX_PATH+1];
+ int n;
+
+ if(strlen(file) >= MAX_PATH){
+ werrstr("file name too long");
+ return -1;
+ }
+ strcpy(tmp, file);
+
+ for(p=tmp; *p; p++) {
+ if(*p == '/')
+ *p = '\\';
+ }
+
+ if(tmp[0] != 0 && tmp[1] == ':') {
+ if(tmp[2] == 0) {
+ tmp[2] = '\\';
+ tmp[3] = 0;
+ } else if(tmp[2] != '\\') {
+ /* don't allow c:foo - only c:\foo */
+ werrstr("illegal file name");
+ return -1;
+ }
+ }
+
+ path[0] = 0;
+ n = GetFullPathName(tmp, MAX_PATH, path, &last);
+ if(n >= MAX_PATH) {
+ werrstr("file name too long");
+ return -1;
+ }
+ if(n == 0 && tmp[0] == '\\' && tmp[1] == '\\' && tmp[2] != 0) {
+ strcpy(path, tmp);
+ return -1;
+ }
+
+ if(n == 0) {
+ werrstr("bad file name");
+ return -1;
+ }
+
+ for(p=path; *p; p++) {
+ if(*p < 32 || *p == '*' || *p == '?') {
+ werrstr("file not found");
+ return -1;
+ }
+ }
+
+ /* get rid of trailling \ */
+ if(path[n-1] == '\\') {
+ if(n <= 2) {
+ werrstr("illegal file name");
+ return -1;
+ }
+ path[n-1] = 0;
+ n--;
+ }
+
+ if(path[1] == ':' && path[2] == 0) {
+ path[2] = '\\';
+ path[3] = '.';
+ path[4] = 0;
+ return -1;
+ }
+
+ if(path[0] != '\\' || path[1] != '\\')
+ return 0;
+
+ for(p=path+2,n=0; *p; p++)
+ if(*p == '\\')
+ n++;
+ if(n == 0)
+ return -1;
+ if(n == 1)
+ return -1;
+ return 0;
+}
+
+
+static int
+execpath(char *path, char *file)
+{
+ int n;
+
+ if(setpath(path, file) < 0)
+ return 0;
+
+ n = strlen(path)-4;
+ if(path[n] == '.') {
+ if(GetFileAttributes(path) != -1)
+ return 1;
+ }
+ strncat(path, ".exe", MAX_PATH);
+ path[MAX_PATH-1] = 0;
+ if(GetFileAttributes(path) != -1)
+ return 1;
+ return 0;
+}
+
+static HANDLE
+fdexport(int fd)
+{
+ HANDLE h, r;
+
+ if(fd < 0)
+ return INVALID_HANDLE_VALUE;
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if(h < 0)
+ return INVALID_HANDLE_VALUE;
+
+ if(!DuplicateHandle(GetCurrentProcess(), h,
+ GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS,
+ 1, DUPLICATE_SAME_ACCESS))
+ return INVALID_HANDLE_VALUE;
+ return r;
+}
+
+static int
+addchild(int pid, HANDLE handle)
+{
+ int i;
+
+ for(i=0; i<Nchild; i++) {
+ if(child[i].handle == 0) {
+ child[i].handle = handle;
+ child[i].pid = pid;
+ return 1;
+ }
+ }
+ werrstr("child table full");
+ return 0;
+}
+
+int
+procwait(uint pid)
+{
+ HANDLE h;
+ int i, exit;
+
+ if(pid == 0)
+ return 0;
+
+ h = 0;
+ for(i = 0; i < Nchild; i++){
+ if(child[i].pid == pid){
+ h = child[i].handle;
+ child[i].pid = 0;
+ child[i].handle = 0;
+ break;
+ }
+ }
+
+ if(h == 0){ /* we don't know about this one - let the system try to find it */
+ h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ if(h == 0)
+ return 0; /* can't find it */
+ }
+
+ if(WaitForSingleObject(h, INFINITE) == WAIT_FAILED) {
+ winerror();
+ fatal("procwait: ");
+ }
+
+ if(!GetExitCodeProcess(h, &exit)) {
+ winerror();
+ exit = 1;
+ }
+
+ CloseHandle(h);
+ return exit;
+}
+
+uint
+proc(char **argv, int stdin, int stdout, int stderr)
+{
+ char *p, *arg0, *q, buf[MAX_PATH], path[MAX_PATH], *cmd, *eb;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ int r, found, full;
+ extern char **_environ;
+ Word *w;
+
+ arg0 = argv[0];
+ if(arg0 == 0) {
+ werrstr("null argv[0]");
+ return 0;
+ }
+
+ full = arg0[0] == '\\' || arg0[0] == '/' || arg0[0] == '.';
+ found = execpath(path, arg0);
+
+ if(!found && !full) {
+ w = vlook("path")->val;
+ if(w)
+ p = w->word;
+ else
+ p = getenv("path");
+ for(; p && *p; p = q){
+ q = strchr(p, ';');
+ if(q)
+ *q = 0;
+ snprint(buf, sizeof(buf), "%s/%s", p, arg0);
+ if(q)
+ *q++ = ';';
+ found = execpath(path, buf);
+ if(found)
+ break;
+ }
+ }
+
+ if(!found) {
+ werrstr("file not found");
+ return 0;
+ }
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
+ si.wShowWindow = SW_SHOW;
+ si.hStdInput = fdexport(stdin);
+ si.hStdOutput = fdexport(stdout);
+ si.hStdError = fdexport(stderr);
+
+ eb = exportenv(_environ);
+
+ cmd = proccmd(argv);
+
+ r = CreateProcess(path, cmd, 0, 0, 1, 0, eb, 0, &si, &pi);
+
+ /* allow child to run */
+ Sleep(0);
+
+ free(cmd);
+ free(eb);
+
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+
+ if(!r) {
+ winerror();
+ return 0;
+ }
+
+ CloseHandle(pi.hThread);
+
+ if(addchild(pi.dwProcessId, pi.hProcess) == 0)
+ return 0;
+
+ return pi.dwProcessId;
+}
+
+int
+pipe(int *fd)
+{
+ return _pipe(fd, 0, _O_BINARY);
+}
diff --git a/utils/rcsh/code.c b/utils/rcsh/code.c
new file mode 100644
index 00000000..06aea6ff
--- /dev/null
+++ b/utils/rcsh/code.c
@@ -0,0 +1,486 @@
+#include "rc.h"
+#include "y.tab.h"
+
+#define c0 t->child[0]
+#define c1 t->child[1]
+#define c2 t->child[2]
+#define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
+#define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
+#define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
+
+void stuffdot(int);
+char *fnstr(Tree*);
+void outcode(Tree*, int);
+void codeswitch(Tree*, int);
+int iscase(Tree*);
+Code *codecopy(Code*);
+void codefree(Code*);
+
+int codep, ncode;
+Code *codebuf;
+
+int
+morecode(void)
+{
+ ncode+=100;
+ codebuf=realloc(codebuf, ncode*sizeof codebuf[0]);
+ if(codebuf==0)
+ panic("Can't realloc %d bytes in morecode!",
+ ncode*sizeof codebuf[0]);
+ return 0; /* not used */
+}
+
+void
+stuffdot(int a)
+{
+ if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
+ codebuf[a].i=codep;
+}
+
+int
+compile(Tree *t)
+{
+ ncode=100;
+ codebuf=malloc(ncode*sizeof codebuf[0]);
+ codep=0;
+ emiti(0); /* reference count */
+ outcode(t, flag['e']?1:0);
+ if(nerror){
+ free(codebuf);
+ return 0;
+ }
+/* readhere(); */
+ emitf(Xreturn);
+ emitf(0);
+ return 1;
+}
+
+void
+cleanhere(char *f)
+{
+ emitf(Xdelhere);
+ emits(strdup(f));
+}
+
+char *
+fnstr(Tree *t)
+{
+ Io *f=openstr();
+ char *v;
+ extern char nl;
+ char svnl=nl;
+
+ nl=';';
+ pfmt(f, "%t", t);
+ nl=svnl;
+ v=f->strp;
+ f->strp=0;
+ closeio(f);
+ return v;
+}
+
+void
+outcode(Tree *t, int eflag)
+{
+ int p, q;
+ Tree *tt;
+
+ if(t==0)
+ return;
+ if(t->type != NOT && t->type != ';')
+ runq->iflast=0;
+ switch(t->type){
+ default:
+ pfmt(err, "bad type %d in outcode\n", t->type);
+ break;
+ case '$':
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xdol);
+ break;
+ case '"':
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xqdol);
+ break;
+ case SUB:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xsub);
+ break;
+ case '&':
+ emitf(Xasync);
+ emits(fnstr(c0));
+/*
+ p=emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ break;
+ case ';':
+ outcode(c0, eflag);
+ outcode(c1, eflag);
+ break;
+ case '^':
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xconc);
+ break;
+ case '`':
+ emitf(Xbackq);
+ emits(fnstr(c0));
+/*
+ p=emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ break;
+ case ANDAND:
+ outcode(c0, 0);
+ emitf(Xtrue);
+ p=emiti(0);
+ outcode(c1, eflag);
+ stuffdot(p);
+ break;
+ case ARGLIST:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
+ break;
+ case BANG:
+ outcode(c0, eflag);
+ emitf(Xbang);
+ break;
+ case PCMD:
+ case BRACE:
+ outcode(c0, eflag);
+ break;
+ case COUNT:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xcount);
+ break;
+ case FN:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ if(c1){
+ emitf(Xfn);
+ p=emiti(0);
+ emits(fnstr(c1));
+ outcode(c1, eflag);
+ emitf(Xunlocal); /* get rid of $* */
+ emitf(Xreturn);
+ stuffdot(p);
+ }
+ else
+ emitf(Xdelfn);
+ break;
+ case IF:
+ outcode(c0, 0);
+ emitf(Xif);
+ p=emiti(0);
+ outcode(c1, eflag);
+ emitf(Xwastrue);
+ stuffdot(p);
+ break;
+ case NOT:
+ if(!runq->iflast) yyerror("`if not' does not follow `if(...)'");
+ emitf(Xifnot);
+ p=emiti(0);
+ outcode(c0, eflag);
+ stuffdot(p);
+ break;
+ case OROR:
+ outcode(c0, 0);
+ emitf(Xfalse);
+ p=emiti(0);
+ outcode(c1, eflag);
+ stuffdot(p);
+ break;
+ case PAREN:
+ outcode(c0, eflag);
+ break;
+ case SIMPLE:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xsimple);
+ if(eflag) emitf(Xeflag);
+ break;
+ case SUBSHELL:
+ emitf(Xsubshell);
+ emits(fnstr(c0));
+/*
+ p=emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ if(eflag) emitf(Xeflag);
+ break;
+ case SWITCH:
+ codeswitch(t, eflag);
+ break;
+ case TWIDDLE:
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xmatch);
+ if(eflag) emitf(Xeflag);
+ break;
+ case WHILE:
+ q=codep;
+ emitf(Xsettrue);
+ outcode(c0, 0);
+ emitf(Xtrue);
+ p=emiti(0);
+ outcode(c1, eflag);
+ emitf(Xjump);
+ emiti(q);
+ stuffdot(p);
+ break;
+ case WORDS:
+ outcode(c1, eflag);
+ outcode(c0, eflag);
+ break;
+ case FOR:
+ emitf(Xmark);
+ if(c1){
+ outcode(c1, eflag);
+ emitf(Xglob);
+ }
+ else{
+ emitf(Xmark);
+ emitf(Xword);
+ emits(strdup("*"));
+ emitf(Xdol);
+ }
+ emitf(Xmark); /* dummy value for Xlocal */
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xlocal);
+ p=emitf(Xfor);
+ q=emiti(0);
+ outcode(c2, eflag);
+ emitf(Xjump);
+ emiti(p);
+ stuffdot(q);
+ emitf(Xunlocal);
+ break;
+ case WORD:
+ emitf(Xword);
+ emits(strdup(t->str));
+ break;
+ case DUP:
+ if(t->rtype==DUPFD) {
+ emitf(Xdup);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ } else { /* t->rtype == CLOSE */
+ emitf(Xclose);
+ emiti(t->fd0);
+ }
+ outcode(c1, eflag);
+ emitf(Xpopredir);
+ break;
+/*
+ case PIPEFD:
+ emitf(Xpipefd);
+ emiti(t->rtype);
+ p=emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ break;
+*/
+ case REDIR:
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xglob);
+ switch(t->rtype){
+ case APPEND:
+ emitf(Xappend);
+ break;
+ case WRITE:
+ emitf(Xwrite);
+ break;
+ case READ:
+ case HERE:
+ emitf(Xread);
+ break;
+ }
+ emiti(t->fd0);
+ outcode(c1, eflag);
+ emitf(Xpopredir);
+ break;
+ case '=':
+ tt=t;
+ for(;t && t->type=='=';t=c2)
+ ;
+ if(t){
+ for(t=tt;t->type=='=';t=c2){
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xlocal);
+ }
+ t=tt;
+ outcode(c2, eflag);
+ for(;t->type=='=';t=c2)
+ emitf(Xunlocal);
+ }
+ else{
+ for(t=tt;t;t=c2){
+ emitf(Xmark);
+ outcode(c1, eflag);
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xassign);
+ }
+ }
+ t=tt; /* so tests below will work */
+ break;
+ case PIPE:
+ emitf(Xpipe);
+ emiti(t->fd0);
+ emiti(t->fd1);
+ emits(fnstr(c0));
+ q=emiti(0);
+/*
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+*/
+ outcode(c1, eflag);
+ emitf(Xreturn);
+ stuffdot(q);
+ emitf(Xpipewait);
+ break;
+ }
+ if(t->type!=NOT && t->type!=';')
+ runq->iflast=t->type==IF;
+ else if(c0) runq->iflast=c0->type==IF;
+}
+
+/*
+ * switch code looks like this:
+ * Xmark
+ * (get switch value)
+ * Xjump 1f
+ * out: Xjump leave
+ * 1: Xmark
+ * (get case values)
+ * Xcase 1f
+ * (commands)
+ * Xjump out
+ * 1: Xmark
+ * (get case values)
+ * Xcase 1f
+ * (commands)
+ * Xjump out
+ * 1:
+ * leave:
+ * Xpopm
+ */
+void
+codeswitch(Tree *t, int eflag)
+{
+ int leave; /* patch jump address to leave switch */
+ int out; /* jump here to leave switch */
+ int nextcase; /* patch jump address to next case */
+ Tree *tt;
+ if(c1->child[0]->type!=';'
+ || !iscase(c1->child[0]->child[0])){
+ yyerror("case missing in switch");
+ return;
+ }
+ emitf(Xmark);
+ outcode(c0, eflag);
+ emitf(Xjump);
+ nextcase=emiti(0);
+ out=emitf(Xjump);
+ leave=emiti(0);
+ stuffdot(nextcase);
+ t=c1->child[0];
+ while(t->type==';'){
+ tt=c1;
+ emitf(Xmark);
+ for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
+ emitf(Xcase);
+ nextcase=emiti(0);
+ t=tt;
+ for(;;){
+ if(t->type==';'){
+ if(iscase(c0)) break;
+ outcode(c0, eflag);
+ t=c1;
+ }
+ else{
+ outcode(t, eflag);
+ break;
+ }
+ }
+ emitf(Xjump);
+ emiti(out);
+ stuffdot(nextcase);
+ }
+ stuffdot(leave);
+ emitf(Xpopm);
+}
+
+int
+iscase(Tree *t)
+{
+ if(t->type!=SIMPLE)
+ return 0;
+ do
+ t=c0;
+ while(t->type==ARGLIST);
+
+ return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
+}
+
+Code *
+codecopy(Code *cp)
+{
+ cp[0].i++;
+ return cp;
+}
+
+void
+codefree(Code *cp)
+{
+ Code *p;
+
+ if(--cp[0].i!=0)
+ return;
+
+ for(p=cp+1;p->f;){
+ if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
+ || p->f==Xasync || p->f==Xcase || p->f==Xfalse
+ || p->f==Xfor || p->f==Xjump
+ || p->f==Xsubshell || p->f==Xtrue)
+ p+=2;
+ else if(p->f==Xdup || p->f==Xpipefd)
+ p+=3;
+ else if(p->f==Xpipe) {
+ free(p[3].s);
+ p+=5;
+ } else if(p->f==Xword || p->f==Xdelhere || p->f==Xbackq) {
+ free(p[1].s);
+ p+=2;
+ } else if(p->f==Xfn){
+ free(p[2].s);
+ p+=3;
+ } else
+ p++;
+ }
+
+ free(cp);
+}
diff --git a/utils/rcsh/exec.c b/utils/rcsh/exec.c
new file mode 100644
index 00000000..66112d80
--- /dev/null
+++ b/utils/rcsh/exec.c
@@ -0,0 +1,802 @@
+#include "rc.h"
+
+extern char *argv0;
+
+int ifnot;
+int eflagok;
+
+/*
+ * Opcode routines
+ * Arguments on stack (...)
+ * Arguments in line [...]
+ * Code in line with jump around {...}
+ *
+ * Xappend(file)[fd] open file to append
+ * Xassign(name, val) assign val to name
+ * Xasync{... Xexit} make thread for {}, no wait
+ * Xbackq{... Xreturn} make thread for {}, push stdout
+ * Xbang complement condition
+ * Xcase(pat, value){...} exec code on match, leave (value) on
+ * stack
+ * Xclose[i] close file descriptor
+ * Xconc(left, right) concatenate, push results
+ * Xcount(name) push var count
+ * Xdelfn(name) delete function definition
+ * Xdeltraps(names) delete named traps
+ * Xdol(name) get variable value
+ * Xqdol(name) concatenate variable components
+ * Xdup[i j] dup file descriptor
+ * Xexit rc exits with status
+ * Xfalse{...} execute {} if false
+ * Xfn(name){... Xreturn} define function
+ * Xfor(var, list){... Xreturn} for loop
+ * Xjump[addr] goto
+ * Xlocal(name, val) create local variable, assign value
+ * Xmark mark stack
+ * Xmatch(pat, str) match pattern, set status
+ * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
+ * wait for both
+ * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
+ * depending on type), push /dev/fd/??
+ * Xpopm(value) pop value from stack
+ * Xread(file)[fd] open file to read
+ * Xsettraps(names){... Xreturn} define trap functions
+ * Xshowtraps print trap list
+ * Xsimple(args) run command and wait
+ * Xreturn kill thread
+ * Xsubshell{... Xexit} execute {} in a subshell and wait
+ * Xtrue{...} execute {} if true
+ * Xunlocal delete local variable
+ * Xword[string] push string
+ * Xwrite(file)[fd] open file to write
+ */
+
+static char **
+rcargv(char *s)
+{
+ char *flags;
+
+ if(flag['e'])
+ flags = "-Se";
+ else
+ flags = "-S";
+ return procargv(argv0, flags, "-c", s, vlook("*")->val);
+}
+
+void
+Xappend(void)
+{
+ char *file;
+ int f;
+
+ switch(count(runq->argv->words)){
+ default: Xerror(">> requires singleton"); return;
+ case 0: Xerror(">> requires file"); return;
+ case 1: break;
+ }
+ file=runq->argv->words->word;
+ if((f=open(file, 1))<0 && (f=create(file, 1, 0666))<0){
+ Xperror(file);
+ return;
+ }
+ seek(f, 0L, 2);
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+void
+Xassign(void)
+{
+ Var *v;
+
+ if(count(runq->argv->words)!=1){
+ Xerror("variable name not singleton!");
+ return;
+ }
+ deglob(runq->argv->words->word);
+ v=vlook(runq->argv->words->word);
+ poplist();
+ globlist();
+ freewords(v->val);
+ v->val=runq->argv->words;
+ v->changed=1;
+ runq->argv->words=0;
+ poplist();
+}
+
+void
+Xasync(void)
+{
+ uint pid;
+ char buf[20], **argv;
+
+ updenv();
+
+ argv = rcargv(runq->code[runq->pc].s);
+ pid = proc(argv, -1, 1, 2);
+ free(argv);
+
+ if(pid == 0) {
+ Xerror("proc failed");
+ return;
+ }
+
+ runq->pc++;
+ sprint(buf, "%d", pid);
+ setvar("apid", newword(buf, (Word *)0));
+}
+
+void
+Xbackq(void)
+{
+ char wd[8193], **argv;
+ int c;
+ char *s, *ewd=&wd[8192], *stop;
+ Io *f;
+ Var *ifs=vlook("ifs");
+ Word *v, *nextv;
+ int pfd[2];
+ int pid;
+
+ stop = ifs->val?ifs->val->word:"";
+ if(pipe(pfd)<0){
+ Xerror("can't make pipe");
+ return;
+ }
+
+ updenv();
+
+ argv = rcargv(runq->code[runq->pc].s);
+ pid = proc(argv, -1, pfd[1], 2);
+ free(argv);
+
+ close(pfd[1]);
+
+ if(pid == 0) {
+ Xerror("proc failed");
+ close(pfd[0]);
+ return;
+ }
+
+ f = openfd(pfd[0]);
+ s = wd;
+ v = 0;
+ while((c=rchr(f))!=EOF){
+ if(strchr(stop, c) || s==ewd){
+ if(s!=wd){
+ *s='\0';
+ v=newword(wd, v);
+ s=wd;
+ }
+ }
+ else *s++=c;
+ }
+ if(s!=wd){
+ *s='\0';
+ v=newword(wd, v);
+ }
+ closeio(f);
+ waitfor(pid);
+ /* v points to reversed arglist -- reverse it onto argv */
+ while(v){
+ nextv=v->next;
+ v->next=runq->argv->words;
+ runq->argv->words=v;
+ v=nextv;
+ }
+ runq->pc++;
+}
+
+void
+Xbang(void)
+{
+ setstatus(truestatus()?"false":"");
+}
+
+void
+Xcase(void)
+{
+ Word *p;
+ char *s;
+ int ok=0;
+
+ s=list2str(runq->argv->next->words);
+ for(p=runq->argv->words;p;p=p->next){
+ if(match(s, p->word, '\0')){
+ ok=1;
+ break;
+ }
+ }
+ free(s);
+ if(ok)
+ runq->pc++;
+ else
+ runq->pc=runq->code[runq->pc].i;
+ poplist();
+}
+
+void
+Xclose(void)
+{
+ pushredir(RCLOSE, runq->code[runq->pc].i, 0);
+ runq->pc++;
+}
+
+void
+Xconc(void)
+{
+ Word *lp=runq->argv->words;
+ Word *rp=runq->argv->next->words;
+ Word *vp=runq->argv->next->next->words;
+ int lc=count(lp), rc=count(rp);
+
+ if(lc!=0 || rc!=0){
+ if(lc==0 || rc==0){
+ Xerror("null list in concatenation");
+ return;
+ }
+ if(lc!=1 && rc!=1 && lc!=rc){
+ Xerror("mismatched list lengths in concatenation");
+ return;
+ }
+ vp=conclist(lp, rp, vp);
+ }
+ poplist();
+ poplist();
+ runq->argv->words=vp;
+}
+
+void
+Xcount(void)
+{
+ Word *a;
+ char *s, *t;
+ int n;
+ char num[12];
+
+ if(count(runq->argv->words)!=1){
+ Xerror("variable name not singleton!");
+ return;
+ }
+ s=runq->argv->words->word;
+ deglob(s);
+ n=0;
+ for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
+ if(n==0 || *t){
+ a=vlook(s)->val;
+ sprint(num, "%d", count(a));
+ }
+ else{
+ a=vlook("*")->val;
+ sprint(num, "%d", a && 1<=n && n<=count(a)?1:0);
+ }
+ poplist();
+ pushword(num);
+}
+
+void
+Xdelfn(void)
+{
+ Var *v;
+ Word *a;
+
+ for(a=runq->argv->words;a;a=a->next){
+ v=gvlook(a->word);
+ if(v->fn)
+ codefree(v->fn);
+ v->fn=0;
+ v->fnchanged=1;
+ }
+ poplist();
+}
+
+void
+Xdelhere(void)
+{
+ Var *v;
+ Word *a;
+
+ for(a=runq->argv->words;a;a=a->next){
+ v=gvlook(a->word);
+ if(v->fn) codefree(v->fn);
+ v->fn=0;
+ v->fnchanged=1;
+ }
+ poplist();
+}
+
+void
+Xdol(void)
+{
+ Word *a, *star;
+ char *s, *t;
+ int n;
+
+ if(count(runq->argv->words)!=1){
+ Xerror("variable name not singleton!");
+ return;
+ }
+ s=runq->argv->words->word;
+ deglob(s);
+ n=0;
+ for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
+ a=runq->argv->next->words;
+ if(n==0 || *t)
+ a=copywords(vlook(s)->val, a);
+ else{
+ star=vlook("*")->val;
+ if(star && 1<=n && n<=count(star)){
+ while(--n) star=star->next;
+ a=newword(star->word, a);
+ }
+ }
+ poplist();
+ runq->argv->words=a;
+}
+
+void
+Xdup(void)
+{
+ pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
+ runq->pc+=2;
+}
+
+void
+Xeflag(void)
+{
+ if(eflagok && !truestatus())
+ Xexit();
+}
+
+void
+Xexit(void)
+{
+ Var *trapreq;
+ Word *starval;
+ char *c;
+ static int beenhere=0;
+
+ if(truestatus())
+ c = "";
+ else
+ c = getstatus();
+
+ if(flag['S'] || beenhere)
+ exits(c);
+
+ trapreq=vlook("sigexit");
+ if(trapreq->fn){
+ beenhere=1;
+ --runq->pc;
+ starval=vlook("*")->val;
+ start(trapreq->fn, trapreq->pc, (Var*)0);
+ runq->local=newvar(strdup("*"), runq->local);
+ runq->local->val=copywords(starval, (Word*)0);
+ runq->local->changed=1;
+ runq->redir=runq->startredir=0;
+ }
+
+ exits(c);
+}
+
+void
+Xfalse(void)
+{
+ if(truestatus())
+ runq->pc=runq->code[runq->pc].i;
+ else
+ runq->pc++;
+}
+
+void
+Xfor(void)
+{
+ if(runq->argv->words==0) {
+ poplist();
+ runq->pc=runq->code[runq->pc].i;
+ } else {
+ freelist(runq->local->val);
+ runq->local->val=runq->argv->words;
+ runq->local->changed=1;
+ runq->argv->words=runq->argv->words->next;
+ runq->local->val->next=0;
+ runq->pc++;
+ }
+}
+
+void
+Xfn(void)
+{
+ Var *v;
+ Word *a;
+ int end;
+
+ end=runq->code[runq->pc].i;
+ for(a=runq->argv->words;a;a=a->next){
+ v=gvlook(a->word);
+ if(v->fn)
+ codefree(v->fn);
+ v->fn=codecopy(runq->code);
+ v->pc=runq->pc+2;
+ v->fnchanged=1;
+ }
+ runq->pc=end;
+ poplist();
+}
+
+void
+Xglob(void)
+{
+ globlist();
+}
+
+void
+Xif(void)
+{
+ ifnot=1;
+ if(truestatus()) runq->pc++;
+ else runq->pc=runq->code[runq->pc].i;
+}
+
+void
+Xifnot(void)
+{
+ if(ifnot)
+ runq->pc++;
+ else
+ runq->pc=runq->code[runq->pc].i;
+}
+
+void
+Xjump(void)
+{
+ runq->pc=runq->code[runq->pc].i;
+}
+
+
+void
+Xlocal(void)
+{
+ if(count(runq->argv->words)!=1){
+ Xerror("variable name must be singleton\n");
+ return;
+ }
+ deglob(runq->argv->words->word);
+ runq->local=newvar(strdup(runq->argv->words->word), runq->local);
+ runq->local->val=copywords(runq->argv->next->words, 0);
+ runq->local->changed=1;
+ poplist();
+ poplist();
+}
+
+
+void
+Xmark(void)
+{
+ pushlist();
+}
+
+void
+Xmatch(void)
+{
+ Word *p;
+ char *subject;
+
+ subject=list2str(runq->argv->words);
+ setstatus("no match");
+ for(p=runq->argv->next->words;p;p=p->next) {
+ if(match(subject, p->word, '\0')){
+ setstatus("");
+ break;
+ }
+ }
+ free(subject);
+ poplist();
+ poplist();
+}
+
+void
+Xpipe(void)
+{
+ Thread *p=runq;
+ int pc=p->pc, pid;
+ int lfd=p->code[pc].i;
+ int rfd=p->code[pc+1].i;
+ int pfd[2];
+ char **argv;
+
+ if(pipe(pfd)<0){
+ Xperror("can't get pipe");
+ return;
+ }
+
+ updenv();
+
+ argv = rcargv(runq->code[pc+2].s);
+ pid = proc(argv, 0, pfd[1], 2);
+ free(argv);
+ close(pfd[1]);
+
+ if(pid == 0) {
+ Xerror("proc failed");
+ close(pfd[0]);
+ return;
+ }
+
+ start(p->code, pc+4, runq->local);
+ pushredir(ROPEN, pfd[0], rfd);
+ p->pc=p->code[pc+3].i;
+ p->pid=pid;
+}
+
+void
+Xpipefd(void)
+{
+ fatal("Xpipefd");
+}
+
+void
+Xpipewait(void)
+{
+ char status[NSTATUS+1];
+ if(runq->pid==-1)
+ setstatus(concstatus(runq->status, getstatus()));
+ else{
+ strncpy(status, getstatus(), NSTATUS);
+ status[NSTATUS]='\0';
+ waitfor(runq->pid);
+ runq->pid=-1;
+ setstatus(concstatus(getstatus(), status));
+ }
+}
+
+void
+Xpopm(void)
+{
+ poplist();
+}
+
+void
+Xpopredir(void)
+{
+ Redir *rp=runq->redir;
+
+ if(rp==0)
+ panic("turfredir null!", 0);
+ runq->redir=rp->next;
+ if(rp->type==ROPEN)
+ close(rp->from);
+ free((char *)rp);
+}
+
+void
+Xqdol(void)
+{
+ Word *a, *p;
+ char *s;
+ int n;
+
+ if(count(runq->argv->words)!=1){
+ Xerror("variable name not singleton!");
+ return;
+ }
+ s=runq->argv->words->word;
+ deglob(s);
+ a=vlook(s)->val;
+ poplist();
+ n=count(a);
+ if(n==0){
+ pushword("");
+ return;
+ }
+ for(p=a;p;p=p->next) n+=strlen(p->word);
+ s=malloc(n);
+ if(a){
+ strcpy(s, a->word);
+ for(p=a->next;p;p=p->next){
+ strcat(s, " ");
+ strcat(s, p->word);
+ }
+ }
+ else
+ s[0]='\0';
+ pushword(s);
+ free(s);
+}
+
+void
+Xrdcmds(void)
+{
+ Thread *p=runq;
+ Word *prompt;
+
+ flush(err);
+ nerror=0;
+ if(flag['s'] && !truestatus())
+ pfmt(err, "status=%v\n", vlook("status")->val);
+ if(runq->iflag){
+ prompt=vlook("prompt")->val;
+ if(prompt)
+ promptstr=prompt->word;
+ else
+ promptstr="% ";
+ }
+ interrupted=0;
+ if(yyparse()) {
+ if(!p->iflag || p->eof /* && !Eintr() */) {
+ if(p->cmdfile)
+ free(p->cmdfile);
+ closeio(p->cmdfd);
+ Xreturn(); /* should this be omitted? */
+ } else {
+ if(interrupted){
+ pchr(err, '\n');
+ p->eof=0;
+ }
+ --p->pc; /* go back for next command */
+ }
+ } else {
+ --p->pc; /* re-execute Xrdcmds after codebuf runs */
+ start(codebuf, 1, runq->local);
+ }
+ freenodes();
+}
+
+void
+Xread(void)
+{
+ char *file;
+ int f;
+
+ switch(count(runq->argv->words)){
+ default: Xerror("< requires singleton\n"); return;
+ case 0: Xerror("< requires file\n"); return;
+ case 1: break;
+ }
+ file=runq->argv->words->word;
+ if((f=open(file, 0))<0){
+ Xperror(file);
+ return;
+ }
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+void
+Xreturn(void)
+{
+ Thread *p=runq;
+
+ turfredir();
+ while(p->argv)
+ poplist();
+ codefree(p->code);
+ runq=p->ret;
+ free(p);
+ if(runq==0)
+ exits(truestatus()?"":getstatus());
+}
+
+void
+Xsettrue(void)
+{
+ setstatus("");
+}
+
+
+void
+Xsub(void)
+{
+ Word *a, *v;
+ char *s;
+ if(count(runq->argv->next->words)!=1){
+ Xerror("variable name not singleton!");
+ return;
+ }
+ s=runq->argv->next->words->word;
+ deglob(s);
+ a=runq->argv->next->next->words;
+ v=vlook(s)->val;
+ a=subwords(v, count(v), runq->argv->words, a);
+ poplist();
+ poplist();
+ runq->argv->words=a;
+}
+
+void
+Xsubshell(void)
+{
+ char **argv;
+ uint pid;
+
+ updenv();
+
+ argv = rcargv(runq->code[runq->pc].s);
+ pid = proc(argv, -1, 1, 2);
+ free(argv);
+
+ if(pid == 0) {
+ Xerror("proc failed");
+ return;
+ }
+
+ waitfor(pid);
+ runq->pc++;
+}
+
+void
+Xtrue(void)
+{
+ if(truestatus())
+ runq->pc++;
+ else
+ runq->pc=runq->code[runq->pc].i;
+}
+
+void
+Xunlocal(void)
+{
+ Var *v=runq->local, *hid;
+
+ if(v==0)
+ panic("Xunlocal: no locals!", 0);
+ runq->local=v->next;
+ hid=vlook(v->name);
+ hid->changed=1;
+ free(v->name);
+ freewords(v->val);
+ free(v);
+}
+
+void
+Xwastrue(void)
+{
+ ifnot=0;
+}
+
+void
+Xwrite(void)
+{
+ char *file;
+ int f;
+
+ switch(count(runq->argv->words)){
+ default: Xerror("> requires singleton\n"); return;
+ case 0: Xerror("> requires file\n"); return;
+ case 1: break;
+ }
+ file=runq->argv->words->word;
+ if((f = create(file, 1, 0666))<0){
+ Xperror(file);
+ return;
+ }
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+void
+Xword(void)
+{
+ pushword(runq->code[runq->pc++].s);
+}
+
+void
+Xerror(char *s)
+{
+ pfmt(err, "rcsh: %s\n", s);
+ flush(err);
+ while(!runq->iflag)
+ Xreturn();
+}
+
+void
+Xperror(char *s)
+{
+ pfmt(err, "rcsh: %s: %r\n", s);
+ flush(err);
+ while(!runq->iflag)
+ Xreturn();
+}
diff --git a/utils/rcsh/glob.c b/utils/rcsh/glob.c
new file mode 100644
index 00000000..7640eeb1
--- /dev/null
+++ b/utils/rcsh/glob.c
@@ -0,0 +1,286 @@
+#include "rc.h"
+
+char *globname;
+Word *globv;
+
+int matchfn(char *s, char *p);
+int globsize(char *p);
+
+/*
+ * delete all the GLOB marks from s, in place
+ */
+void
+deglob(char *s)
+{
+ char *t=s;
+ do{
+ if(*t==GLOB) t++;
+ *s++=*t;
+ }while(*t++);
+}
+
+int
+globcmp(const void *s, const void *t)
+{
+ return strcmp(*(char**)s, *(char**)t);
+}
+
+void
+globsort(Word *left, Word *right)
+{
+ char **list;
+ Word *a;
+ int n=0;
+ for(a=left;a!=right;a=a->next) n++;
+ list=(char **)malloc(n*sizeof(char *));
+ for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word;
+ qsort((void*)list, (size_t)n, sizeof(char*), globcmp);
+ for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
+ free(list);
+}
+
+/*
+ * Push names prefixed by globname and suffixed by a match of p onto the astack.
+ * namep points to the end of the prefix in globname.
+ */
+void
+globdir(char *p, char *namep)
+{
+ char *t, *q, *newp;
+ Direntry *dp, *dq;
+ Dir *dir;
+
+ /* scan the pattern looking for a component with a metacharacter in it */
+ if(*p=='\0'){
+ globv=newword(globname, globv);
+ return;
+ }
+ t=namep;
+ newp=p;
+ while(*newp){
+ if(*newp==GLOB)
+ break;
+ *t=*newp++;
+ if(*t++=='/'){
+ namep=t;
+ p=newp;
+ }
+ }
+ /* If we ran out of pattern, append the name if accessible */
+ if(*newp=='\0'){
+ *t='\0';
+ if(access(globname, 0)==0)
+ globv=newword(globname, globv);
+ return;
+ }
+ /* read the directory and recur for any entry that matches */
+ *namep='\0';
+ t = globname;
+ if(*t == 0)
+ t = ".";
+ q = strdup(t);
+ if (q[strlen(q)-1] == '/')
+ q[strlen(q)-1] = 0;
+ if((dir=dirstat(q)) == nil || !(dir->mode&0x80000000)){
+ free(dir);
+ return;
+ }
+ free(dir);
+ dq = readdirect(q);
+ if(dq == 0){
+ fprint(2, "could not open %s: %r\n", q);
+ return;
+ }
+ while(*newp!='/' && *newp!='\0')
+ newp++;
+ for(dp = dq;dp->name; dp++){
+ strcpy(namep, dp->name);
+ if(matchfn(namep, p))
+ globdir(newp, namep+strlen(namep));
+ free(dp->name);
+ }
+ free(dq);
+}
+
+/*
+ * Push all file names matched by p on the current thread's stack.
+ * If there are no matches, the list consists of p.
+ */
+void
+glob(char *p)
+{
+ Word *svglobv=globv;
+ int globlen=globsize(p);
+
+ if(globlen == 0){
+ deglob(p);
+ globv=newword(p, globv);
+ return;
+ }
+ globname=malloc(globlen);
+ globname[0]='\0';
+ globdir(p, globname);
+ free(globname);
+ if(svglobv==globv){
+ deglob(p);
+ globv=newword(p, globv);
+ }
+ else
+ globsort(globv, svglobv);
+}
+
+
+/*
+ * Do p and q point at equal utf codes
+ */
+int
+equtf(char *p, char *q)
+{
+ if(*p!=*q)
+ return 0;
+ if(twobyte(*p)) return p[1]==q[1];
+ if(threebyte(*p)){
+ if(p[1]!=q[1]) return 0;
+ if(p[1]=='\0') return 1; /* broken code at end of string! */
+ return p[2]==q[2];
+ }
+ return 1;
+}
+
+/*
+ * Return a pointer to the next utf code in the string,
+ * not jumping past nuls in broken utf codes!
+ */
+char *
+nextutf(char *p)
+{
+ if(twobyte(*p))
+ return p[1]=='\0'?p+1:p+2;
+ if(threebyte(*p))
+ return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
+ return p+1;
+}
+
+/*
+ * Convert the utf code at *p to a unicode value
+ */
+int
+unicode(char *p)
+{
+ int u=*p&0xff;
+ if(twobyte(u))
+ return ((u&0x1f)<<6)|(p[1]&0x3f);
+ if(threebyte(u))
+ return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
+ return u;
+}
+
+/*
+ * Does the string s match the pattern p
+ * . and .. are only matched by patterns starting with .
+ * * matches any sequence of characters
+ * ? matches any single character
+ * [...] matches the enclosed list of characters
+ */
+int
+matchfn(char *s, char *p)
+{
+ if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
+ return 0;
+ return match(s, p, '/');
+}
+
+int
+match(char *s, char *p, int stop)
+{
+ int compl, hit, lo, hi, t, c;
+
+ for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)) {
+ if(*p!=GLOB){
+ if(!equtf(p, s)) return 0;
+ }
+ else switch(*++p){
+ case GLOB:
+ if(*s!=GLOB) return 0;
+ break;
+ case '*':
+ for(;;){
+ if(match(s, nextutf(p), stop)) return 1;
+ if(!*s) break;
+ s=nextutf(s);
+ }
+ return 0;
+ case '?':
+ if(*s=='\0') return 0;
+ break;
+ case '[':
+ if(*s=='\0') return 0;
+ c=unicode(s);
+ p++;
+ compl=*p=='~';
+ if(compl) p++;
+ hit=0;
+ while(*p!=']'){
+ if(*p=='\0') return 0; /* syntax error */
+ lo=unicode(p);
+ p=nextutf(p);
+ if(*p!='-') hi=lo;
+ else{
+ p++;
+ if(*p=='\0') return 0; /* syntax error */
+ hi=unicode(p);
+ p=nextutf(p);
+ if(hi<lo){ t=lo; lo=hi; hi=t; }
+ }
+ if(lo<=c && c<=hi) hit=1;
+ }
+ if(compl) hit=!hit;
+ if(!hit) return 0;
+ break;
+ }
+ }
+ return *s=='\0';
+}
+
+void
+globlist1(Word *gl)
+{
+ if(gl){
+ globlist1(gl->next);
+ glob(gl->word);
+ }
+}
+
+void
+globlist(void)
+{
+ Word *a;
+
+ globv=0;
+ globlist1(runq->argv->words);
+ poplist();
+ pushlist();
+ if(globv){
+ for(a=globv;a->next;a=a->next);
+ a->next=runq->argv->words;
+ runq->argv->words=globv;
+ }
+}
+
+#define NDIR 128
+int
+globsize(char *p)
+{
+ ulong isglob=0, globlen=NDIR+1;
+
+ for(;*p;p++){
+ if(*p==GLOB){
+ p++;
+ if(*p!=GLOB) isglob++;
+ globlen+=*p=='*'?NDIR:1;
+ }
+ else
+ globlen++;
+ }
+ return isglob?globlen:0;
+}
diff --git a/utils/rcsh/here.c b/utils/rcsh/here.c
new file mode 100644
index 00000000..bd1f79cc
--- /dev/null
+++ b/utils/rcsh/here.c
@@ -0,0 +1,145 @@
+#include "rc.h"
+#include "y.tab.h"
+
+Here *here, **ehere;
+int ser;
+
+char tmp[]="/tmp/here0000.0000";
+char hex[]="0123456789abcdef";
+
+void psubst(Io*, char*);
+void pstrs(Io*, Word*);
+
+void hexnum(char *p, int n)
+{
+ *p++=hex[(n>>12)&0xF];
+ *p++=hex[(n>>8)&0xF];
+ *p++=hex[(n>>4)&0xF];
+ *p=hex[n&0xF];
+}
+
+Tree *
+heredoc(Tree *tag)
+{
+ Here *h=new(Here);
+
+ if(tag->type!=WORD)
+ yyerror("Bad here tag");
+ h->next=0;
+ if(here)
+ *ehere=h;
+ else
+ here=h;
+ ehere=&h->next;
+ h->tag=tag;
+ hexnum(&tmp[9], getpid());
+ hexnum(&tmp[14], ser++);
+ h->name=strdup(tmp);
+ return token(tmp, WORD);
+}
+/*
+ * bug: lines longer than NLINE get split -- this can cause spurious
+ * missubstitution, or a misrecognized EOF marker.
+ */
+#define NLINE 4096
+void
+readhere(void)
+{
+ Here *h, *nexth;
+ Io *f;
+ char *s, *tag;
+ int c, subst;
+ char line[NLINE+1];
+
+ for(h=here;h;h=nexth){
+ subst=!h->tag->quoted;
+ tag=h->tag->str;
+ c=create(h->name, 1, 0666);
+ if(c<0) yyerror("can't create here document");
+ f=openfd(c);
+ s=line;
+ pprompt();
+ while((c=rchr(runq->cmdfd))!=EOF){
+ if(c=='\n' || s==&line[NLINE]){
+ *s='\0';
+ if(strcmp(line, tag)==0) break;
+ if(subst) psubst(f, line);
+ else pstr(f, line);
+ s=line;
+ if(c=='\n'){
+ pprompt();
+ pchr(f, c);
+ }
+ else *s++=c;
+ }
+ else *s++=c;
+ }
+ flush(f);
+ closeio(f);
+ cleanhere(h->name);
+ nexth=h->next;
+ free(h);
+ }
+ here=0;
+ doprompt=1;
+}
+
+void
+psubst(Io *f, char *s)
+{
+ char *t, *u;
+ int savec, n;
+ Word *star;
+
+ while(*s){
+ if(*s!='$'){
+ if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
+ pchr(f, *s++);
+ if(*s=='\0') break;
+ }
+ else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
+ pchr(f, *s++);
+ if(*s=='\0') break;
+ pchr(f, *s++);
+ if(*s=='\0') break;
+ }
+ pchr(f, *s++);
+ }
+ else{
+ t=++s;
+ if(*t=='$') pchr(f, *t++);
+ else{
+ while(*t && idchr(*t)) t++;
+ savec=*t;
+ *t='\0';
+ n=0;
+ for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*u-'0';
+ if(n && *u=='\0'){
+ star=vlook("*")->val;
+ if(star && 1<=n && n<=count(star)){
+ while(--n) star=star->next;
+ pstr(f, star->word);
+ }
+ }
+ else
+ pstrs(f, vlook(s)->val);
+ *t=savec;
+ if(savec=='^') t++;
+ }
+ s=t;
+ }
+ }
+}
+
+void
+pstrs(Io *f, Word *a)
+{
+ if(a){
+ while(a->next && a->next->word){
+ pstr(f, a->word);
+ pchr(f, ' ');
+ a=a->next;
+ }
+ pstr(f, a->word);
+ }
+}
diff --git a/utils/rcsh/io.c b/utils/rcsh/io.c
new file mode 100644
index 00000000..6ac2555e
--- /dev/null
+++ b/utils/rcsh/io.c
@@ -0,0 +1,238 @@
+#include "rc.h"
+
+int pfmtnest=0;
+
+void pdec(Io*, long);
+void poct(Io*, ulong);
+void phex(Io*, long);
+void pquo(Io*, char*);
+void pwrd(Io*, char*);
+void pcmd(Io*, Tree*);
+void pval(Io*, Word*);
+
+void
+pfmt(Io *f, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pfmtnest++;
+ for(;*fmt;fmt++) {
+ if(*fmt!='%') pchr(f, *fmt);
+ else switch(*++fmt){
+ case '\0': va_end(ap); return;
+ case 'c': pchr(f, va_arg(ap, int)); break;
+ case 'd': pdec(f, va_arg(ap, int)); break;
+ case 'o': poct(f, va_arg(ap, unsigned)); break;
+ case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/
+ case 'Q': pquo(f, va_arg(ap, char *)); break;
+ case 'q': pwrd(f, va_arg(ap, char *)); break;
+ case 'r': perr(f); break;
+ case 's': pstr(f, va_arg(ap, char *)); break;
+ case 't': pcmd(f, va_arg(ap, Tree *)); break;
+ case 'v': pval(f, va_arg(ap, Word *)); break;
+ default: pchr(f, *fmt); break;
+ }
+ }
+ va_end(ap);
+ if(--pfmtnest==0) flush(f);
+}
+
+void
+perr(Io *f)
+{
+ char err[ERRMAX];
+
+ err[0] = 0;
+ errstr(err, sizeof err);
+ pstr(f, err);
+ errstr(err, sizeof err);
+}
+
+void
+pquo(Io *f, char *s)
+{
+ pchr(f, '\'');
+ for(;*s;s++)
+ if(*s=='\'') pfmt(f, "''");
+ else pchr(f, *s);
+ pchr(f, '\'');
+}
+
+void
+pwrd(Io *f, char *s)
+{
+ char *t;
+ for(t=s;*t;t++)
+ if(!wordchr(*t))
+ break;
+ if(t==s || *t)
+ pquo(f, s);
+ else
+ pstr(f, s);
+}
+
+void
+phex(Io *f, long p)
+{
+ int n;
+ for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+}
+
+void
+pstr(Io *f, char *s)
+{
+ if(s==0)
+ s="(null)";
+ while(*s)
+ pchr(f, *s++);
+}
+
+void
+pdec(Io *f, long n)
+{
+ if(n<0){
+ n=-n;
+ if(n>=0){
+ pchr(f, '-');
+ pdec(f, n);
+ return;
+ }
+ /* n is two's complement minimum integer */
+ n=1-n;
+ pchr(f, '-');
+ pdec(f, n/10);
+ pchr(f, n%10+'1');
+ return;
+ }
+ if(n>9) pdec(f, n/10);
+ pchr(f, n%10+'0');
+}
+
+void
+poct(Io *f, ulong n)
+{
+ if(n>7) poct(f, n>>3);
+ pchr(f, (n&7)+'0');
+}
+
+void
+pval(Io *f, Word *a)
+{
+ if(a){
+ while(a->next && a->next->word){
+ pwrd(f, a->word);
+ pchr(f, ' ');
+ a=a->next;
+ }
+ pwrd(f, a->word);
+ }
+}
+
+int
+fullbuf(Io *f, int c)
+{
+ flush(f);
+ return *f->bufp++=c;
+}
+
+void
+flush(Io *f)
+{
+ int n;
+ char *s;
+ if(f->strp){
+ n=f->ebuf-f->strp;
+ f->strp=realloc(f->strp, n+101);
+ if(f->strp==0)
+ panic("Can't realloc %d bytes in flush!", n+101);
+ f->bufp=f->strp+n;
+ f->ebuf=f->bufp+100;
+ for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ }
+ else{
+ n=f->bufp-f->buf;
+ if(n && write(f->fd, f->buf, n) < 0){
+/* write(3, "Write error\n", 12);
+ if(ntrap.ref)
+ dotrap();
+*/
+ }
+ f->bufp=f->buf;
+ f->ebuf=f->buf+NBUF;
+ }
+}
+
+Io *
+openfd(int fd)
+{
+ Io *f = new(Io);
+ f->fd = fd;
+ f->bufp = f->ebuf = f->buf;
+ f->strp = 0;
+ return f;
+}
+
+Io *
+openstr(void)
+{
+ Io *f=new(struct Io);
+ char *s;
+ f->fd=-1;
+ f->bufp=f->strp=malloc(101);
+ f->ebuf=f->bufp+100;
+ for(s=f->bufp;s<=f->ebuf;s++)
+ *s='\0';
+ return f;
+}
+
+/*
+ * Open a corebuffer to read. EOF occurs after reading len
+ * characters from buf.
+ */
+Io *
+opencore(char *s, int len)
+{
+ Io *f;
+ char *buf;
+
+ f = new(Io);
+ buf = malloc(len);
+ f->fd = -1;
+ f->bufp = f->strp=buf;
+ f->ebuf = buf+len;
+ memmove(buf, s, len);
+
+ return f;
+}
+
+void
+rewind(Io *io)
+{
+ if(io->fd==-1) {
+ io->bufp = io->strp;
+ } else {
+ io->bufp = io->ebuf = io->buf;
+ seek(io->fd, 0L, 0);
+ }
+}
+
+void
+closeio(Io *io)
+{
+ if(io->fd>=0)
+ close(io->fd);
+ if(io->strp)
+ free(io->strp);
+ free(io);
+}
+
+int
+emptybuf(Io *f)
+{
+ int n;
+ if(f->fd==-1 || (n=read(f->fd, f->buf, NBUF))<=0) return EOF;
+ f->bufp=f->buf;
+ f->ebuf=f->buf+n;
+ return *f->bufp++&0xff;
+}
diff --git a/utils/rcsh/lex.c b/utils/rcsh/lex.c
new file mode 100644
index 00000000..d31a94d8
--- /dev/null
+++ b/utils/rcsh/lex.c
@@ -0,0 +1,398 @@
+#include "rc.h"
+#include "y.tab.h"
+
+#define NTOK 8192
+
+int getnext(void);
+
+int future=EOF;
+int doprompt=1;
+int inquote;
+int nerror;
+char *promptstr;
+
+char tok[NTOK];
+
+int lastdol; /* was the last token read '$' or '$#' or '"'? */
+int lastword; /* was the last token read a word or compound word terminator? */
+int lastc;
+
+void
+kinit(void)
+{
+ kenter(FOR, "for");
+ kenter(IN, "in");
+ kenter(WHILE, "while");
+ kenter(IF, "if");
+ kenter(NOT, "not");
+ kenter(TWIDDLE, "~");
+ kenter(BANG, "!");
+ kenter(SUBSHELL, "@");
+ kenter(SWITCH, "switch");
+ kenter(FN, "fn");
+}
+
+int
+wordchr(int c)
+{
+ return !strchr("\n \t\r#;&|^$=`'{}()<>", c) && c!=EOF;
+}
+
+int
+idchr(int c)
+{
+ /*
+ * Formerly:
+ * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
+ * || c=='_' || c=='*';
+ */
+ return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
+}
+
+/*
+ * Look ahead in the input stream
+ */
+int
+nextc(void)
+{
+ if(future==EOF)
+ future=getnext();
+ return future;
+}
+
+/*
+ * Consume the lookahead character.
+ */
+int
+advance(void)
+{
+ int c=nextc();
+ lastc=future;
+ future=EOF;
+ return c;
+}
+
+/*
+ * read a character from the input stream
+ */
+int
+getnext(void)
+{
+ register int c;
+ static peekc=EOF;
+ if(peekc!=EOF){
+ c=peekc;
+ peekc=EOF;
+ return c;
+ }
+ if(runq->eof) return EOF;
+ if(doprompt)
+ pprompt();
+ c=rchr(runq->cmdfd);
+ if(!inquote && c=='\\'){
+ c=rchr(runq->cmdfd);
+ if(c=='\n'){
+ doprompt=1;
+ c=' ';
+ }
+ else{
+ peekc=c;
+ c='\\';
+ }
+ }
+ doprompt=doprompt || c=='\n' || c==EOF;
+ if(c==EOF) runq->eof++;
+ else if(flag['V'] || ndot>=2 && flag['v'])
+ pchr(err, c);
+ return c;
+}
+
+void
+pprompt(void)
+{
+ Var *prompt;
+
+ if(runq->iflag){
+ pstr(err, promptstr);
+ flush(err);
+ prompt=vlook("prompt");
+ if(prompt->val && prompt->val->next)
+ promptstr=prompt->val->next->word;
+ else
+ promptstr="\t";
+ }
+ runq->lineno++;
+ doprompt=0;
+}
+
+void
+skipwhite(void)
+{
+ int c;
+ for(;;){
+ c=nextc();
+ if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */
+ for(;;){
+ c=nextc();
+ if(c=='\n' || c==EOF) break;
+ advance();
+ }
+ }
+ if(c==' ' || c=='\t' || c=='\r') advance();
+ else return;
+ }
+}
+
+void
+skipnl(void)
+{
+ int c;
+ for(;;){
+ skipwhite();
+ c=nextc();
+ if(c!='\n') return;
+ advance();
+ }
+}
+
+int
+nextis(int c)
+{
+ if(nextc()==c){
+ advance();
+ return 1;
+ }
+ return 0;
+}
+
+char *
+addtok(char *p, int val)
+{
+ if(p==0) return 0;
+ if(p==&tok[NTOK]){
+ *p=0;
+ yyerror("token buffer too short");
+ return 0;
+ }
+ *p++=val;
+ return p;
+}
+
+char *
+addutf(char *p, int c)
+{
+ p=addtok(p, c);
+ if(twobyte(c)) /* 2-byte escape */
+ return addtok(p, advance());
+ if(threebyte(c)){ /* 3-byte escape */
+ p=addtok(p, advance());
+ return addtok(p, advance());
+ }
+ return p;
+}
+
+int
+yylex(void)
+{
+ int c, d=nextc();
+ char *w=tok;
+ Tree *t;
+
+ yylval.tree=0;
+ /*
+ * Embarassing sneakiness: if the last token read was a quoted or unquoted
+ * WORD then we alter the meaning of what follows. If the next character
+ * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise,
+ * if the next character is the first character of a simple or compound word,
+ * we insert a `^' before it.
+ */
+ if(lastword){
+ lastword=0;
+ if(d=='('){
+ advance();
+ strcpy(tok, "( [SUB]");
+ return SUB;
+ }
+ if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
+ strcpy(tok, "^");
+ return '^';
+ }
+ }
+ inquote=0;
+ skipwhite();
+ switch(c=advance()){
+ case EOF:
+ lastdol=0;
+ strcpy(tok, "EOF");
+ return EOF;
+ case '$':
+ lastdol=1;
+ if(nextis('#')){
+ strcpy(tok, "$#");
+ return COUNT;
+ }
+ if(nextis('"')){
+ strcpy(tok, "$\"");
+ return '"';
+ }
+ strcpy(tok, "$");
+ return '$';
+ case '&':
+ lastdol=0;
+ if(nextis('&')){
+ skipnl();
+ strcpy(tok, "&&");
+ return ANDAND;
+ }
+ strcpy(tok, "&");
+ return '&';
+ case '|':
+ lastdol=0;
+ if(nextis(c)){
+ skipnl();
+ strcpy(tok, "||");
+ return OROR;
+ }
+ case '<':
+ case '>':
+ lastdol=0;
+ /*
+ * funny redirection tokens:
+ * redir: arrow | arrow '[' fd ']'
+ * arrow: '<' | '<<' | '>' | '>>' | '|'
+ * fd: digit | digit '=' | digit '=' digit
+ * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
+ * some possibilities are nonsensical and get a message.
+ */
+ *w++=c;
+ t=newtree();
+ switch(c){
+ case '|':
+ t->type=PIPE;
+ t->fd0=1;
+ t->fd1=0;
+ break;
+ case '>':
+ t->type=REDIR;
+ if(nextis(c)){
+ t->rtype=APPEND;
+ *w++=c;
+ }
+ else t->rtype=WRITE;
+ t->fd0=1;
+ break;
+ case '<':
+ t->type=REDIR;
+ if(nextis(c)){
+ t->rtype=HERE;
+ *w++=c;
+ }
+ else t->rtype=READ;
+ t->fd0=0;
+ break;
+ }
+ if(nextis('[')){
+ *w++='[';
+ c=advance();
+ *w++=c;
+ if(c<'0' || '9'<c){
+ RedirErr:
+ *w=0;
+ yyerror(t->type==PIPE?"pipe syntax"
+ :"redirection syntax");
+ return EOF;
+ }
+ t->fd0=0;
+ do{
+ t->fd0=t->fd0*10+c-'0';
+ *w++=c;
+ c=advance();
+ }while('0'<=c && c<='9');
+ if(c=='='){
+ *w++='=';
+ if(t->type==REDIR)
+ t->type=DUP;
+ c=advance();
+ if('0'<=c && c<='9'){
+ t->rtype=DUPFD;
+ t->fd1=t->fd0;
+ t->fd0=0;
+ do{
+ t->fd0=t->fd0*10+c-'0';
+ *w++=c;
+ c=advance();
+ }while('0'<=c && c<='9');
+ }
+ else{
+ if(t->type==PIPE) goto RedirErr;
+ t->rtype=CLOSE;
+ }
+ }
+ if(c!=']' || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
+ goto RedirErr;
+ *w++=']';
+ }
+ *w='\0';
+ yylval.tree=t;
+ if(t->type==PIPE) skipnl();
+ return t->type;
+ case '\'':
+ lastdol=0;
+ lastword=1;
+ inquote=1;
+ for(;;){
+ c=advance();
+ if(c==EOF) break;
+ if(c=='\''){
+ if(nextc()!='\'')
+ break;
+ advance();
+ }
+ w=addutf(w, c);
+ }
+ if(w!=0) *w='\0';
+ t=token(tok, WORD);
+ t->quoted=1;
+ yylval.tree=t;
+ return t->type;
+ }
+ if(!wordchr(c)){
+ lastdol=0;
+ tok[0]=c;
+ tok[1]='\0';
+ return c;
+ }
+ for(;;){
+ /* next line should have (char)c==GLOB, but ken's compiler is broken */
+ if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
+ w=addtok(w, GLOB);
+ w=addutf(w, c);
+ c=nextc();
+ if(lastdol?!idchr(c):!wordchr(c)) break;
+ advance();
+ }
+Out:
+ lastword=1;
+ lastdol=0;
+ if(w!=0) *w='\0';
+ t=klook(tok);
+ if(t->type!=WORD) lastword=0;
+ t->quoted=0;
+ yylval.tree=t;
+ return t->type;
+}
+
+void
+yyerror(char *m)
+{
+ pfmt(err, "rc: ");
+ if(runq->cmdfile) pfmt(err, "file %s: ", runq->cmdfile);
+ if(!runq->iflag) pfmt(err, "line %d: ", runq->lineno);
+ if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok);
+ pfmt(err, "%s\n", m);
+ flush(err);
+ lastword=0;
+ lastdol=0;
+ while(lastc!='\n' && lastc!=EOF) advance();
+ nerror++;
+}
diff --git a/utils/rcsh/main.c b/utils/rcsh/main.c
new file mode 100644
index 00000000..93cd2951
--- /dev/null
+++ b/utils/rcsh/main.c
@@ -0,0 +1,228 @@
+#include "rc.h"
+
+int flag[256];
+Io *err;
+char *argv0;
+
+Thread *runq;
+int ndot;
+
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ Code bootstrap[17];
+ char *cflag, *cp;
+ char rcmain[200];
+ Var *infroot;
+ char **p;
+
+ cflag = 0;
+
+ /* default to interactive mode */
+ flag['i']++;
+
+ /* hack for DOS-style options, when rcsh started from MS-land */
+ for (p = argv+1; *p && **p == '/'; p++)
+ **p = '-';
+
+ argv0 = *argv;
+ ARGBEGIN{
+ default:
+ fprint(2, "usage: %s: [-seiIlvxr] [-c string] [file [args]]\n", argv0);
+ exits("usage");
+ case 'e': flag['e']++; break;
+ case 'c': cflag = ARGF(); break;
+ case 'i': flag['i']++; break;
+ case 'I': flag['i'] = 0; break;
+ case 'l': flag['l']++; break;
+ case 'r': flag['r']++; break;
+ case 's': flag['s']++; break;
+ case 'S': flag['S']++; break; /* sub shell */
+ case 'v': flag['v']++; break;
+ case 'V': flag['V']++; break;
+ case 'x': flag['x']++; break;
+ }ARGEND
+
+ err = openfd(2);
+
+ kinit();
+ vinit();
+
+ cp = ROOT;
+ if(0 && strlen(argv0))
+ sprint(rcmain, "%s/../lib/rcmain", argv0);
+ else{
+ infroot = vlook("ROOT");
+ if(infroot->val)
+ cp = infroot->val->word;
+ }
+ sprint(rcmain, "%s/utils/lib/rcmain", cp);
+
+ setvar("rcname", newword(argv0, 0));
+ if(cflag)
+ setvar("cflag", newword(cflag, 0));
+ else
+ setvar("cflag", 0);
+
+ /* bootstrap == . rcmain $* */
+ i=0;
+ bootstrap[i++].i=1;
+ bootstrap[i++].f=Xmark;
+ bootstrap[i++].f=Xword;
+ bootstrap[i++].s="*";
+ bootstrap[i++].f=Xassign;
+ bootstrap[i++].f=Xmark;
+ bootstrap[i++].f=Xmark;
+ bootstrap[i++].f=Xword;
+ bootstrap[i++].s="*";
+ bootstrap[i++].f=Xdol;
+ bootstrap[i++].f=Xword;
+ bootstrap[i++].s=rcmain;
+ bootstrap[i++].f=Xword;
+ bootstrap[i++].s=".";
+ bootstrap[i++].f=Xsimple;
+ bootstrap[i++].f=Xexit;
+ bootstrap[i].i=0;
+ start(bootstrap, 1, 0);
+ pushlist();
+ for(i=argc-1;i>=0;i--)
+ pushword(argv[i]);
+
+ for(;;){
+ if(flag['r']) pfnc(err, runq);
+ runq->pc++;
+ (*runq->code[runq->pc-1].f)();
+ if(ntrap.ref)
+ dotrap();
+ }
+}
+
+void
+panic(char *s, int n)
+{
+ pfmt(err, "rc: ");
+ pfmt(err, s, n);
+ pchr(err, '\n');
+ flush(err);
+ pfmt(err, "aborting\n");
+ flush(err);
+ exits("aborting");
+}
+
+void
+setstatus(char *s)
+{
+ setvar("status", newword(s, 0));
+}
+
+char *
+getstatus(void)
+{
+ Var *status=vlook("status");
+
+ return status->val?status->val->word:"";
+}
+
+int
+truestatus(void)
+{
+ char *s;
+ for(s=getstatus();*s;s++)
+ if(*s!='|' && *s!='0') return 0;
+ return 1;
+}
+
+char *
+concstatus(char *s, char *t)
+{
+ static char v[NSTATUS+1];
+ int n=strlen(s);
+ strncpy(v, s, NSTATUS);
+ if(n<NSTATUS){
+ v[n]='|';
+ strncpy(v+n+1, t, NSTATUS-n-1);
+ }
+ v[NSTATUS]='\0';
+ return v;
+}
+
+/*
+ * Start executing the given code at the given pc with the given redirection
+ */
+void
+start(Code *c, int pc, Var *local)
+{
+ Thread *p = new(Thread);
+
+ memset(p, 0, sizeof(Thread));
+ p->code = codecopy(c);
+ p->pc = pc;
+ if(runq) {
+ p->redir = runq->redir;
+ p->startredir = runq->redir;
+ }
+ p->local = local;
+ p->lineno = 1;
+ p->ret = runq;
+ runq=p;
+}
+
+void
+execcmds(Io *f)
+{
+ static Code rdcmds[4];
+ static int first=1;
+
+ if(first){
+ rdcmds[0].i=1;
+ rdcmds[1].f=Xrdcmds;
+ rdcmds[2].f=Xreturn;
+ first=0;
+ }
+ start(rdcmds, 1, runq->local);
+ runq->cmdfd=f;
+ runq->iflast=0;
+}
+
+void
+waitfor(uint pid)
+{
+ int e;
+ char estr[64];
+
+ e = procwait(pid);
+ if(e != 0) {
+ sprint(estr, "error code %d", e);
+ setstatus(estr);
+ } else
+ setstatus("");
+}
+
+char **
+procargv(char *s0, char *s1, char *s2, char *s3, Word *w)
+{
+ int n, i;
+ Word *p;
+ char **argv;
+
+ for(p=w,n=5; p; p=p->next,n++);
+ ;
+
+ argv = malloc(n*sizeof(char*));
+ i = 0;
+ if(s0)
+ argv[i++] = s0;
+ if(s1)
+ argv[i++] = s1;
+ if(s2)
+ argv[i++] = s2;
+ if(s3)
+ argv[i++] = s3;
+ for(p=w; p; p=p->next)
+ argv[i++] = p->word;
+ argv[i] = 0;
+ return argv;
+}
+
diff --git a/utils/rcsh/mkfile b/utils/rcsh/mkfile
new file mode 100644
index 00000000..b4c818cf
--- /dev/null
+++ b/utils/rcsh/mkfile
@@ -0,0 +1,53 @@
+<../../mkconfig
+
+#
+# this directory contains a stripped-down version of rc
+# it is only build for Windows Nt and Windows 95
+
+TARG=rcsh
+
+OFILES= code.$O\
+ exec.$O\
+ glob.$O\
+ here.$O\
+ io.$O\
+ lex.$O\
+ main.$O\
+ $TARGMODEL.$O\
+ pcmd.$O\
+ pfnc.$O\
+ simple.$O\
+ trap.$O\
+ tree.$O\
+ var.$O\
+ word.$O\
+ y.tab.$O\
+
+HFILES= rc.h\
+ y.tab.h\
+
+YFILES= syn.y
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS '-DROOT="'$ROOT'"'
+
+$BIN/%:Q: $O.out
+ echo $TARG must be installed manually on Windows systems
+ echo use: cp $O.out $target
+ cp $O.out $target
+
+install:V: $ROOT/utils/lib/rcmain
+
+$ROOT/utils/lib/rcmain:Q: rcmain
+ echo $prereq must be installed manually on Windows systems
+ echo use: cp $prereq $target
+ cp $prereq $target
+
+Posix.c Inferno.c:QV:
+ echo $TARG is only built on Windows NT or Windows 95
+ exit 1
diff --git a/utils/rcsh/pcmd.c b/utils/rcsh/pcmd.c
new file mode 100644
index 00000000..9c5eb8a6
--- /dev/null
+++ b/utils/rcsh/pcmd.c
@@ -0,0 +1,110 @@
+#include "rc.h"
+#include "y.tab.h"
+
+char nl='\n'; /* change to semicolon for bourne-proofing */
+
+#define c0 t->child[0]
+#define c1 t->child[1]
+#define c2 t->child[2]
+
+void
+pdeglob(Io *f, char *s)
+{
+ while(*s){
+ if(*s==GLOB) s++;
+ pchr(f, *s++);
+ }
+}
+
+void
+pcmd(Io *f, Tree *t)
+{
+ if(t==0)
+ return;
+
+ switch(t->type){
+ default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break;
+ case '$': pfmt(f, "$%t", c0); break;
+ case '"': pfmt(f, "$\"%t", c0); break;
+ case '&': pfmt(f, "%t&", c0); break;
+ case '^': pfmt(f, "%t^%t", c0, c1); break;
+ case '`': pfmt(f, "`%t", c0); break;
+ case ANDAND: pfmt(f, "%t && %t", c0, c1); break;
+ case ARGLIST: pfmt(f, "%t %t", c0, c1); break;
+ case BANG: pfmt(f, "! %t", c0); break;
+ case BRACE: pfmt(f, "{%t}", c0); break;
+ case COUNT: pfmt(f, "$#%t", c0); break;
+ case FN: pfmt(f, "fn %t %t", c0, c1); break;
+ case IF: pfmt(f, "if%t%t", c0, c1); break;
+ case NOT: pfmt(f, "if not %t", c0); break;
+ case OROR: pfmt(f, "%t || %t", c0, c1); break;
+ case PCMD:
+ case PAREN: pfmt(f, "(%t)", c0); break;
+ case SUB: pfmt(f, "$%t(%t)", c0, c1); break;
+ case SIMPLE: pfmt(f, "%t", c0); break;
+ case SUBSHELL: pfmt(f, "@ %t", c0); break;
+ case SWITCH: pfmt(f, "switch %t %t", c0, c1); break;
+ case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); break;
+ case WHILE: pfmt(f, "while %t%t", c0, c1); break;
+ case ';':
+ if(c0){
+ if(c1) pfmt(f, "%t%c%t", c0, nl, c1);
+ else pfmt(f, "%t", c0);
+ }
+ else pfmt(f, "%t", c1);
+ break;
+ case WORDS:
+ if(c0) pfmt(f, "%t ", c0);
+ pfmt(f, "%t", c1);
+ break;
+ case FOR:
+ pfmt(f, "for(%t", c0);
+ if(c1) pfmt(f, " in %t", c1);
+ pfmt(f, ")%t", c2);
+ break;
+ case WORD:
+ if(t->quoted) pfmt(f, "%Q", t->str);
+ else pdeglob(f, t->str);
+ break;
+ case DUP:
+ pfmt(f, ">[%d=", t->fd0);
+ if(t->rtype==DUPFD)
+ pfmt(f, "%d", t->fd1);
+ /* else t->rtype == CLOSE */
+ pchr(f, ']');
+ break;
+ case PIPEFD:
+ case REDIR:
+ switch(t->rtype){
+ case HERE:
+ pchr(f, '<');
+ case READ:
+ pchr(f, '<');
+ if(t->fd0!=0)
+ pfmt(f, "[%d]", t->fd0);
+ break;
+ case APPEND:
+ pchr(f, '>');
+ case WRITE:
+ pchr(f, '>');
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
+ break;
+ }
+ pfmt(f, "%t", c0);
+ if(c1) pfmt(f, " %t", c1);
+ break;
+ case '=':
+ pfmt(f, "%t=%t", c0, c1);
+ if(c2) pfmt(f, " %t", c2);
+ break;
+ case PIPE:
+ pfmt(f, "%t|", c0);
+ if(t->fd1==0){
+ if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+ }
+ else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
+ pfmt(f, "%t", c1);
+ break;
+ }
+}
diff --git a/utils/rcsh/pfnc.c b/utils/rcsh/pfnc.c
new file mode 100644
index 00000000..4116b087
--- /dev/null
+++ b/utils/rcsh/pfnc.c
@@ -0,0 +1,70 @@
+#include "rc.h"
+
+struct{
+ void (*f)(void);
+ char *name;
+}fname[]={
+ Xappend, "Xappend",
+ Xasync, "Xasync",
+ Xbang, "Xbang",
+ Xclose, "Xclose",
+ Xdup, "Xdup",
+ Xeflag, "Xeflag",
+ Xexit, "Xexit",
+ Xfalse, "Xfalse",
+ Xifnot, "Xifnot",
+ Xjump, "Xjump",
+ Xmark, "Xmark",
+ Xpopm, "Xpopm",
+ Xread, "Xread",
+ Xreturn, "Xreturn",
+ Xtrue, "Xtrue",
+ Xif, "Xif",
+ Xwastrue, "Xwastrue",
+ Xword, "Xword",
+ Xwrite, "Xwrite",
+ Xmatch, "Xmatch",
+ Xcase, "Xcase",
+ Xconc, "Xconc",
+ Xassign, "Xassign",
+ Xdol, "Xdol",
+ Xcount, "Xcount",
+ Xlocal, "Xlocal",
+ Xunlocal, "Xunlocal",
+ Xfn, "Xfn",
+ Xdelfn, "Xdelfn",
+ Xpipe, "Xpipe",
+ Xpipewait, "Xpipewait",
+ Xrdcmds, "Xrdcmds",
+ Xbackq, "Xbackq",
+ Xpipefd, "Xpipefd",
+ Xsubshell, "Xsubshell",
+ Xdelhere, "Xdelhere",
+ Xfor, "Xfor",
+ Xglob, "Xglob",
+ Xsimple, "Xsimple",
+ Xqdol, "Xqdol",
+ 0
+};
+
+void
+pfnc(Io *fd, Thread *t)
+{
+ int i;
+ void (*fn)(void)=t->code[t->pc].f;
+ List *a;
+
+ pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
+ for(i=0;fname[i].f;i++) {
+ if(fname[i].f==fn) {
+ pstr(fd, fname[i].name);
+ break;
+ }
+ }
+ if(!fname[i].f)
+ pfmt(fd, "%p", fn);
+ for(a=t->argv;a;a=a->next)
+ pfmt(fd, " (%v)", a->words);
+ pchr(fd, '\n');
+ flush(fd);
+}
diff --git a/utils/rcsh/rc.h b/utils/rcsh/rc.h
new file mode 100644
index 00000000..f7d56746
--- /dev/null
+++ b/utils/rcsh/rc.h
@@ -0,0 +1,295 @@
+#include <lib9.h>
+
+#define Lock Rclock
+#define Ref Rcref
+
+typedef union Code Code;
+typedef struct Tree Tree;
+typedef struct Thread Thread;
+typedef struct Word Word;
+typedef struct Var Var;
+typedef struct List List;
+typedef struct Redir Redir;
+typedef struct Io Io;
+typedef struct Here Here;
+typedef struct Ref Ref;
+typedef struct Lock Lock;
+typedef struct Direntry Direntry;
+
+#define EOF (-1)
+#define NBUF 512
+
+/* values for Tree->rtype */
+#define APPEND 1
+#define WRITE 2
+#define READ 3
+#define HERE 4
+#define DUPFD 5
+#define CLOSE 6
+
+/*
+ * redir types
+ */
+#define ROPEN 1 /* dup2(from, to); close(from); */
+#define RDUP 2 /* dup2(from, to); */
+#define RCLOSE 3 /* close(from); */
+
+#define NSTATUS 64 /* length of status (from plan 9) */
+
+#define IWS 0x01 /* inter word seperator when word lists are stored in env variables */
+
+/*
+ * Glob character escape in strings:
+ * In a string, GLOB must be followed by *?[ or GLOB.
+ * GLOB* matches any string
+ * GLOB? matches any single character
+ * GLOB[...] matches anything in the brackets
+ * GLOBGLOB matches GLOB
+ */
+#define GLOB ((char)0x02)
+
+/*
+ * The first word of any code vector is a reference count.
+ * Always create a new reference to a code vector by calling codecopy(.).
+ * Always call codefree(.) when deleting a reference.
+ */
+union Code {
+ void (*f)(void);
+ int i;
+ char *s;
+};
+
+
+struct Tree
+{
+ int type;
+ int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
+ char *str;
+ int quoted;
+ int iskw;
+ Tree *child[3];
+ Tree *next;
+};
+
+struct Thread
+{
+ Code *code; /* code for this thread */
+ int pc; /* code[pc] is the next instruction */
+ List *argv; /* argument stack */
+ Redir *redir; /* redirection stack */
+ Redir *startredir; /* redir inheritance point */
+ Var *local; /* list of local variables */
+ char *cmdfile; /* file name in Xrdcmd */
+ Io *cmdfd; /* file descriptor for Xrdcmd */
+ int iflast; /* static `if not' checking */
+ int eof; /* is cmdfd at eof? */
+ int iflag; /* interactive? */
+ int lineno; /* linenumber */
+ int pid; /* process for Xpipewait to wait for */
+ char status[NSTATUS]; /* status for Xpipewait */
+ Tree *treenodes; /* tree nodes created by this process */
+ Thread *ret; /* who continues when this finishes */
+};
+
+struct Io
+{
+ int fd;
+ char *bufp;
+ char *ebuf;
+ char *strp;
+ char buf[NBUF];
+};
+
+struct Var
+{
+ char *name; /* ascii name */
+ Word *val; /* value */
+ int changed;
+ Code *fn; /* pointer to function's code vector */
+ int fnchanged;
+ int pc; /* pc of start of function */
+ Var *next; /* next on hash or local list */
+};
+
+struct Word
+{
+ char *word;
+ Word *next;
+};
+
+struct List
+{
+ Word *words;
+ List *next;
+};
+
+struct Redir
+{
+ char type; /* what to do */
+ short from, to; /* what to do it to */
+ Redir *next; /* what else to do (reverse order) */
+};
+
+struct Here{
+ Tree *tag;
+ char *name;
+ Here *next;
+};
+
+struct Lock {
+ int val;
+};
+
+struct Ref
+{
+ Lock lk;
+ int ref;
+};
+
+struct Direntry
+{
+ int isdir;
+ char *name;
+};
+
+/* main.c */
+void start(Code *c, int pc, Var *local);
+
+/* lex.c */
+void yyerror(char*);
+int yylex(void);
+int yyparse(void);
+int wordchr(int);
+int idchr(int);
+
+/* code.c */
+int compile(Tree*);
+Code *codecopy(Code*);
+void codefree(Code*);
+void cleanhere(char *f);
+
+void skipnl(void);
+
+void panic(char*, int);
+
+/* var.c */
+void kinit(void);
+void vinit(void);
+Var *vlook(char*);
+Var *gvlook(char*);
+Var *newvar(char*, Var*);
+void setvar(char*, Word*);
+void updenv(void);
+void kenter(int type, char *name);
+
+/* glob.c */
+void deglob(char*);
+void globlist(void);
+int match(char *s, char *p, int stop);
+
+/* main.c */
+void setstatus(char *s);
+char *getstatus(void);
+int truestatus(void);
+void execcmds(Io*);
+char *concstatus(char *s, char *t);
+char **procargv(char*, char*, char*, char*, Word *w);
+
+void freewords(Word*);
+
+/* tree.c */
+Tree *newtree(void);
+Tree *token(char*, int), *klook(char*), *tree1(int, Tree*);
+Tree *tree2(int, Tree*, Tree*), *tree3(int, Tree*, Tree*, Tree*);
+Tree *mung1(Tree*, Tree*), *mung2(Tree*, Tree*, Tree*);
+Tree *mung3(Tree*, Tree*, Tree*, Tree*), *epimung(Tree*, Tree*);
+Tree *simplemung(Tree*), *heredoc(Tree*);
+void freetree(Tree*);
+void freenodes(void);
+
+/* here.c */
+Tree *heredoc(Tree *tag);
+
+/* exec.c */
+extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void);
+extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void);
+extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
+extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
+extern void Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
+extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
+extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
+extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void);
+extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
+extern void Xerror(char*), Xperror(char*);
+
+/* word.c */
+Word *newword(char*, Word*);
+void pushlist(void);
+void poplist(void);
+void pushword(char*);
+void popword(void);
+int count(Word*);
+Word *copywords(Word*, Word*);
+void pushredir(int, int, int);
+void turfredir(void);
+char *list2str(Word*);
+void freelist(Word*);
+Word *conclist(Word*, Word*, Word*);
+Word *subwords(Word*, int, Word*, Word*);
+
+/* io.c */
+#define pchr(b, c) if((b)->bufp==(b)->ebuf)fullbuf((b), (c));else (*(b)->bufp++=(c))
+#define rchr(b) ((b)->bufp==(b)->ebuf?emptybuf(b):(*(b)->bufp++&0xff))
+
+Io *openfd(int), *openstr(void), *opencore(char*, int);
+int emptybuf(Io*);
+void closeio(Io*);
+void flush(Io*);
+int fullbuf(Io*, int);
+
+void pfmt(Io*, char*, ...);
+void perr(Io*);
+void pstr(Io*, char*);
+void pfnc(Io*, Thread*);
+
+void pprompt(void);
+
+/* trap.c */
+void dotrap(void);
+void dointr(void);
+
+void waitfor(uint);
+
+/* nt.c */
+
+Direntry* readdirect(char*);
+void fatal(char*, ...);
+uint proc(char**, int, int, int);
+int procwait(uint);
+int refinc(Ref*);
+int refdec(Ref*);
+int pipe(int*);
+
+/*
+ * onebyte(c), twobyte(c), threebyte(c)
+ * Is c the first character of a one- two- or three-byte utf sequence?
+ */
+#define onebyte(c) ((c&0x80)==0x00)
+#define twobyte(c) ((c&0xe0)==0xc0)
+#define threebyte(c) ((c&0xf0)==0xe0)
+
+#define new(type) ((type *)malloc(sizeof(type)))
+
+
+extern Tree *cmdtree;
+extern Thread *runq;
+extern Io *err;
+extern int flag[256];
+extern int doprompt;
+extern char *promptstr;
+extern int ndot;
+extern int nerror;
+extern Code *codebuf;
+extern int eflagok;
+extern int interrupted;
+extern Ref ntrap;
diff --git a/utils/rcsh/rcmain b/utils/rcsh/rcmain
new file mode 100644
index 00000000..f74190ca
--- /dev/null
+++ b/utils/rcsh/rcmain
@@ -0,0 +1,29 @@
+# rcmain: 9pm version
+if(~ $#home 0) home=/
+if(~ $#ifs 0) ifs='
+'
+switch($#prompt){
+case 0
+case 1
+ prompt=('% ' ' ')
+}
+if(~ $rcname v.out) prompt=('broken! ' ' ')
+if(! ~ $#cflag 0){
+ if(flag l && test -r $home/lib/profile) . $home/lib/profile
+ status=''
+ eval $cflag
+}
+if not if(flag i){
+ if(flag l && test -r $home/lib/profile) . $home/lib/profile
+ status=''
+ if(! ~ $#* 0) . $*
+ if not . -i 'stdin$'
+}
+if not {
+ if(~ $#* 0) . 'stdin$'
+ if not{
+ status=''
+ . $*
+ }
+}
+exit $status
diff --git a/utils/rcsh/rcpath b/utils/rcsh/rcpath
new file mode 100644
index 00000000..cb19ff4f
--- /dev/null
+++ b/utils/rcsh/rcpath
@@ -0,0 +1,13 @@
+# rcmain: 9pm version
+PF='Program Files'
+MVS='Microsoft Visual Studio'
+PATH=D:/Users/Inferno/Nt/386/bin
+PATH=$PATH';'D:/apps/mks/mksnt
+PATH=$PATH';'C:/WINNT/system32
+PATH=$PATH';'C:/WINNT
+PATH=$PATH';'D:/$PF/$MVS/Common/Tools/WinNT
+PATH=$PATH';'D:/$PF/$MVS/Common/MSDev98/Bin
+PATH=$PATH';'D:/$PF/$MVS/Common/Tools
+PATH=$PATH';'D:/$PF/$MVS/VC98/bin
+PATH=$PATH';'D:/MSSQL7/BINN
+PATH=$PATH';'D:/$PF/Mts
diff --git a/utils/rcsh/simple.c b/utils/rcsh/simple.c
new file mode 100644
index 00000000..1c3a89b3
--- /dev/null
+++ b/utils/rcsh/simple.c
@@ -0,0 +1,528 @@
+#include "rc.h"
+
+typedef struct Builtin Builtin;
+
+struct Builtin
+{
+ char *name;
+ void (*fnc)(void);
+};
+
+int exitnext(void);
+void execexec(void);
+void execfunc(Var *func);
+void execcd(void);
+void execwhatis(void);
+void execeval(void);
+void execexit(void);
+void execshift(void);
+void execwait(void);
+void execdot(void);
+void execflag(void);
+
+Builtin builtin[]={
+ "cd", execcd,
+ "whatis", execwhatis,
+ "eval", execeval,
+ "exec", execexec, /* but with popword first */
+ "exit", execexit,
+ "shift", execshift,
+ "wait", execwait,
+ ".", execdot,
+ "flag", execflag,
+ 0
+};
+
+int mapfd(int fd);
+
+void
+Xsimple(void)
+{
+ Word *a;
+ Thread *p=runq;
+ Var *v;
+ Builtin *bp;
+ uint pid;
+ char **argv;
+
+ globlist();
+ a=runq->argv->words;
+ if(a==0){
+ Xerror("empty argument list");
+ return;
+ }
+ if(flag['x'])
+ pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
+
+ v=gvlook(a->word);
+ if(v->fn)
+ execfunc(v);
+ else{
+ if(strcmp(a->word, "builtin")==0){
+ if(count(a)==1){
+ pfmt(err, "builtin: empty argument list\n");
+ setstatus("empty arg list");
+ poplist();
+ return;
+ }
+ a=a->next;
+ popword();
+ }
+ for(bp=builtin;bp->name;bp++) {
+ if(strcmp(a->word, bp->name)==0){
+ (*bp->fnc)();
+ return;
+ }
+ }
+
+ updenv();
+ argv = procargv(0, 0, 0, 0, runq->argv->words);
+ pid = proc(argv, mapfd(0), mapfd(1), mapfd(2));
+ free(argv);
+
+ if(pid == 0)
+ pfmt(err, "%s: %r\n", runq->argv->words->word);
+ else
+ waitfor(pid);
+ poplist();
+#ifdef XXX
+ if(exitnext()){
+ /* fork and wait is redundant */
+ pushword("exec");
+ execexec();
+ Xexit();
+ }
+ else{
+ flush(err);
+ updenv();
+ switch(pid=fork()){
+ case -1:
+ Xperror("try again");
+ return;
+ case 0:
+ pushword("exec");
+ execexec();
+ Exit("can't exec");
+ default:
+ poplist();
+ /* interrupts don't get us out */
+ while(Waitfor(pid, 1) < 0)
+ ;
+ }
+ }
+#endif
+ }
+}
+
+Word nullpath={ "", 0};
+
+Word *
+searchpath(char *w)
+{
+ Word *path;
+
+ return &nullpath;
+
+ if(strncmp(w, "/", 1) == 0
+ || strncmp(w, "#", 1) == 0
+ || *w && w[1] == ':'
+ || strncmp(w, "./", 2) == 0
+ || strncmp(w, "../", 3) == 0
+ || (path=vlook("path")->val) == 0)
+ path=&nullpath;
+ return path;
+}
+
+/*
+ * Search through the following code to see if we're just going to exit.
+ */
+int
+exitnext(void)
+{
+ Code *c=&runq->code[runq->pc];
+
+ while(c->f==Xpopredir)
+ c++;
+ return c->f==Xexit;
+}
+
+#ifdef XXX
+
+void
+doredir(Redir *rp)
+{
+ if(rp){
+ doredir(rp->next);
+ switch(rp->type){
+ case ROPEN:
+ if(rp->from!=rp->to){
+ Dup(rp->from, rp->to);
+ close(rp->from);
+ }
+ break;
+ case RDUP: Dup(rp->from, rp->to); break;
+ case RCLOSE: close(rp->from); break;
+ }
+ }
+}
+
+
+#endif
+
+void
+execexec(void)
+{
+ popword(); /* "exec" */
+ if(runq->argv->words==0){
+ Xerror("empty argument list");
+ return;
+ }
+ fatal("execexec not done yet");
+/*
+ doredir(runq->redir);
+ Execute(runq->argv->words, searchpath(runq->argv->words->word));
+*/
+
+ poplist();
+}
+
+void
+execfunc(Var *func)
+{
+ Word *starval;
+
+ popword();
+ starval=runq->argv->words;
+ runq->argv->words=0;
+ poplist();
+ start(func->fn, func->pc, 0);
+ runq->local=newvar(strdup("*"), runq->local);
+ runq->local->val=starval;
+ runq->local->changed=1;
+}
+
+void
+execcd(void)
+{
+ Word *a=runq->argv->words;
+ Word *cdpath;
+ char dir[512];
+
+ setstatus("can't cd");
+ cdpath=vlook("cdpath")->val;
+ switch(count(a)){
+ default:
+ pfmt(err, "Usage: cd [directory]\n");
+ break;
+ case 2:
+ if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
+ for(;cdpath;cdpath=cdpath->next){
+ strcpy(dir, cdpath->word);
+ if(dir[0]) strcat(dir, "/");
+ strcat(dir, a->next->word);
+ if(chdir(dir)>=0){
+ if(strlen(cdpath->word)
+ && strcmp(cdpath->word, ".")!=0)
+ pfmt(err, "%s\n", dir);
+ setstatus("");
+ break;
+ }
+ }
+ if(cdpath==0) pfmt(err, "Can't cd %s\n", a->next->word);
+ break;
+ case 1:
+ a=vlook("home")->val;
+ if(count(a)>=1){
+ if(chdir(a->word)>=0)
+ setstatus("");
+ else
+ pfmt(err, "Can't cd %s\n", a->word);
+ }
+ else
+ pfmt(err, "Can't cd -- $home empty\n");
+ break;
+ }
+ poplist();
+}
+
+void
+execexit(void)
+{
+ switch(count(runq->argv->words)){
+ default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
+ case 2: setstatus(runq->argv->words->next->word);
+ case 1: Xexit();
+ }
+}
+
+void
+execflag(void)
+{
+ char *letter, *val;
+ switch(count(runq->argv->words)){
+ case 2:
+ setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
+ break;
+ case 3:
+ letter=runq->argv->words->next->word;
+ val=runq->argv->words->next->next->word;
+ if(strlen(letter)==1){
+ if(strcmp(val, "+")==0){
+ flag[letter[0]]=1;
+ break;
+ }
+ if(strcmp(val, "-")==0){
+ flag[letter[0]]=0;
+ break;
+ }
+ }
+ default:
+ Xerror("Usage: flag [letter] [+-]");
+ return;
+ }
+ poplist();
+}
+
+void
+execshift(void)
+{
+ int n;
+ Word *a;
+ Var *star;
+ switch(count(runq->argv->words)){
+ default:
+ pfmt(err, "Usage: shift [n]\n");
+ setstatus("shift usage");
+ poplist();
+ return;
+ case 2: n=atoi(runq->argv->words->next->word); break;
+ case 1: n=1; break;
+ }
+ star=vlook("*");
+ for(;n && star->val;--n){
+ a=star->val->next;
+ free(star->val->word);
+ free(star->val);
+ star->val=a;
+ star->changed=1;
+ }
+ setstatus("");
+ poplist();
+}
+
+int
+octal(char *s)
+{
+ int n=0;
+ while(*s==' ' || *s=='\t' || *s=='\n') s++;
+ while('0'<=*s && *s<='7') n=n*8+*s++-'0';
+ return n;
+}
+
+void
+execeval(void)
+{
+ char *cmdline, *s, *t;
+ int len=0;
+ Word *ap;
+
+ if(count(runq->argv->words)<=1){
+ Xerror("Usage: eval cmd ...");
+ return;
+ }
+ eflagok=1;
+ for(ap=runq->argv->words->next;ap;ap=ap->next)
+ len+=1+strlen(ap->word);
+ cmdline=malloc(len);
+ s=cmdline;
+ for(ap=runq->argv->words->next;ap;ap=ap->next){
+ for(t=ap->word;*t;) *s++=*t++;
+ *s++=' ';
+ }
+ s[-1]='\n';
+ poplist();
+ execcmds(opencore(cmdline, len));
+ free(cmdline);
+}
+
+void
+execdot(void)
+{
+ int iflag=0;
+ int fd;
+ List *av;
+ Thread *p=runq;
+ char *zero;
+ char file[512];
+ Word *path;
+ static int first=1;
+ static Code dotcmds[14];
+
+ if(first) {
+ dotcmds[0].i=1;
+ dotcmds[1].f=Xmark;
+ dotcmds[2].f=Xword;
+ dotcmds[3].s="0";
+ dotcmds[4].f=Xlocal;
+ dotcmds[5].f=Xmark;
+ dotcmds[6].f=Xword;
+ dotcmds[7].s="*";
+ dotcmds[8].f=Xlocal;
+ dotcmds[9].f=Xrdcmds;
+ dotcmds[10].f=Xunlocal;
+ dotcmds[11].f=Xunlocal;
+ dotcmds[12].f=Xreturn;
+ first=0;
+ } else
+ eflagok=1;
+ popword();
+ if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
+ iflag=1;
+ popword();
+ }
+ /* get input file */
+ if(p->argv->words==0){
+ Xerror("Usage: . [-i] file [arg ...]");
+ return;
+ }
+ zero=strdup(p->argv->words->word);
+ popword();
+ strcpy(file, "**No file name**");
+ fd = -1;
+ if(strcmp(zero, "stdin$") == 0)
+ fd = dup(0);
+ else{
+ for(path=searchpath(zero);path;path=path->next){
+ strcpy(file, path->word);
+ if(file[0])
+ strcat(file, "/");
+ strcat(file, zero);
+ if((fd=open(file, 0))>=0)
+ break;
+ }
+ }
+ if(fd<0){
+ Xperror(file);
+ return;
+ }
+ /* set up for a new command loop */
+ start(dotcmds, 1, 0);
+ pushredir(RCLOSE, fd, 0);
+ runq->cmdfile=zero;
+ runq->cmdfd=openfd(fd);
+ runq->iflag=iflag;
+ runq->iflast=0;
+ /* push $* value */
+ pushlist();
+ runq->argv->words=p->argv->words;
+ /* free caller's copy of $* */
+ av=p->argv;
+ p->argv=av->next;
+ free(av);
+ /* push $0 value */
+ pushlist();
+ pushword(zero);
+ ndot++;
+}
+
+void
+execwhatis(void)
+{ /* mildly wrong -- should fork before writing */
+ Word *a, *b, *path;
+ Var *v;
+ Builtin *bp;
+ char file[512];
+ Io out[1];
+ int found, sep;
+
+ a=runq->argv->words->next;
+ if(a==0){
+ Xerror("Usage: whatis name ...");
+ return;
+ }
+ setstatus("");
+ out->fd=mapfd(1);
+ out->bufp=out->buf;
+ out->ebuf=&out->buf[NBUF];
+ out->strp=0;
+ for(;a;a=a->next){
+ v=vlook(a->word);
+ if(v->val){
+ pfmt(out, "%s=", a->word);
+ if(v->val->next==0)
+ pfmt(out, "%q\n", v->val->word);
+ else{
+ sep='(';
+ for(b=v->val;b && b->word;b=b->next){
+ pfmt(out, "%c%q", sep, b->word);
+ sep=' ';
+ }
+ pfmt(out, ")\n");
+ }
+ found=1;
+ }
+ else
+ found=0;
+ v=gvlook(a->word);
+ if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
+ else{
+ for(bp=builtin;bp->name;bp++)
+ if(strcmp(a->word, bp->name)==0){
+ pfmt(out, "builtin %s\n", a->word);
+ break;
+ }
+ if(!bp->name){
+ for(path=searchpath(a->word);path;path=path->next){
+ strcpy(file, path->word);
+ if(file[0]) strcat(file, "/");
+ strcat(file, a->word);
+#ifdef XXX
+ if(Executable(file)){
+ pfmt(out, "%s\n", file);
+ break;
+ }
+#endif
+ }
+ if(!path && !found){
+ pfmt(err, "%s: not found\n", a->word);
+ setstatus("not found");
+ }
+ }
+ }
+ }
+ poplist();
+ flush(err);
+}
+
+void
+execwait(void)
+{
+ fprint(2, "wait: not done yet");
+
+#ifdef XXX
+ switch(count(runq->argv->words)){
+ default: Xerror("Usage: wait [pid]"); return;
+ case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
+ case 1: Waitfor(-1, 0); break;
+ }
+ poplist();
+#endif
+}
+
+int
+mapfd(int fd)
+{
+ Redir *rp;
+ for(rp=runq->redir;rp;rp=rp->next){
+ switch(rp->type){
+ case RCLOSE:
+ if(rp->from==fd) fd=-1;
+ break;
+ case RDUP:
+ case ROPEN:
+ if(rp->to==fd) fd=rp->from;
+ break;
+ }
+ }
+ return fd;
+}
diff --git a/utils/rcsh/syn.y b/utils/rcsh/syn.y
new file mode 100644
index 00000000..b0201ef0
--- /dev/null
+++ b/utils/rcsh/syn.y
@@ -0,0 +1,90 @@
+%{
+#include "rc.h"
+%}
+
+/* operator priorities -- lowest first */
+%left IF WHILE FOR SWITCH ')' NOT
+%left ANDAND OROR
+%left BANG SUBSHELL
+%left PIPE
+%left '^'
+%right '$' COUNT '"'
+%left SUB
+
+%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN
+%term WORD REDIR DUP PIPE SUB
+%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
+
+
+%union{
+ Tree *tree;
+};
+
+%type<tree> line paren brace body cmdsa cmdsan assign epilog redir
+%type<tree> cmd simple first word comword keyword words
+%type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN
+%type<tree> WORD REDIR DUP PIPE
+
+%%
+
+rc: { return 1;}
+| line '\n' {return !compile($1);}
+line: cmd
+| cmdsa line {$$=tree2(';', $1, $2);}
+body: cmd
+| cmdsan body {$$=tree2(';', $1, $2);}
+cmdsa: cmd ';'
+| cmd '&' {$$=tree1('&', $1);}
+cmdsan: cmdsa
+| cmd '\n'
+brace: '{' body '}' {$$=tree1(BRACE, $2);}
+paren: '(' body ')' {$$=tree1(PCMD, $2);}
+assign: first '=' word {$$=tree2('=', $1, $3);}
+epilog: {$$=0;}
+| redir epilog {$$=mung2($1, $1->child[0], $2);}
+redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
+| DUP
+cmd: {$$=0;}
+| brace epilog {$$=epimung($1, $2);}
+| IF paren {skipnl();} cmd
+ {$$=mung2($1, $2, $4);}
+| IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
+| FOR '(' word IN words ')' {skipnl();} cmd
+ {$$=mung3($1, $3, tree1(PAREN, $5), $8);}
+| FOR '(' word ')' {skipnl();} cmd
+ {$$=mung3($1, $3, 0, $6);}
+| WHILE paren {skipnl();} cmd
+ {$$=mung2($1, $2, $4);}
+| SWITCH word {skipnl();} brace
+ {$$=tree2(SWITCH, $2, $4);}
+| simple {$$=simplemung($1);}
+| TWIDDLE word words {$$=mung2($1, $2, $3);}
+| cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
+| cmd OROR cmd {$$=tree2(OROR, $1, $3);}
+| cmd PIPE cmd {$$=mung2($2, $1, $3);}
+| redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
+| assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
+| BANG cmd {$$=mung1($1, $2);}
+| SUBSHELL cmd {$$=mung1($1, $2);}
+| FN words brace {$$=tree2(FN, $2, $3);}
+| FN words {$$=tree1(FN, $2);}
+simple: first
+| simple word {$$=tree2(ARGLIST, $1, $2);}
+| simple redir {$$=tree2(ARGLIST, $1, $2);}
+first: comword
+| first '^' word {$$=tree2('^', $1, $3);}
+word: keyword {$1->type=WORD;}
+| comword
+| word '^' word {$$=tree2('^', $1, $3);}
+comword: '$' word {$$=tree1('$', $2);}
+| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
+| '"' word {$$=tree1('"', $2);}
+| COUNT word {$$=tree1(COUNT, $2);}
+| WORD
+| '`' brace {$$=tree1('`', $2);}
+| '(' words ')' {$$=tree1(PAREN, $2);}
+/* | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;} */
+
+keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
+words: {$$=0;}
+| words word {$$=tree2(WORDS, $1, $2);}
diff --git a/utils/rcsh/trap.c b/utils/rcsh/trap.c
new file mode 100644
index 00000000..7bae2cbc
--- /dev/null
+++ b/utils/rcsh/trap.c
@@ -0,0 +1,42 @@
+#include "rc.h"
+
+int interrupted;
+Ref ntrap;
+
+/* runs in a different thread */
+void
+dointr(void)
+{
+ refinc(&ntrap);
+ interrupted = 1;
+}
+
+void
+dotrap(void)
+{
+ Var *trapreq;
+ Word *starval;
+
+ while(refdec(&ntrap) >= 0) {
+ if(flag['S'])
+ exits(truestatus()?"":getstatus());
+ starval=vlook("*")->val;
+ trapreq=vlook("sysint");
+ if(trapreq->fn){
+ start(trapreq->fn, trapreq->pc, (Var*)0);
+ runq->local=newvar(strdup("*"), runq->local);
+ runq->local->val=copywords(starval, (Word*)0);
+ runq->local->changed=1;
+ runq->redir=runq->startredir=0;
+ } else {
+ /*
+ * run the stack down until we uncover the
+ * command reading loop. Xreturn will exit
+ * if there is none (i.e. if this is not
+ * an interactive rc.)
+ */
+ while(!runq->iflag)
+ Xreturn();
+ }
+ }
+}
diff --git a/utils/rcsh/tree.c b/utils/rcsh/tree.c
new file mode 100644
index 00000000..145f9c77
--- /dev/null
+++ b/utils/rcsh/tree.c
@@ -0,0 +1,140 @@
+#include "rc.h"
+#include "y.tab.h"
+
+Tree *Treenodes;
+
+/*
+ * create and clear a new Tree node, and add it
+ * to the node list.
+ */
+Tree *
+newtree(void)
+{
+ Tree *t=new(Tree);
+ t->iskw=0;
+ t->str=0;
+ t->child[0]=t->child[1]=t->child[2]=0;
+ t->next=Treenodes;
+ Treenodes=t;
+ return t;
+}
+
+void
+freenodes(void)
+{
+ Tree *t, *u;
+ for(t=Treenodes;t;t=u){
+ u=t->next;
+ if(t->str)
+ free(t->str);
+ free(t);
+ }
+ Treenodes=0;
+}
+
+Tree *
+tree1(int type, Tree *c0)
+{
+ return tree3(type, c0, 0, 0);
+}
+
+Tree *
+tree2(int type, Tree *c0, Tree *c1)
+{
+ return tree3(type, c0, c1, 0);
+}
+
+Tree *
+tree3(int type, Tree *c0, Tree *c1, Tree *c2)
+{
+ Tree *t;
+ if(type==';'){
+ if(c0==0) return c1;
+ if(c1==0) return c0;
+ }
+ t=newtree();
+ t->type=type;
+ t->child[0]=c0;
+ t->child[1]=c1;
+ t->child[2]=c2;
+ return t;
+}
+
+Tree *
+mung1(Tree *t, Tree *c0)
+{
+ t->child[0]=c0;
+ return t;
+}
+
+Tree *
+mung2(Tree *t, Tree *c0, Tree *c1)
+{
+ t->child[0]=c0;
+ t->child[1]=c1;
+ return t;
+}
+
+Tree *
+mung3(Tree *t, Tree *c0, Tree *c1, Tree *c2)
+{
+ t->child[0]=c0;
+ t->child[1]=c1;
+ t->child[2]=c2;
+ return t;
+}
+
+Tree *
+epimung(Tree *comp, Tree *epi)
+{
+ Tree *p;
+ if(epi==0) return comp;
+ for(p=epi;p->child[1];p=p->child[1]);
+ p->child[1]=comp;
+ return epi;
+}
+
+/*
+ * Add a SIMPLE node at the root of t and percolate all the redirections
+ * up to the root.
+ */
+Tree *
+simplemung(Tree *t)
+{
+ Tree *u;
+ Io *s;
+ t=tree1(SIMPLE, t);
+ s=openstr();
+ pfmt(s, "%t", t);
+ t->str=strdup(s->strp);
+ closeio(s);
+ for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){
+ if(u->child[1]->type==DUP
+ || u->child[1]->type==REDIR){
+ u->child[1]->child[1]=t;
+ t=u->child[1];
+ u->child[1]=0;
+ }
+ }
+ return t;
+}
+
+Tree *
+token(char *str, int type)
+{
+ Tree *t=newtree();
+ t->type=type;
+ t->str=strdup(str);
+ return t;
+}
+
+void
+freetree(Tree *p)
+{
+ if(p==0) return;
+ freetree(p->child[0]);
+ freetree(p->child[1]);
+ freetree(p->child[2]);
+ if(p->str) free(p->str);
+ free((char *)p);
+}
diff --git a/utils/rcsh/var.c b/utils/rcsh/var.c
new file mode 100644
index 00000000..cee8adf5
--- /dev/null
+++ b/utils/rcsh/var.c
@@ -0,0 +1,240 @@
+#include "rc.h"
+#include "y.tab.h"
+
+extern char **_environ;
+
+typedef struct Kw Kw;
+
+#define NKW 30
+#define NVAR 521
+
+struct Kw{
+ char *name;
+ int type;
+ Kw *next;
+};
+
+void updenvlocal(Var *v);
+void addenv(Var *v);
+
+Kw *kw[NKW];
+Var *gvar[NVAR];
+
+int
+hash(char *s, int n)
+{
+ int h=0, i=1;
+
+ while(*s)
+ h+=*s++*i++;
+ h%=n;
+ return h<0?h+n:h;
+}
+
+void
+kenter(int type, char *name)
+{
+ int h=hash(name, NKW);
+ Kw *p=new(Kw);
+ p->type=type;
+ p->name=name;
+ p->next=kw[h];
+ kw[h]=p;
+}
+
+void
+vinit(void)
+{
+ char **env, *name, *val, *p;
+ int i;
+ Word *w;
+ Io *f;
+ int n;
+ Var *v;
+
+ env = _environ;
+ for(i=0; env[i]; free(name), i++) {
+ name = strdup(env[i]);
+ p = strchr(name, '=');
+ if(p == 0 || p == name)
+ continue;
+ *p = 0;
+ val = p+1;
+ n = strlen(val);
+ if(n == 0)
+ continue;
+
+ if(strncmp(name, "fn#", 3)!=0) {
+ /* variable */
+ w = 0;
+ p = val+n-1;
+ while(*p) {
+ if(*p == IWS)
+ *p-- = 0;
+ for(; *p && *p != IWS; p--)
+ ;
+ w=newword(p+1, w);
+ }
+ setvar(name, w);
+ vlook(name)->changed=0;
+ } else {
+ /* function */
+ f = opencore(val, n);
+ execcmds(f);
+ }
+ }
+ v = vlook("path");
+ p = getenv("path");
+ if(v->val == 0 && p)
+ v->val = newword(p, 0);
+}
+
+
+Tree *
+klook(char *name)
+{
+ Kw *p;
+ Tree *t=token(name, WORD);
+ for(p=kw[hash(name, NKW)];p;p=p->next) {
+ if(strcmp(p->name, name)==0){
+ t->type=p->type;
+ t->iskw=1;
+ break;
+ }
+ }
+ return t;
+}
+
+Var *
+gvlook(char *name)
+{
+ int h=hash(name, NVAR);
+ Var *v;
+ for(v=gvar[h]; v; v=v->next)
+ if(strcmp(v->name, name)==0)
+ return v;
+
+ return gvar[h]=newvar(strdup(name), gvar[h]);
+}
+
+Var *
+vlook(char *name)
+{
+ Var *v;
+ if(runq)
+ for(v=runq->local; v; v=v->next)
+ if(strcmp(v->name, name)==0)
+ return v;
+ return gvlook(name);
+}
+
+void
+setvar(char *name, Word *val)
+{
+ Var *v=vlook(name);
+ freewords(v->val);
+ v->val=val;
+ v->changed=1;
+}
+
+Var *
+newvar(char *name, Var *next)
+{
+ Var *v=new(Var);
+ v->name=name;
+ v->val=0;
+ v->fn=0;
+ v->changed=0;
+ v->fnchanged=0;
+ v->next=next;
+ return v;
+}
+
+
+void
+execfinit(void)
+{
+}
+
+void
+updenv(void)
+{
+ Var *v, **h;
+
+ for(h=gvar;h!=&gvar[NVAR];h++)
+ for(v=*h;v;v=v->next)
+ addenv(v);
+
+ if(runq)
+ updenvlocal(runq->local);
+}
+
+static void
+envput(char *var, char *val)
+{
+ int i, n;
+ char *e;
+ char buf[256];
+
+ snprint(buf, sizeof(buf), "%s=%s", var, val);
+ n = strlen(var);
+ for(i = 0;;i++){
+ e = environ[i];
+ if(e == 0)
+ break;
+ if(strncmp(e, var, n) == 0){
+ free(e);
+ environ[i] = strdup(buf);
+ return;
+ }
+ }
+ environ = realloc(environ, (i+2)*sizeof(char*));
+ environ[i++] = strdup(buf);
+ environ[i] = 0;
+}
+
+void
+addenv(Var *v)
+{
+ char buf[100], *p;
+ Io *f;
+ Word *w;
+ int i, n;
+
+ if(v->changed){
+ v->changed=0;
+ p = 0;
+ n = 0;
+ if(v->val) {
+ for(w=v->val; w; w=w->next) {
+ i = strlen(w->word);
+ p = realloc(p, n+i+1);
+ memmove(p+n, w->word, i);
+ n+=i;
+ p[n++] = IWS;
+ }
+ p[n-1] = 0;
+ envput(v->name, p);
+ } else
+ envput(v->name, "");
+ free(p);
+ }
+
+ if(v->fnchanged){
+ v->fnchanged=0;
+ snprint(buf, sizeof(buf), "fn#%s", v->name);
+ f = openstr();
+ pfmt(f, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
+ envput(buf, f->strp);
+ closeio(f);
+ }
+}
+
+void
+updenvlocal(Var *v)
+{
+ if(v){
+ updenvlocal(v->next);
+ addenv(v);
+ }
+}
diff --git a/utils/rcsh/word.c b/utils/rcsh/word.c
new file mode 100644
index 00000000..7cbab88e
--- /dev/null
+++ b/utils/rcsh/word.c
@@ -0,0 +1,173 @@
+#include "rc.h"
+
+Word *
+newword(char *wd, Word *next)
+{
+ Word *p=new(Word);
+ p->word=strdup(wd);
+ p->next=next;
+ return p;
+}
+
+void
+pushword(char *wd)
+{
+ if(runq->argv==0)
+ panic("pushword but no argv!", 0);
+ runq->argv->words=newword(wd, runq->argv->words);
+}
+
+void
+popword(void)
+{
+ Word *p;
+
+ if(runq->argv==0)
+ panic("popword but no argv!", 0);
+ p=runq->argv->words;
+ if(p==0)
+ panic("popword but no word!", 0);
+ runq->argv->words=p->next;
+ free(p->word);
+ free(p);
+}
+
+void
+freewords(Word *w)
+{
+ Word *nw;
+ while(w){
+ free(w->word);
+ nw=w->next;
+ free(w);
+ w=nw;
+ }
+}
+
+void
+freelist(Word *w)
+{
+ Word *nw;
+ while(w){
+ nw=w->next;
+ free(w->word);
+ free(w);
+ w=nw;
+ }
+}
+
+void
+pushlist(void)
+{
+ List *p=new(List);
+ p->next=runq->argv;
+ p->words=0;
+ runq->argv=p;
+}
+
+void
+poplist(void)
+{
+ List *p=runq->argv;
+ if(p==0)
+ panic("poplist but no argv", 0);
+ freelist(p->words);
+ runq->argv=p->next;
+ free(p);
+}
+
+int
+count(Word *w)
+{
+ int n;
+ for(n=0;w;n++)
+ w=w->next;
+ return n;
+}
+
+/*
+ * copy arglist a, adding the copy to the front of tail
+ */
+Word *
+copywords(Word *a, Word *tail)
+{
+ Word *v=0, **end;
+ for(end=&v;a;a=a->next,end=&(*end)->next)
+ *end=newword(a->word, 0);
+ *end=tail;
+ return v;
+}
+
+char *
+list2str(Word *words)
+{
+ char *value, *s, *t;
+ int len=0;
+ Word *ap;
+
+ for(ap=words;ap;ap=ap->next)
+ len+=1+strlen(ap->word);
+ value=malloc(len+1);
+ s=value;
+ for(ap=words;ap;ap=ap->next){
+ for(t=ap->word;*t;) *s++=*t++;
+ *s++=' ';
+ }
+ if(s==value)
+ *s='\0';
+ else
+ s[-1]='\0';
+ return value;
+}
+
+Word *
+subwords(Word *val, int len, Word *sub, Word *a)
+{
+ int n;
+ char *s;
+
+ if(!sub) return a;
+ a=subwords(val, len, sub->next, a);
+ s=sub->word;
+ deglob(s);
+ n=0;
+ while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
+ if(n<1 || len<n) return a;
+ for(;n!=1;--n) val=val->next;
+ return newword(val->word, a);
+}
+
+
+void
+pushredir(int type, int from, int to)
+{
+ Redir *rp=new(Redir);
+ rp->type=type;
+ rp->from=from;
+ rp->to=to;
+ rp->next=runq->redir;
+ runq->redir=rp;
+}
+
+void
+turfredir(void)
+{
+ while(runq->redir!=runq->startredir)
+ Xpopredir();
+}
+
+Word*
+conclist(Word *lp, Word *rp, Word *tail)
+{
+ char *buf;
+ Word *v;
+ if(lp->next || rp->next)
+ tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
+ tail);
+ buf=malloc(strlen(lp->word)+strlen(rp->word)+1);
+ strcpy(buf, lp->word);
+ strcat(buf, rp->word);
+ v=newword(buf, tail);
+ free(buf);
+ return v;
+}
diff --git a/utils/rm/mkfile b/utils/rm/mkfile
new file mode 100644
index 00000000..0051452b
--- /dev/null
+++ b/utils/rm/mkfile
@@ -0,0 +1,24 @@
+<../../mkconfig
+
+#
+# the rm command is only needed on Windows NT and Windows 95
+#
+
+TARG=rm
+
+OFILES= rm-$TARGMODEL.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+rm-Posix.c rm-Inferno.c:QV:
+ echo 'rm is only built on Windows NT or Windows 95'
+ exit 1
+
+$BIN/rm.exe: $O.out
+ rm -f $target && cp $prereq $target
diff --git a/utils/rm/rm-Nt.c b/utils/rm/rm-Nt.c
new file mode 100644
index 00000000..9c666213
--- /dev/null
+++ b/utils/rm/rm-Nt.c
@@ -0,0 +1,151 @@
+#include <lib9.h>
+#include <windows.h>
+
+typedef struct Direntry
+{
+ int isdir;
+ char *name;
+} Direntry;
+
+char errbuf[ERRMAX];
+long ndirbuf = 0;
+int ignerr = 0;
+
+void
+err(char *f)
+{
+ if(!ignerr){
+ errstr(errbuf, sizeof errbuf);
+ fprint(2, "rm: %s: %s\n", f, errbuf);
+ }
+}
+
+int
+badentry(char *filename)
+{
+ if(*filename == 0)
+ return 1;
+ if(filename[0] == '.'){
+ if(filename[1] == 0)
+ return 1;
+ if(filename[1] == '.' && filename[2] == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Read a whole directory before removing anything as the holes formed
+ * by removing affect the read offset.
+ */
+Direntry*
+readdirect(char *path)
+{
+ long n;
+ HANDLE h;
+ Direntry *d;
+ char fullpath[MAX_PATH];
+ WIN32_FIND_DATA data;
+
+ snprint(fullpath, MAX_PATH, "%s\\*.*", path);
+ h = FindFirstFile(fullpath, &data);
+ if(h == INVALID_HANDLE_VALUE)
+ err(path);
+
+ n = 0;
+ d = 0;
+ for(;;){
+ if(!badentry(data.cFileName)){
+ d = realloc(d, (n+2)*sizeof(Direntry));
+ if(d == 0){
+ err("memory allocation");
+ exits(errbuf);
+ }
+ d[n].name = malloc(strlen(data.cFileName)+1);
+ if(d[n].name == 0){
+ err("memory allocation");
+ exits(errbuf);
+ }
+ strcpy(d[n].name, data.cFileName);
+ if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ d[n].isdir = 1;
+ else
+ d[n].isdir = 0;
+ n++;
+ }
+ if(FindNextFile(h, &data) == 0)
+ break;
+ }
+ FindClose(h);
+ if(d){
+ d[n].name = 0;
+ d[n].isdir = 0;
+ }
+ return d;
+}
+
+/*
+ * f is a non-empty directory. Remove its contents and then it.
+ */
+void
+Ntrmdir(char *f)
+{
+ Direntry *dp, *dq;
+ char name[MAX_PATH];
+
+ dq = readdirect(f);
+
+ if(dq == 0)
+ return;
+
+ for(dp = dq; dp->name; dp++){
+ snprint(name, MAX_PATH, "%s/%s", f, dp->name);
+ if(remove(name) == -1){
+ if(dp->isdir == 0)
+ err(name);
+ else
+ if(RemoveDirectory(name) == 0)
+ Ntrmdir(name);
+ }
+ free(dp->name);
+ }
+ if(RemoveDirectory(f) == 0)
+ err(f);
+ free(dq);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ int recurse;
+ char *f;
+ Dir *db;
+
+ ignerr = 0;
+ recurse = 0;
+ ARGBEGIN{
+ case 'r':
+ recurse = 1;
+ break;
+ case 'f':
+ ignerr = 1;
+ break;
+ default:
+ fprint(2, "usage: rm [-fr] file ...\n");
+ exits("usage");
+ }ARGEND
+ for(i=0; i<argc; i++){
+ f = argv[i];
+ if(remove(f) != -1)
+ continue;
+ if((db = dirstat(f)) == nil || (db->qid.type&QTDIR) ==0)
+ err(f);
+ else if(RemoveDirectory(f) == 0)
+ if(recurse)
+ Ntrmdir(f);
+ else
+ err(f);
+ }
+ exits(errbuf);
+}
diff --git a/utils/sed/mkfile b/utils/sed/mkfile
new file mode 100644
index 00000000..f56a797b
--- /dev/null
+++ b/utils/sed/mkfile
@@ -0,0 +1,16 @@
+<../../mkconfig
+
+TARG=sed
+
+OFILES= sed.$O\
+
+HFILES= $ROOT/include/bio.h\
+ ../include/regexp.h\
+
+LIBS=regexp bio 9 # libbio.a uses lib9.a so order matters.
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/sed/sed.c b/utils/sed/sed.c
new file mode 100644
index 00000000..e275b8f4
--- /dev/null
+++ b/utils/sed/sed.c
@@ -0,0 +1,1428 @@
+/*
+ * sed -- stream editor
+ *
+ *
+ */
+#include <lib9.h>
+#include <bio.h>
+#include <regexp.h>
+
+enum {
+ DEPTH = 20, /* max nesting depth of {} */
+ MAXCMDS = 512, /* max sed commands */
+ ADDSIZE = 10000, /* size of add & read buffer */
+ MAXADDS = 20, /* max pending adds and reads */
+ LBSIZE = 8192, /* input line size */
+ LABSIZE = 50, /* max label name size */
+ MAXSUB = 10, /* max number of sub reg exp */
+ MAXFILES = 120, /* max output files */
+};
+ /* An address is a line #, a R.E., "$", a reference to the last
+ * R.E., or nothing.
+ */
+typedef struct {
+ enum {
+ A_NONE,
+ A_DOL,
+ A_LINE,
+ A_RE,
+ A_LAST,
+ }type;
+ union {
+ long line; /* Line # */
+ Reprog *rp; /* Compiled R.E. */
+ };
+} Addr;
+
+typedef struct SEDCOM {
+ Addr ad1; /* optional start address */
+ Addr ad2; /* optional end address */
+ union {
+ Reprog *re1; /* compiled R.E. */
+ Rune *text; /* added text or file name */
+ struct SEDCOM *lb1; /* destination command of branch */
+ };
+ Rune *rhs; /* Right-hand side of substitution */
+ Biobuf* fcode; /* File ID for read and write */
+ char command; /* command code -see below */
+ char gfl; /* 'Global' flag for substitutions */
+ char pfl; /* 'print' flag for substitutions */
+ char active; /* 1 => data between start and end */
+ char negfl; /* negation flag */
+} SedCom;
+
+ /* Command Codes for field SedCom.command */
+#define ACOM 01
+#define BCOM 020
+#define CCOM 02
+#define CDCOM 025
+#define CNCOM 022
+#define COCOM 017
+#define CPCOM 023
+#define DCOM 03
+#define ECOM 015
+#define EQCOM 013
+#define FCOM 016
+#define GCOM 027
+#define CGCOM 030
+#define HCOM 031
+#define CHCOM 032
+#define ICOM 04
+#define LCOM 05
+#define NCOM 012
+#define PCOM 010
+#define QCOM 011
+#define RCOM 06
+#define SCOM 07
+#define TCOM 021
+#define WCOM 014
+#define CWCOM 024
+#define YCOM 026
+#define XCOM 033
+
+
+typedef struct label { /* Label symbol table */
+ Rune asc[9]; /* Label name */
+ SedCom *chain;
+ SedCom *address; /* Command associated with label */
+} Label;
+
+typedef struct FILE_CACHE { /* Data file control block */
+ struct FILE_CACHE *next; /* Forward Link */
+ char *name; /* Name of file */
+} FileCache;
+
+SedCom pspace[MAXCMDS]; /* Command storage */
+SedCom *pend = pspace+MAXCMDS; /* End of command storage */
+SedCom *rep = pspace; /* Current fill point */
+
+Reprog *lastre = 0; /* Last regular expression */
+Resub subexp[MAXSUB]; /* sub-patterns of pattern match*/
+
+Rune addspace[ADDSIZE]; /* Buffer for a, c, & i commands */
+Rune *addend = addspace+ADDSIZE;
+
+SedCom *abuf[MAXADDS]; /* Queue of pending adds & reads */
+SedCom **aptr = abuf;
+
+struct { /* Sed program input control block */
+ enum PTYPE /* Either on command line or in file */
+ { P_ARG,
+ P_FILE
+ } type;
+ union PCTL { /* Pointer to data */
+ Biobuf *bp;
+ char *curr;
+ };
+} prog;
+
+Rune genbuf[LBSIZE]; /* Miscellaneous buffer */
+
+FileCache *fhead = 0; /* Head of File Cache Chain */
+FileCache *ftail = 0; /* Tail of File Cache Chain */
+
+Rune *loc1; /* Start of pattern match */
+Rune *loc2; /* End of pattern match */
+Rune seof; /* Pattern delimiter char */
+
+Rune linebuf[LBSIZE+1]; /* Input data buffer */
+Rune *lbend = linebuf+LBSIZE; /* End of buffer */
+Rune *spend = linebuf; /* End of input data */
+Rune *cp; /* Current scan point in linebuf */
+
+Rune holdsp[LBSIZE+1]; /* Hold buffer */
+Rune *hend = holdsp+LBSIZE; /* End of hold buffer */
+Rune *hspend = holdsp; /* End of hold data */
+
+int nflag; /* Command line flags */
+int gflag;
+
+int dolflag; /* Set when at true EOF */
+int sflag; /* Set when substitution done */
+int jflag; /* Set when jump required */
+int delflag; /* Delete current line when set */
+
+long lnum = 0; /* Input line count */
+
+char fname[MAXFILES][40]; /* File name cache */
+Biobuf *fcode[MAXFILES]; /* File ID cache */
+int nfiles = 0; /* Cache fill point */
+
+Biobuf fout; /* Output stream */
+Biobuf stdin; /* Default input */
+Biobuf* f = 0; /* Input data */
+
+Label ltab[LABSIZE]; /* Label name symbol table */
+Label *labend = ltab+LABSIZE; /* End of label table */
+Label *lab = ltab+1; /* Current Fill point */
+
+int depth = 0; /* {} stack pointer */
+
+Rune bad; /* Dummy err ptr reference */
+Rune *badp = &bad;
+
+
+char CGMES[] = "Command garbled: %S";
+char TMMES[] = "Too much text: %S";
+char LTL[] = "Label too long: %S";
+char AD0MES[] = "No addresses allowed: %S";
+char AD1MES[] = "Only one address allowed: %S";
+
+void address(Addr *);
+void arout(void);
+int cmp(char *, char *);
+int rcmp(Rune *, Rune *);
+void command(SedCom *);
+Reprog *compile(void);
+Rune *compsub(Rune *, Rune *);
+void dechain(void);
+void dosub(Rune *);
+int ecmp(Rune *, Rune *, int);
+void enroll(char *);
+void errexit(void);
+int executable(SedCom *);
+void execute(void);
+void fcomp(void);
+long getrune(void);
+Rune *gline(Rune *);
+int match(Reprog *, Rune *);
+void newfile(enum PTYPE, char *);
+int opendata(void);
+Biobuf *open_file(char *);
+Rune *place(Rune *, Rune *, Rune *);
+void quit(char *, char *);
+int rline(Rune *, Rune *);
+Label *search(Label *);
+int substitute(SedCom *);
+char *text(char *);
+Rune *stext(Rune *, Rune *);
+int ycomp(SedCom *);
+char * trans(int c);
+void putline(Biobuf *bp, Rune *buf, int n);
+
+void
+main(int argc, char **argv)
+{
+ int compfl;
+
+ lnum = 0;
+ Binit(&fout, 1, OWRITE);
+ fcode[nfiles++] = &fout;
+ compfl = 0;
+
+ if(argc == 1)
+ exits(0);
+ ARGBEGIN{
+ case 'n':
+ nflag++;
+ continue;
+ case 'f':
+ if(argc <= 1)
+ quit("no pattern-file", 0);
+ newfile(P_FILE, ARGF());
+ fcomp();
+ compfl = 1;
+ continue;
+ case 'e':
+ if (argc <= 1)
+ quit("missing pattern", 0);
+ newfile(P_ARG, ARGF());
+ fcomp();
+ compfl = 1;
+ continue;
+ case 'g':
+ gflag++;
+ continue;
+ default:
+ fprint(2, "sed: Unknown flag: %c\n", ARGC());
+ continue;
+ } ARGEND
+
+ if(compfl == 0) {
+ if (--argc < 0)
+ quit("missing pattern", 0);
+ newfile(P_ARG, *argv++);
+ fcomp();
+ }
+
+ if(depth)
+ quit("Too many {'s", 0);
+
+ ltab[0].address = rep;
+
+ dechain();
+
+ if(argc <= 0)
+ enroll(0); /* Add stdin to cache */
+ else while(--argc >= 0) {
+ enroll(*argv++);
+ }
+ execute();
+ exits(0);
+}
+void
+fcomp(void)
+{
+ Rune *tp;
+ SedCom *pt, *pt1;
+ int i;
+ Label *lpt;
+
+ static Rune *p = addspace;
+ static SedCom **cmpend[DEPTH]; /* stack of {} operations */
+
+ while (rline(linebuf, lbend) >= 0) {
+ cp = linebuf;
+comploop:
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ if(*cp == '\0' || *cp == '#')
+ continue;
+ if(*cp == ';') {
+ cp++;
+ goto comploop;
+ }
+
+ address(&rep->ad1);
+ if (rep->ad1.type != A_NONE) {
+ if (rep->ad1.type == A_LAST) {
+ if (!lastre)
+ quit("First RE may not be null", 0);
+ rep->ad1.type = A_RE;
+ rep->ad1.rp = lastre;
+ }
+ if(*cp == ',' || *cp == ';') {
+ cp++;
+ address(&rep->ad2);
+ if (rep->ad2.type == A_LAST) {
+ rep->ad1.type = A_RE;
+ rep->ad2.rp = lastre;
+ }
+ } else
+ rep->ad2.type = A_NONE;
+ }
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+
+swit:
+ switch(*cp++) {
+
+ default:
+ quit("Unrecognized command: %S", (char *)linebuf);
+
+ case '!':
+ rep->negfl = 1;
+ goto swit;
+
+ case '{':
+ rep->command = BCOM;
+ rep->negfl = !(rep->negfl);
+ cmpend[depth++] = &rep->lb1;
+ if(++rep >= pend)
+ quit("Too many commands: %S", (char *) linebuf);
+ if(*cp == '\0') continue;
+ goto comploop;
+
+ case '}':
+ if(rep->ad1.type != A_NONE)
+ quit(AD0MES, (char *) linebuf);
+ if(--depth < 0)
+ quit("Too many }'s", 0);
+ *cmpend[depth] = rep;
+ if(*cp == 0) continue;
+ goto comploop;
+
+ case '=':
+ rep->command = EQCOM;
+ if(rep->ad2.type != A_NONE)
+ quit(AD1MES, (char *) linebuf);
+ break;
+
+ case ':':
+ if(rep->ad1.type != A_NONE)
+ quit(AD0MES, (char *) linebuf);
+
+ while(*cp == ' ')
+ cp++;
+ tp = lab->asc;
+ while (*cp && *cp != ';' && *cp != ' ' && *cp != '\t' && *cp != '#') {
+ *tp++ = *cp++;
+ if(tp >= &(lab->asc[8]))
+ quit(LTL, (char *) linebuf);
+ }
+ *tp = '\0';
+
+ if(lpt = search(lab)) {
+ if(lpt->address)
+ quit("Duplicate labels: %S", (char *) linebuf);
+ } else {
+ lab->chain = 0;
+ lpt = lab;
+ if(++lab >= labend)
+ quit("Too many labels: %S", (char *) linebuf);
+ }
+ lpt->address = rep;
+ if (*cp == '#')
+ continue;
+ rep--; /* reuse this slot */
+ break;
+
+ case 'a':
+ rep->command = ACOM;
+ if(rep->ad2.type != A_NONE)
+ quit(AD1MES, (char *) linebuf);
+ if(*cp == '\\') cp++;
+ if(*cp++ != '\n')
+ quit(CGMES, (char *) linebuf);
+ rep->text = p;
+ p = stext(p, addend);
+ break;
+ case 'c':
+ rep->command = CCOM;
+ if(*cp == '\\') cp++;
+ if(*cp++ != '\n')
+ quit(CGMES, (char *) linebuf);
+ rep->text = p;
+ p = stext(p, addend);
+ break;
+ case 'i':
+ rep->command = ICOM;
+ if(rep->ad2.type != A_NONE)
+ quit(AD1MES, (char *) linebuf);
+ if(*cp == '\\') cp++;
+ if(*cp++ != '\n')
+ quit(CGMES, (char *) linebuf);
+ rep->text = p;
+ p = stext(p, addend);
+ break;
+
+ case 'g':
+ rep->command = GCOM;
+ break;
+
+ case 'G':
+ rep->command = CGCOM;
+ break;
+
+ case 'h':
+ rep->command = HCOM;
+ break;
+
+ case 'H':
+ rep->command = CHCOM;
+ break;
+
+ case 't':
+ rep->command = TCOM;
+ goto jtcommon;
+
+ case 'b':
+ rep->command = BCOM;
+jtcommon:
+ while(*cp == ' ')cp++;
+ if(*cp == '\0') {
+ if(pt = ltab[0].chain) {
+ while(pt1 = pt->lb1)
+ pt = pt1;
+ pt->lb1 = rep;
+ } else
+ ltab[0].chain = rep;
+ break;
+ }
+ tp = lab->asc;
+ while((*tp++ = *cp++))
+ if(tp >= &(lab->asc[8]))
+ quit(LTL, (char *) linebuf);
+ cp--;
+ tp[-1] = '\0';
+
+ if(lpt = search(lab)) {
+ if(lpt->address) {
+ rep->lb1 = lpt->address;
+ } else {
+ pt = lpt->chain;
+ while(pt1 = pt->lb1)
+ pt = pt1;
+ pt->lb1 = rep;
+ }
+ } else {
+ lab->chain = rep;
+ lab->address = 0;
+ if(++lab >= labend)
+ quit("Too many labels: %S",
+ (char *) linebuf);
+ }
+ break;
+
+ case 'n':
+ rep->command = NCOM;
+ break;
+
+ case 'N':
+ rep->command = CNCOM;
+ break;
+
+ case 'p':
+ rep->command = PCOM;
+ break;
+
+ case 'P':
+ rep->command = CPCOM;
+ break;
+
+ case 'r':
+ rep->command = RCOM;
+ if(rep->ad2.type != A_NONE)
+ quit(AD1MES, (char *) linebuf);
+ if(*cp++ != ' ')
+ quit(CGMES, (char *) linebuf);
+ rep->text = p;
+ p = stext(p, addend);
+ break;
+
+ case 'd':
+ rep->command = DCOM;
+ break;
+
+ case 'D':
+ rep->command = CDCOM;
+ rep->lb1 = pspace;
+ break;
+
+ case 'q':
+ rep->command = QCOM;
+ if(rep->ad2.type != A_NONE)
+ quit(AD1MES, (char *) linebuf);
+ break;
+
+ case 'l':
+ rep->command = LCOM;
+ break;
+
+ case 's':
+ rep->command = SCOM;
+ seof = *cp++;
+ if ((rep->re1 = compile()) == 0) {
+ if(!lastre)
+ quit("First RE may not be null.", 0);
+ rep->re1 = lastre;
+ }
+ rep->rhs = p;
+ if((p = compsub(p, addend)) == 0)
+ quit(CGMES, (char *) linebuf);
+ if(*cp == 'g') {
+ cp++;
+ rep->gfl++;
+ } else if(gflag)
+ rep->gfl++;
+
+ if(*cp == 'p') {
+ cp++;
+ rep->pfl = 1;
+ }
+
+ if(*cp == 'P') {
+ cp++;
+ rep->pfl = 2;
+ }
+
+ if(*cp == 'w') {
+ cp++;
+ if(*cp++ != ' ')
+ quit(CGMES, (char *) linebuf);
+ text(fname[nfiles]);
+ for(i = nfiles - 1; i >= 0; i--)
+ if(cmp(fname[nfiles],fname[i]) == 0) {
+ rep->fcode = fcode[i];
+ goto done;
+ }
+ if(nfiles >= MAXFILES)
+ quit("Too many files in w commands 1", 0);
+ rep->fcode = open_file(fname[nfiles]);
+ }
+ break;
+
+ case 'w':
+ rep->command = WCOM;
+ if(*cp++ != ' ')
+ quit(CGMES, (char *) linebuf);
+ text(fname[nfiles]);
+ for(i = nfiles - 1; i >= 0; i--)
+ if(cmp(fname[nfiles], fname[i]) == 0) {
+ rep->fcode = fcode[i];
+ goto done;
+ }
+ if(nfiles >= MAXFILES){
+ fprint(2, "sed: Too many files in w commands 2 \n");
+ fprint(2, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES);
+ errexit();
+ }
+ rep->fcode = open_file(fname[nfiles]);
+ break;
+
+ case 'x':
+ rep->command = XCOM;
+ break;
+
+ case 'y':
+ rep->command = YCOM;
+ seof = *cp++;
+ if (ycomp(rep) == 0)
+ quit(CGMES, (char *) linebuf);
+ break;
+
+ }
+done:
+ if(++rep >= pend)
+ quit("Too many commands, last: %S", (char *) linebuf);
+
+ if(*cp++ != '\0') {
+ if(cp[-1] == ';')
+ goto comploop;
+ quit(CGMES, (char *) linebuf);
+ }
+
+ }
+}
+
+Biobuf *
+open_file(char *name)
+{
+ Biobuf *bp;
+ int fd;
+
+ if ((bp = malloc(sizeof(Biobuf))) == 0)
+ quit("Out of memory", 0);
+ if ((fd = open(name, OWRITE)) < 0 &&
+ (fd = create(name, OWRITE, 0666)) < 0)
+ quit("Cannot create %s", name);
+ Binit(bp, fd, OWRITE);
+ Bseek(bp, 0, 2);
+ fcode[nfiles++] = bp;
+ return bp;
+}
+
+Rune *
+compsub(Rune *rhs, Rune *end)
+{
+ Rune r;
+
+ while ((r = *cp++) != '\0') {
+ if(r == '\\') {
+ if (rhs < end)
+ *rhs++ = 0xFFFF;
+ else
+ return 0;
+ r = *cp++;
+ if(r == 'n')
+ r = '\n';
+ } else {
+ if(r == seof) {
+ if (rhs < end)
+ *rhs++ = '\0';
+ else
+ return 0;
+ return rhs;
+ }
+ }
+ if (rhs < end)
+ *rhs++ = r;
+ else
+ return 0;
+
+ }
+ return 0;
+}
+
+Reprog *
+compile(void)
+{
+ Rune c;
+ char *ep;
+ char expbuf[512];
+
+ if((c = *cp++) == seof) /* '//' */
+ return 0;
+ ep = expbuf;
+ do {
+ if (c == 0 || c == '\n')
+ quit(TMMES, (char *) linebuf);
+ if (c == '\\') {
+ if (ep >= expbuf+sizeof(expbuf))
+ quit(TMMES, (char *) linebuf);
+ ep += runetochar(ep, &c);
+ if ((c = *cp++) == 'n')
+ c = '\n';
+ }
+ if (ep >= expbuf+sizeof(expbuf))
+ quit(TMMES, (char *) linebuf);
+ ep += runetochar(ep, &c);
+ } while ((c = *cp++) != seof);
+ *ep = 0;
+ return lastre = regcomp(expbuf);
+}
+
+void
+regerror(char *s)
+{
+ USED(s);
+ quit(CGMES, (char *) linebuf);
+}
+
+void
+newfile(enum PTYPE type, char *name)
+{
+ if (type == P_ARG)
+ prog.curr = name;
+ else if ((prog.bp = Bopen(name, OREAD)) == 0)
+ quit("Cannot open pattern-file: %s\n", name);
+ prog.type = type;
+}
+
+int
+rline(Rune *buf, Rune *end)
+{
+ long c;
+ Rune r;
+
+ while ((c = getrune()) >= 0) {
+ if(c == '\r') /* consume CRs on win95 */
+ continue;
+ r = c;
+ if (r == '\\') {
+ if (buf <= end)
+ *buf++ = r;
+ c = getrune();
+ if (c == '\r')
+ c = getrune();
+ if (c < 0)
+ break;
+ r = c;
+ } else if (r == '\n') {
+ *buf = '\0';
+ return(1);
+ }
+ if (buf <= end)
+ *buf++ = r;
+ }
+ *buf = '\0';
+ return(-1);
+}
+
+long
+getrune(void)
+{
+ char *p;
+ long c;
+ Rune r;
+
+ if (prog.type == P_ARG) {
+ if ((p = prog.curr) != 0) {
+ if (*p) {
+ prog.curr += chartorune(&r, p);
+ c = r;
+ } else {
+ c = '\n'; /* fake an end-of-line */
+ prog.curr = 0;
+ }
+ } else
+ c = -1;
+ } else if ((c = Bgetrune(prog.bp)) < 0)
+ Bterm(prog.bp);
+ return c;
+}
+
+void
+address(Addr *ap)
+{
+ int c;
+ long lno;
+
+ if((c = *cp++) == '$')
+ ap->type = A_DOL;
+ else if(c == '/') {
+ seof = c;
+ if (ap->rp = compile())
+ ap->type = A_RE;
+ else
+ ap->type = A_LAST;
+ }
+ else if (c >= '0' && c <= '9') {
+ lno = c-'0';
+ while ((c = *cp) >= '0' && c <= '9')
+ lno = lno*10 + *cp++-'0';
+ if(!lno)
+ quit("line number 0 is illegal",0);
+ ap->type = A_LINE;
+ ap->line = lno;
+ }
+ else {
+ cp--;
+ ap->type = A_NONE;
+ }
+}
+
+cmp(char *a, char *b) /* compare characters */
+{
+ while(*a == *b++)
+ if (*a == '\0')
+ return(0);
+ else a++;
+ return(1);
+}
+rcmp(Rune *a, Rune *b) /* compare runes */
+{
+ while(*a == *b++)
+ if (*a == '\0')
+ return(0);
+ else a++;
+ return(1);
+}
+
+char *
+text(char *p) /* extract character string */
+{
+ Rune r;
+
+ while(*cp == '\t' || *cp == ' ')
+ cp++;
+ while (*cp) {
+ if ((r = *cp++) == '\\')
+ if ((r = *cp++) == 0)
+ break;;
+ if (r == '\n')
+ while (*cp == '\t' || *cp == ' ')
+ cp++;
+ p += runetochar(p, &r);
+ }
+ *p++ = '\0';
+ return p;
+}
+
+Rune *
+stext(Rune *p, Rune *end) /* extract rune string */
+{
+ while(*cp == '\t' || *cp == ' ')
+ cp++;
+ while (*cp) {
+ if (*cp == '\\')
+ if (*++cp == 0)
+ break;
+ if (p >= end-1)
+ quit(TMMES, (char *) linebuf);
+ if ((*p++ = *cp++) == '\n')
+ while(*cp == '\t' || *cp == ' ')
+ cp++;
+ }
+ *p++ = 0;
+ return p;
+}
+
+
+Label *
+search (Label *ptr)
+{
+ Label *rp;
+
+ for (rp = ltab; rp < ptr; rp++)
+ if(rcmp(rp->asc, ptr->asc) == 0)
+ return(rp);
+ return(0);
+}
+
+void
+dechain(void)
+{
+ Label *lptr;
+ SedCom *rptr, *trptr;
+
+ for(lptr = ltab; lptr < lab; lptr++) {
+
+ if(lptr->address == 0)
+ quit("Undefined label: %S", (char *) lptr->asc);
+
+ if(lptr->chain) {
+ rptr = lptr->chain;
+ while(trptr = rptr->lb1) {
+ rptr->lb1 = lptr->address;
+ rptr = trptr;
+ }
+ rptr->lb1 = lptr->address;
+ }
+ }
+}
+
+int
+ycomp(SedCom *r)
+{
+ int i;
+ Rune *rp;
+ Rune c, *tsp, highc;
+ Rune *sp;
+
+ highc = 0;
+ for(tsp = cp; *tsp != seof; tsp++) {
+ if(*tsp == '\\')
+ tsp++;
+ if(*tsp == '\n' || *tsp == '\0')
+ return(0);
+ if (*tsp > highc) highc = *tsp;
+ }
+ tsp++;
+ if ((rp = r->text = (Rune *) malloc(sizeof(Rune)*(highc+2))) == 0)
+ quit("Out of memory", 0);
+ *rp++ = highc; /* save upper bound */
+ for (i = 0; i <= highc; i++)
+ rp[i] = i;
+ sp = cp;
+ while((c = *sp++) != seof) {
+ if(c == '\\' && *sp == 'n') {
+ sp++;
+ c = '\n';
+ }
+ if((rp[c] = *tsp++) == '\\' && *tsp == 'n') {
+ rp[c] = '\n';
+ tsp++;
+ }
+ if(rp[c] == seof || rp[c] == '\0') {
+ free(r->re1);
+ r->re1 = 0;
+ return(0);
+ }
+ }
+ if(*tsp != seof) {
+ free(r->re1);
+ r->re1 = 0;
+ return(0);
+ }
+ cp = tsp+1;
+ return(1);
+}
+
+void
+execute(void)
+{
+ SedCom *ipc;
+
+ while (spend = gline(linebuf)){
+ for(ipc = pspace; ipc->command; ) {
+ if (!executable(ipc)) {
+ ipc++;
+ continue;
+ }
+ command(ipc);
+
+ if(delflag)
+ break;
+
+ if(jflag) {
+ jflag = 0;
+ if((ipc = ipc->lb1) == 0)
+ break;
+ } else
+ ipc++;
+
+ }
+ if(!nflag && !delflag)
+ putline(&fout, linebuf, spend-linebuf);
+ if(aptr > abuf) {
+ arout();
+ }
+ delflag = 0;
+ }
+}
+ /* determine if a statement should be applied to an input line */
+int
+executable(SedCom *ipc)
+{
+ if (ipc->active) { /* Addr1 satisfied - accept until Addr2 */
+ if (ipc->active == 1) /* Second line */
+ ipc->active = 2;
+ switch(ipc->ad2.type) {
+ case A_NONE: /* No second addr; use first */
+ ipc->active = 0;
+ break;
+ case A_DOL: /* Accept everything */
+ return !ipc->negfl;
+ case A_LINE: /* Line at end of range? */
+ if (lnum <= ipc->ad2.line) {
+ if (ipc->ad2.line == lnum)
+ ipc->active = 0;
+ return !ipc->negfl;
+ }
+ ipc->active = 0; /* out of range */
+ return ipc->negfl;
+ case A_RE: /* Check for matching R.E. */
+ if (match(ipc->ad2.rp, linebuf))
+ ipc->active = 0;
+ return !ipc->negfl;
+ default: /* internal error */
+ quit("Internal error", 0);
+ }
+ }
+ switch (ipc->ad1.type) { /* Check first address */
+ case A_NONE: /* Everything matches */
+ return !ipc->negfl;
+ case A_DOL: /* Only last line */
+ if (dolflag)
+ return !ipc->negfl;
+ break;
+ case A_LINE: /* Check line number */
+ if (ipc->ad1.line == lnum) {
+ ipc->active = 1; /* In range */
+ return !ipc->negfl;
+ }
+ break;
+ case A_RE: /* Check R.E. */
+ if (match(ipc->ad1.rp, linebuf)) {
+ ipc->active = 1; /* In range */
+ return !ipc->negfl;
+ }
+ break;
+ default:
+ quit("Internal error", 0);
+ }
+ return ipc->negfl;
+}
+match(Reprog *pattern, Rune *buf)
+{
+ if (!pattern)
+ return 0;
+ subexp[0].s.rsp = buf;
+ subexp[0].e.ep = 0;
+ if (rregexec(pattern, linebuf, subexp, MAXSUB)) {
+ loc1 = subexp[0].s.rsp;
+ loc2 = subexp[0].e.rep;
+ return 1;
+ }
+ loc1 = loc2 = 0;
+ return 0;
+}
+substitute(SedCom *ipc)
+{
+ if(match(ipc->re1, linebuf)) {
+ sflag = 1;
+ dosub(ipc->rhs);
+ if(!ipc->gfl)
+ return 1;
+ while (match(ipc->re1, loc2)) {
+ if (loc2-loc1 == 0){ /* NULL R.E. match */
+ if (*loc2++ == 0)
+ break;
+ } else {
+ dosub(ipc->rhs);
+ if(*loc2 == 0)
+ break;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void
+dosub(Rune *rhsbuf)
+{
+ Rune *lp, *sp;
+ Rune *rp;
+ int c, n;
+
+ lp = linebuf;
+ sp = genbuf;
+ rp = rhsbuf;
+ while (lp < loc1)
+ *sp++ = *lp++;
+ while(c = *rp++) {
+ if (c == '&') {
+ sp = place(sp, loc1, loc2);
+ continue;
+ }
+ if (c == 0xFFFF && (c = *rp++) >= '1' && c <= MAXSUB+'0') {
+ n = c-'0';
+ if (subexp[n].s.rsp && subexp[n].e.rep) {
+ sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
+ continue;
+ }
+ else {
+ fprint(2, "sed: Invalid back reference \\%d\n",n);
+ errexit();
+ }
+ }
+ *sp++ = c;
+ if (sp >= &genbuf[LBSIZE])
+ fprint(2, "sed: Output line too long.\n");
+ }
+ lp = loc2;
+ loc2 = sp - genbuf + linebuf;
+ while (*sp++ = *lp++)
+ if (sp >= &genbuf[LBSIZE])
+ fprint(2, "sed: Output line too long.\n");
+ lp = linebuf;
+ sp = genbuf;
+ while (*lp++ = *sp++)
+ ;
+ spend = lp-1;
+}
+
+Rune *
+place(Rune *sp, Rune *l1, Rune *l2)
+{
+ while (l1 < l2) {
+ *sp++ = *l1++;
+ if (sp >= &genbuf[LBSIZE])
+ fprint(2, "sed: Output line too long.\n");
+ }
+ return(sp);
+}
+
+char *
+trans(int c)
+{
+ static char buf[] = "\\x0000";
+ static char hex[] = "0123456789abcdef";
+
+ switch(c) {
+ case '\b':
+ return "\\b";
+ case '\n':
+ return "\\n";
+ case '\r':
+ return "\\r";
+ case '\t':
+ return "\\t";
+ case '\\':
+ return "\\\\";
+ }
+ buf[2] = hex[(c>>12)&0xF];
+ buf[3] = hex[(c>>8)&0xF];
+ buf[4] = hex[(c>>4)&0xF];
+ buf[5] = hex[c&0xF];
+ return buf;
+}
+
+void
+command(SedCom *ipc)
+{
+ int i, c;
+ Rune *p1, *p2;
+ char *ucp;
+ Rune *rp;
+ Rune *execp;
+
+ switch(ipc->command) {
+
+ case ACOM:
+ *aptr++ = ipc;
+ if(aptr >= abuf+MAXADDS) {
+ quit("sed: Too many appends after line %ld\n",
+ (char *) lnum);
+ }
+ *aptr = 0;
+ break;
+ case CCOM:
+ delflag = 1;
+ if(ipc->active == 1) {
+ for(rp = ipc->text; *rp; rp++)
+ Bputrune(&fout, *rp);
+ Bputc(&fout, '\n');
+ }
+ break;
+ case DCOM:
+ delflag++;
+ break;
+ case CDCOM:
+ p1 = p2 = linebuf;
+ while(*p1 != '\n') {
+ if(*p1++ == 0) {
+ delflag++;
+ return;
+ }
+ }
+ p1++;
+ while(*p2++ = *p1++)
+ ;
+ spend = p2-1;
+ jflag++;
+ break;
+ case EQCOM:
+ Bprint(&fout, "%ld\n", lnum);
+ break;
+ case GCOM:
+ p1 = linebuf;
+ p2 = holdsp;
+ while(*p1++ = *p2++)
+ ;
+ spend = p1-1;
+ break;
+ case CGCOM:
+ *spend++ = '\n';
+ p1 = spend;
+ p2 = holdsp;
+ while(*p1++ = *p2++)
+ if(p1 >= lbend)
+ break;
+ spend = p1-1;
+ break;
+ case HCOM:
+ p1 = holdsp;
+ p2 = linebuf;
+ while(*p1++ = *p2++);
+ hspend = p1-1;
+ break;
+ case CHCOM:
+ *hspend++ = '\n';
+ p1 = hspend;
+ p2 = linebuf;
+ while(*p1++ = *p2++)
+ if(p1 >= hend)
+ break;
+ hspend = p1-1;
+ break;
+ case ICOM:
+ for(rp = ipc->text; *rp; rp++)
+ Bputrune(&fout, *rp);
+ Bputc(&fout, '\n');
+ break;
+ case BCOM:
+ jflag = 1;
+ break;
+ case LCOM:
+ c = 0;
+ for (i = 0, rp = linebuf; *rp; rp++) {
+ c = *rp;
+ if(c >= 0x20 && c < 0x7F && c != '\\') {
+ Bputc(&fout, c);
+ if(i++ > 71) {
+ Bprint(&fout, "\\\n");
+ i = 0;
+ }
+ } else {
+ for (ucp = trans(*rp); *ucp; ucp++){
+ c = *ucp;
+ Bputc(&fout, c);
+ if(i++ > 71) {
+ Bprint(&fout, "\\\n");
+ i = 0;
+ }
+ }
+ }
+ }
+ if(c == ' ')
+ Bprint(&fout, "\\n");
+ Bputc(&fout, '\n');
+ break;
+ case NCOM:
+ if(!nflag)
+ putline(&fout, linebuf, spend-linebuf);
+
+ if(aptr > abuf)
+ arout();
+ if((execp = gline(linebuf)) == 0) {
+ delflag = 1;
+ break;
+ }
+ spend = execp;
+ break;
+ case CNCOM:
+ if(aptr > abuf)
+ arout();
+ *spend++ = '\n';
+ if((execp = gline(spend)) == 0) {
+ delflag = 1;
+ break;
+ }
+ spend = execp;
+ break;
+ case PCOM:
+ putline(&fout, linebuf, spend-linebuf);
+ break;
+ case CPCOM:
+ cpcom:
+ for(rp = linebuf; *rp && *rp != '\n'; rp++)
+ Bputc(&fout, *rp);
+ Bputc(&fout, '\n');
+ break;
+ case QCOM:
+ if(!nflag)
+ putline(&fout, linebuf, spend-linebuf);
+ if(aptr > abuf)
+ arout();
+ exits(0);
+ case RCOM:
+ *aptr++ = ipc;
+ if(aptr >= &abuf[MAXADDS])
+ quit("sed: Too many reads after line %ld\n",
+ (char *) lnum);
+ *aptr = 0;
+ break;
+ case SCOM:
+ i = substitute(ipc);
+ if(i && ipc->pfl)
+ if(ipc->pfl == 1)
+ putline(&fout, linebuf, spend-linebuf);
+ else
+ goto cpcom;
+ if(i && ipc->fcode)
+ goto wcom;
+ break;
+
+ case TCOM:
+ if(sflag == 0) break;
+ sflag = 0;
+ jflag = 1;
+ break;
+
+ wcom:
+ case WCOM:
+ putline(ipc->fcode,linebuf, spend-linebuf);
+ break;
+ case XCOM:
+ p1 = linebuf;
+ p2 = genbuf;
+ while(*p2++ = *p1++);
+ p1 = holdsp;
+ p2 = linebuf;
+ while(*p2++ = *p1++);
+ spend = p2 - 1;
+ p1 = genbuf;
+ p2 = holdsp;
+ while(*p2++ = *p1++);
+ hspend = p2 - 1;
+ break;
+ case YCOM:
+ p1 = linebuf;
+ p2 = ipc->text;
+ for (i = *p2++; *p1; p1++){
+ if (*p1 <= i) *p1 = p2[*p1];
+ }
+ break;
+ }
+
+}
+
+void
+putline(Biobuf *bp, Rune *buf, int n)
+{
+ while (n--)
+ Bputrune(bp, *buf++);
+ Bputc(bp, '\n');
+}
+ecmp(Rune *a, Rune *b, int count)
+{
+ while(count--)
+ if(*a++ != *b++) return(0);
+ return(1);
+}
+
+void
+arout(void)
+{
+ Rune *p1;
+ Biobuf *fi;
+ int c;
+ char *s;
+ char buf[128];
+
+ for (aptr = abuf; *aptr; aptr++) {
+ if((*aptr)->command == ACOM) {
+ for(p1 = (*aptr)->text; *p1; p1++ )
+ Bputrune(&fout, *p1);
+ Bputc(&fout, '\n');
+ } else {
+ for(s = buf, p1= (*aptr)->text; *p1; p1++)
+ s += runetochar(s, p1);
+ *s = '\0';
+ if((fi = Bopen(buf, OREAD)) == 0)
+ continue;
+ while((c = Bgetc(fi)) >= 0)
+ Bputc(&fout, c);
+ Bterm(fi);
+ }
+ }
+ aptr = abuf;
+ *aptr = 0;
+}
+
+void
+errexit(void)
+{
+ exits("error");
+}
+
+void
+quit (char *msg, char *arg)
+{
+ fprint(2, "sed: ");
+ fprint(2, msg, arg);
+ fprint(2, "\n");
+ errexit();
+}
+
+Rune *
+gline(Rune *addr)
+{
+ long c;
+ Rune *p;
+
+ static long peekc = 0;
+
+ if (f == 0 && opendata() < 0)
+ return 0;
+ sflag = 0;
+ lnum++;
+/* Bflush(&fout);********* dumped 4/30/92 - bobf****/
+ do {
+ p = addr;
+ for (c = (peekc ? peekc : Bgetrune(f)); c >= 0; c = Bgetrune(f)) {
+ if (c == '\n') {
+ if ((peekc = Bgetrune(f)) < 0) {
+ Bterm(f);
+ if (fhead == 0)
+ dolflag = 1;
+ }
+ *p = '\0';
+ return p;
+ }
+ if (c && p < lbend)
+ *p++ = c;
+ }
+ peekc = 0;
+ } while (opendata() > 0); /* Switch to next stream */
+ f = 0;
+ return 0;
+}
+
+ /* Data file input section - the intent is to transparently
+ * catenate all data input streams.
+ */
+void
+enroll(char *filename) /* Add a file to the input file cache */
+{
+ FileCache *fp;
+
+ if ((fp = (FileCache *) malloc(sizeof (FileCache))) == 0)
+ quit("Out of memory", 0);
+ if (ftail == 0)
+ fhead = fp;
+ else
+ ftail->next = fp;
+ ftail = fp;
+ fp->next = 0;
+ fp->name = filename; /* 0 => stdin */
+}
+
+int
+opendata(void)
+{
+ if (fhead == 0)
+ return -1;
+ if (fhead->name) {
+ if ((f = Bopen(fhead->name, OREAD)) == 0)
+ quit("Can't open %s", fhead->name);
+ } else {
+ Binit(&stdin, 0, OREAD);
+ f = &stdin;
+ }
+ fhead = fhead->next;
+ return 1;
+}
diff --git a/utils/sqz/NOTICE b/utils/sqz/NOTICE
new file mode 100644
index 00000000..724003a1
--- /dev/null
+++ b/utils/sqz/NOTICE
@@ -0,0 +1,27 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1998 C H Forsyth (forsyth@terzarima.net).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/utils/sqz/mkfile b/utils/sqz/mkfile
new file mode 100644
index 00000000..430bbce5
--- /dev/null
+++ b/utils/sqz/mkfile
@@ -0,0 +1,19 @@
+<../../mkconfig
+CFLAGS=$CFLAGS -I../include
+
+TARG=sqz
+
+OFILES= sqz.$O\
+
+HFILES= \
+ squeeze.h\
+ ../include/a.out.h\
+ ../include/mach.h\
+
+LIBS= mach bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/sqz/squeeze.h b/utils/sqz/squeeze.h
new file mode 100644
index 00000000..b06c1b79
--- /dev/null
+++ b/utils/sqz/squeeze.h
@@ -0,0 +1,34 @@
+
+/*
+ * squeezed file format:
+ * Sqhdr
+ * original Exec header
+ * two Squeeze tables
+ * squeezed segment
+ * unsqueezed segment, if any
+ */
+#define SQMAGIC (ulong)0xFEEF0F1E
+
+typedef struct Sqhdr Sqhdr;
+struct Sqhdr {
+ uchar magic[4]; /* SQMAGIC */
+ uchar text[4]; /* squeezed length of text (excluding tables) */
+ uchar data[4]; /* squeezed length of data (excluding tables) */
+ uchar asis[4]; /* length of unsqueezed segment */
+ uchar toptxt[4]; /* value for 0 encoding in text */
+ uchar topdat[4]; /* value for 0 encoding in data */
+ uchar sum[4]; /* simple checksum of unsqueezed data */
+ uchar flags[4];
+};
+#define SQHDRLEN (8*4)
+
+/*
+ * certain power instruction types are rearranged by sqz
+ * so as to move the variable part of the instruction word to the
+ * low order bits. note that the mapping is its own inverse.
+ */
+#define QREMAP(X)\
+ switch((X)>>26){\
+ case 19: case 31: case 59: case 63:\
+ (X) = (((X) & 0xFC00F801) | (((X)>>15)&0x7FE) | (((X)&0x7FE)<<15));\
+ }
diff --git a/utils/sqz/sqz.c b/utils/sqz/sqz.c
new file mode 100644
index 00000000..cf399e45
--- /dev/null
+++ b/utils/sqz/sqz.c
@@ -0,0 +1,528 @@
+#include <lib9.h>
+#include <a.out.h>
+#include "squeeze.h"
+
+/*
+ * forsyth@vitanuova.com
+ */
+
+typedef struct Word Word;
+struct Word {
+ ulong v;
+ ushort freq;
+ ushort code;
+ Word* next;
+};
+
+typedef struct Squeeze Squeeze;
+struct Squeeze {
+ int n;
+ /*union {*/
+ ulong tab[7*256];
+ Word* rep[7*256];
+ /*};*/
+};
+
+enum {
+ HMASK = 0xFFFF,
+ HSIZE = HMASK+1,
+
+ Codebufsize = 3*1024*1024
+};
+
+#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3])
+#define GET4L(p) (((((((p)[3]<<8)|(p)[2])<<8)|(p)[1])<<8)|(p)[0])
+#define PUT4(p,v) (((p)[0]=(v)>>24),((p)[1]=(v)>>16),((p)[2]=(v)>>8),((p)[3]=(v)))
+
+static uchar prog[Codebufsize];
+static uchar outbuf[Codebufsize];
+static Word* hash1[HSIZE];
+static Word* hash2[HSIZE];
+static Sqhdr sqhdr;
+static ulong chksum;
+
+static int aflag; /* all: both text (squeezed) and data (not) */
+static int dflag; /* squeeze data, not text */
+static int tflag; /* squeeze text, leave data as-is */
+static int qflag = 1; /* enable powerpc option */
+static int wflag; /* write output */
+static int zflag; /* use top==0 for data segment */
+static int islittle; /* object code uses little-endian byte order */
+static int debug;
+static char* fname;
+
+static void analyse(ulong*, int, Squeeze*, Squeeze*, Word**);
+static Word** collate(Word**, int);
+static void dumpsq(Squeeze*, int);
+static void freehash(Word**);
+static long Read(int, void*, long);
+static void remap(Squeeze*);
+static int squeeze(ulong*, int, uchar*, ulong);
+static int squeezetab(int, int, Squeeze*, Word**, int);
+static void squirt(int, Squeeze*);
+static void Write(int, void*, long);
+
+static void
+usage(void)
+{
+ fprint(2, "Usage: sqz [-w] [-t] [-d] [-q] q.out\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, n, ns, nst, nsd;
+ long txtlen, datlen, asis;
+ ulong topdat, toptxt;
+ Exec ex;
+ Squeeze sq3, sq4, sq5, sq6;
+ Word *top;
+
+ setbinmode();
+/* fmtinstall('f', gfltconv); */
+ ARGBEGIN{
+ case 'D':
+ debug++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'q':
+ qflag = 0;
+ break;
+ case 't':
+ tflag++;
+ break;
+ case 'w':
+ wflag++;
+ break;
+ default:
+ usage();
+ }ARGEND
+ fname = *argv;
+ if(fname == nil)
+ usage();
+ fd = open(fname, OREAD);
+ if(fd < 0){
+ fprint(2, "sqz: can't open %s: %r\n", fname);
+ exits("open");
+ }
+ Read(fd, &ex, sizeof(Exec));
+ txtlen = GET4((uchar*)&ex.text);
+ datlen = GET4((uchar*)&ex.data);
+ switch(GET4((uchar*)&ex.magic)){
+ case Q_MAGIC: /* powerpc */
+ islittle = 0;
+ break;
+ case E_MAGIC: /* arm */
+ islittle = 1;
+ qflag = 0;
+ break;
+ case 0xA0E1: /* arm AIF */
+ islittle = 1;
+ qflag = 0;
+ txtlen = GET4L((uchar*)&ex+(5*4))-sizeof(Exec);
+ datlen = GET4L((uchar*)&ex+(6*4));
+ break;
+ default:
+ fprint(2, "sqz: unknown magic for sqz: %8.8ux\n", GET4((uchar*)&ex.magic));
+ exits("bad magic");
+ }
+ if(qflag)
+ fprint(2, "PowerPC rules\n");
+ if(islittle)
+ fprint(2, "Little endian\n");
+ if(txtlen > sizeof(prog) || datlen > sizeof(prog) || txtlen+datlen > sizeof(prog)){
+ fprint(2, "sqz: executable too big: %lud+%lud; increase Codebufsize in sqz.c\n", txtlen, datlen);
+ exits("size");
+ }
+ if(dflag){
+ seek(fd, txtlen, 1);
+ Read(fd, prog, datlen);
+ }else{
+ Read(fd, prog, txtlen);
+ Read(fd, prog+txtlen, datlen);
+ }
+ close(fd);
+ asis = 0;
+ if(dflag)
+ n = datlen;
+ else if(tflag){
+ n = txtlen;
+ asis = datlen;
+ }else
+ n = txtlen+datlen;
+ if(dflag || tflag){
+ analyse((ulong*)prog, n/4, &sq3, &sq4, &top);
+ nst = squeeze((ulong*)prog, n/4, outbuf, top->v);
+ if(nst < 0)
+ exits("sqz");
+ nsd = 0;
+ remap(&sq3);
+ remap(&sq4);
+ toptxt = topdat = top->v;
+ }else{
+ analyse((ulong*)prog, txtlen/4, &sq3, &sq4, &top);
+ nst = squeeze((ulong*)prog, txtlen/4, outbuf, top->v);
+ if(nst < 0)
+ exits("sqz");
+ toptxt = top->v;
+ remap(&sq3);
+ remap(&sq4);
+ if(datlen/4){
+ freehash(hash1);
+ freehash(hash2);
+ analyse((ulong*)(prog+txtlen), datlen/4, &sq5, &sq6, &top);
+ nsd = squeeze((ulong*)(prog+txtlen), datlen/4, outbuf+nst, top->v);
+ if(nsd < 0)
+ exits("sqz");
+ topdat = top->v;
+ remap(&sq5);
+ remap(&sq6);
+ }else{
+ nsd = 0;
+ topdat = 0;
+ }
+ }
+ ns = nst+nsd;
+ fprint(2, "%d/%d bytes\n", ns, n);
+ fprint(2, "%8.8lux csum\n", chksum);
+ if(!wflag)
+ exits(0);
+ PUT4(sqhdr.magic, SQMAGIC);
+ PUT4(sqhdr.toptxt, toptxt);
+ PUT4(sqhdr.sum, chksum);
+ PUT4(sqhdr.text, nst);
+ PUT4(sqhdr.topdat, topdat);
+ PUT4(sqhdr.data, nsd);
+ PUT4(sqhdr.asis, asis);
+ PUT4(sqhdr.flags, 0);
+ Write(1, &sqhdr, SQHDRLEN);
+ Write(1, &ex, sizeof(Exec));
+ squirt(1, &sq3);
+ squirt(1, &sq4);
+ Write(1, outbuf, nst);
+ if(nsd){
+ squirt(1, &sq5);
+ squirt(1, &sq6);
+ Write(1, outbuf+nst, nsd);
+ }
+ if(asis)
+ Write(1, prog+txtlen, asis);
+ exits(0);
+}
+
+static void
+analyse(ulong *prog, int nw, Squeeze *sq3, Squeeze *sq4, Word **top)
+{
+ Word *w, **hp, **sorts, **resorts;
+ ulong *rp, *ep;
+ ulong v;
+ int i, nv1, nv2, nv, nz;
+
+ rp = prog;
+ ep = prog+nw;
+ nv = 0;
+ nz = 0;
+ while(rp < ep){
+ if(islittle){
+ v = GET4L((uchar*)rp);
+ }else{
+ v = GET4((uchar*)rp);
+ }
+ rp++;
+ chksum += v;
+ if(v == 0){
+ nz++;
+ if(0)
+ continue;
+ }
+ if(qflag){
+ QREMAP(v);
+ }
+ for(hp = &hash1[v&HMASK]; (w = *hp) != nil; hp = &w->next)
+ if(w->v == v)
+ break;
+ if(w == nil){
+ w = (Word*)malloc(sizeof(*w));
+ w->v = v;
+ w->freq = 0;
+ w->code = 0;
+ w->next = nil;
+ *hp = w;
+ nv++;
+ }
+ w->freq++;
+ }
+ sorts = collate(hash1, nv);
+ fprint(2, "phase 1: %d/%d words (%d zero), %d top (%8.8lux)\n", nv, nw, nz, sorts[0]->freq, sorts[0]->v);
+ *top = sorts[0];
+ nv1 = squeezetab(1, 0x900, sq3, sorts+1, nv-1)+1;
+ nv2 = 0;
+ for(i=nv1; i<nv; i++){
+ v = sorts[i]->v >> 8;
+ for(hp = &hash2[v&HMASK]; (w = *hp) != nil; hp = &w->next)
+ if(w->v == v)
+ break;
+ if(w == nil){
+ w = (Word*)malloc(sizeof(*w));
+ w->v = v;
+ w->freq = 0;
+ w->code = 0;
+ w->next = nil;
+ *hp = w;
+ nv2++;
+ }
+ w->freq++;
+ }
+ free(sorts);
+ resorts = collate(hash2, nv2);
+ fprint(2, "phase 2: %d/%d\n", nv2, nv-nv1);
+ squeezetab(2, 0x200, sq4, resorts, nv2);
+ free(resorts);
+ fprint(2, "phase 3: 1 4-code, %d 12-codes, %d 20-codes, %d uncoded\n",
+ sq3->n, sq4->n, nv-(sq3->n+sq4->n+1));
+}
+
+static int
+wdcmp(const void *a, const void *b)
+{
+ return (*(Word**)b)->freq - (*(Word**)a)->freq;
+}
+
+static Word **
+collate(Word **tab, int nv)
+{
+ Word *w, **hp, **sorts;
+ int i;
+
+ sorts = (Word**)malloc(nv*sizeof(Word**));
+ i = 0;
+ for(hp = &tab[0]; hp < &tab[HSIZE]; hp++)
+ for(w = *hp; w != nil; w = w->next)
+ sorts[i++] = w;
+ qsort(sorts, nv, sizeof(*sorts), wdcmp);
+ if(debug > 1)
+ for(i=0; i<nv; i++)
+ fprint(2, "%d\t%d\t%8.8lux\n", i, sorts[i]->freq, sorts[i]->v);
+ return sorts;
+}
+
+static int
+tabcmp(const void *a, const void *b)
+{
+ ulong av, bv;
+
+ av = (*(Word**)a)->v;
+ bv = (*(Word**)b)->v;
+ if(av > bv)
+ return 1;
+ if(av < bv)
+ return -1;
+ return 0;
+}
+
+static int
+squeezetab(int tabno, int base, Squeeze *sq, Word **sorts, int nv)
+{
+ int i;
+
+ if(nv >= 7*256)
+ nv = 7*256;
+ memset(sq, 0, sizeof(*sq));
+ for(i=0; i<nv; i++)
+ sq->rep[sq->n++] = sorts[i];
+ qsort(sq->rep, sq->n, sizeof(*sq->rep), tabcmp);
+ for(i=0; i<sq->n; i++)
+ sq->rep[i]->code = base + i;
+ if(debug)
+ dumpsq(sq, tabno);
+ return sq->n;
+}
+
+static void
+dumpsq(Squeeze *sq, int n)
+{
+ int i;
+
+ fprint(2, "table %d: %d entries\n", n, sq->n);
+ for(i=0; i<sq->n; i++)
+ fprint(2, "%.3x\t%8.8lux\t%lux\n", sq->rep[i]->code, sq->rep[i]->v, i? sq->rep[i]->v - sq->rep[i-1]->v: 0);
+}
+
+static void
+remap(Squeeze *sq)
+{
+ int i;
+ ulong v;
+
+ if(sq->n){
+ v = 0;
+ for(i=0; i<sq->n; i++){
+ sq->tab[i] = sq->rep[i]->v - v;
+ v += sq->tab[i];
+ }
+ }
+}
+
+static Word *
+squash(Word **tab, ulong v)
+{
+ Word *w, **hp;
+
+ for(hp = &tab[v&0xFFFF]; (w = *hp) != nil; hp = &w->next)
+ if(w->v == v)
+ return w;
+ return nil;
+}
+
+static void
+freehash(Word **tab)
+{
+ Word *w, **hp;
+
+ for(hp = &tab[0]; hp < &tab[HSIZE]; hp++)
+ while((w = *hp) != nil){
+ *hp = w->next;
+ free(w);
+ }
+}
+
+static int
+squeeze(ulong *prog, int nw, uchar *out, ulong top)
+{
+ ulong *rp, *ep;
+ ulong v, bits;
+ ulong e1, e2, e3, e4;
+ Word *w;
+ uchar bytes[8], *bp, *wp;
+ int ctl, n;
+
+ rp = prog;
+ ep = prog+nw;
+ bits = 0;
+ e1 = e2 = e3 = e4 = 0;
+ wp = out;
+ n = 0;
+ ctl = 0;
+ bp = bytes;
+ for(;;){
+ if(n == 2){
+ *wp++ = ctl;
+ if(0)
+ fprint(2, "%x\n", ctl);
+ memmove(wp, bytes, bp-bytes);
+ wp += bp-bytes;
+ bp = bytes;
+ ctl = 0;
+ n = 0;
+ }
+ ctl <<= 4;
+ n++;
+ if(rp >= ep){
+ if(n == 1)
+ break;
+ continue;
+ }
+ if(islittle){
+ v = GET4L((uchar*)rp);
+ }else{
+ v = GET4((uchar*)rp);
+ }
+ rp++;
+ if(qflag){
+ QREMAP(v);
+ }
+ if(v == top){
+ e1++;
+ bits += 4;
+ ctl |= 0;
+ continue;
+ }
+ w = squash(hash1, v);
+ if(w && w->code){
+ e2++;
+ bits += 4+8;
+ ctl |= w->code>>8;
+ *bp++ = w->code;
+ continue;
+ }
+ w = squash(hash2, v>>8);
+ if(w && w->code){
+ e3++;
+ bits += 4+8+8;
+ ctl |= w->code>>8;
+ *bp++ = w->code;
+ *bp++ = v & 0xFF;
+ if(debug > 2)
+ fprint(2, "%x %8.8lux %8.8lux\n", w->code, w->v, v);
+ continue;
+ }
+ e4++;
+ bits += 4+32;
+ ctl |= 0x1;
+ bp[0] = v;
+ bp[1] = v>>8;
+ bp[2] = v>>16;
+ bp[3] = v>>24;
+ bp += 4;
+ }
+ fprint(2, "enc: %lud 4-bits, %lud 12-bits %lud 20-bits %lud 36-bits -- %ld bytes\n",
+ e1, e2, e3, e4, wp-out);
+ return wp-out;
+}
+
+static void
+squirt(int fd, Squeeze *sq)
+{
+ uchar b[7*256*5 + 2], rep[5], *p, *q;
+ ulong v;
+ int i;
+
+ p = b+2;
+ for(i=0; i<sq->n; i++){
+ v = sq->tab[i];
+ q = rep;
+ do {
+ *q++ = v & 0x7F;
+ }while((v >>= 7) != 0);
+ do {
+ *p++ = *--q | 0x80;
+ }while(q != rep);
+ p[-1] &= ~0x80;
+ }
+ if(p > b+sizeof(b))
+ abort();
+ i = p-b;
+ b[0] = i>>8;
+ b[1] = i;
+ Write(fd, b, i);
+ fprint(2, "table: %d/%d\n", i, (sq->n+1)*4);
+}
+
+static long
+Read(int fd, void *buf, long nb)
+{
+ long n;
+
+ n = read(fd, buf, nb);
+ if(n < 0){
+ fprint(2, "sqz: %s: read error: %r\n", fname);
+ exits("read");
+ }
+ if(n < nb){
+ fprint(2, "sqz: %s: unexpected end-of-file\n", fname);
+ exits("read");
+ }
+ return n;
+}
+
+static void
+Write(int fd, void *buf, long nb)
+{
+ if(write(fd, buf, nb) != nb){
+ fprint(2, "sqz: write error: %r\n");
+ exits("write err");
+ }
+}
diff --git a/utils/sqz/zqs.c b/utils/sqz/zqs.c
new file mode 100644
index 00000000..b9b2a163
--- /dev/null
+++ b/utils/sqz/zqs.c
@@ -0,0 +1,243 @@
+#include <lib9.h>
+#include <a.out.h>
+#include "squeeze.h"
+
+/*
+ * forsyth@vitanuova.com
+ */
+
+/*
+ * for details of `unsqueeze' see:
+ *
+ * %A Mark Taunton
+ * %T Compressed Executables: An Exercise in Thinking Small
+ * %P 385-404
+ * %I USENIX
+ * %B USENIX Conference Proceedings
+ * %D Summer 1991
+ * %C Nashville, TN
+ *
+ * several of the unimplemented improvements described in the paper
+ * have been implemented here
+ *
+ * there is a further transformation on the powerpc (QFLAG!=0) to shuffle bits
+ * in certain instructions so as to push the fixed bits to the top of the word.
+ */
+
+typedef struct Squeeze Squeeze;
+struct Squeeze {
+ int n;
+ ulong tab[7*256];
+};
+
+enum {
+ CHECK = 1 /* check precise bounds in Squeeze array */
+};
+
+#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3])
+
+static uchar out[3*1024*1024];
+static uchar bigb[1024*1024];
+static ulong top;
+static int qflag = 1;
+static int islittle = 0;
+static ulong chksum, oldsum;
+static int rdtab(int, Squeeze*, int);
+static long unsqueezefd(int, void*);
+static uchar* unsqueeze(uchar*, uchar*, uchar*, Squeeze*, Squeeze*, ulong);
+static uchar* unsqzseg(int, uchar*, long, ulong);
+
+void
+main(int argc, char **argv)
+{
+ int fd;
+ long n;
+
+ if(argc < 2)
+ exits("args");
+ fd = open(argv[1], OREAD);
+ if(fd < 0)
+ exits("open");
+ n = unsqueezefd(fd, out);
+ if(n < 0){
+ fprint(2, "zqs: can't unsqueeze\n");
+ exits("err");
+ }
+ if(write(1, out, n) != n){
+ fprint(2, "zqs: write error: %r\n");
+ exits("err");
+ }
+ fprint(2, "%ld bytes, %8.8lux csum\n", n, chksum);
+ exits(0);
+}
+
+static long
+unsqueezefd(int fd, void *v)
+{
+ uchar *wp, *out;
+ ulong toptxt, topdat;
+ long asis, nst, nsd;
+ Sqhdr sqh;
+ Exec ex;
+
+ out = (uchar*)v;
+ if(read(fd, &sqh, SQHDRLEN) != SQHDRLEN)
+ return -1;
+ if(GET4(sqh.magic) != SQMAGIC)
+ return -1;
+ if(read(fd, &ex, sizeof(Exec)) != sizeof(Exec))
+ return -1;
+ toptxt = GET4(sqh.toptxt);
+ topdat = GET4(sqh.topdat);
+ oldsum = GET4(sqh.sum);
+ asis = GET4(sqh.asis);
+ if(asis < 0)
+ asis = 0;
+ nst = GET4(sqh.text);
+ nsd = GET4(sqh.data);
+ switch(GET4((uchar*)&ex.magic)){
+ case Q_MAGIC:
+ if(qflag)
+ fprint(2, "PowerPC mode\n");
+ islittle = 0;
+ break;
+ case E_MAGIC:
+ case 0xA0E1: /* arm AIF */
+ islittle = 1;
+ qflag = 0;
+ break;
+ default:
+ fprint(2, "Unknown magic: %8.8ux\n", GET4((uchar*)&ex.magic));
+ qflag = 0;
+ break;
+ }
+ memmove(out, &ex, sizeof(ex));
+ wp = unsqzseg(fd, out + sizeof(ex), nst, toptxt);
+ if(wp == nil)
+ return -1;
+ wp = unsqzseg(fd, wp, nsd, topdat);
+ if(wp == nil)
+ return -1;
+ if(asis){
+ if(read(fd, wp, asis) != asis)
+ return -1;
+ wp += asis;
+ }
+ return wp-out;
+}
+
+static uchar*
+unsqzseg(int fd, uchar *wp, long ns, ulong top)
+{
+ Squeeze sq3, sq4;
+
+ if(ns == 0)
+ return wp;
+ if(rdtab(fd, &sq3, 0) < 0)
+ return nil;
+ if(rdtab(fd, &sq4, 8) < 0)
+ return nil;
+ fprint(2, "tables: %d %d\n", sq3.n, sq4.n);
+ if(read(fd, bigb, ns) != ns)
+ return nil;
+ return unsqueeze(wp, bigb, bigb+ns, &sq3, &sq4, top);
+}
+
+static uchar*
+unsqueeze(uchar *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top)
+{
+ ulong nx;
+ int code, n;
+
+ if(qflag){
+ QREMAP(top); /* adjust top just once, outside the loop */
+ }
+ while(rp < ep){
+ code = *rp++;
+ n = 0;
+ nx = code>>4;
+ do{
+ if(nx == 0){
+ nx = top;
+ }else{
+ if(nx==1){
+ if(rp+3 >= ep)
+ return nil;
+ nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0];
+ rp += 4;
+ }else if(nx <= 8){ /* 2 to 8 */
+ if(rp+1 >= ep)
+ return nil;
+ nx = ((nx-2)<<8) | rp[0];
+ if(CHECK && nx >= sq4->n)
+ return nil; /* corrupted file */
+ nx = sq4->tab[nx] | rp[1];
+ rp += 2;
+ }else{ /* 9 to 15 */
+ if(rp >= ep)
+ return nil; /* corrupted file */
+ nx = ((nx-9)<<8) | rp[0];
+ if(CHECK && nx >= sq3->n)
+ return nil; /* corrupted file */
+ nx = sq3->tab[nx];
+ rp++;
+ }
+ if(rp > ep)
+ return nil; /* corrupted file */
+ if(qflag){
+ QREMAP(nx);
+ }
+ }
+ if(islittle){
+ wp[0] = nx;
+ wp[1] = nx>>8;
+ wp[2] = nx>>16;
+ wp[3] = nx>>24;
+ }else{
+ wp[0] = nx>>24;
+ wp[1] = nx>>16;
+ wp[2] = nx>>8;
+ wp[3] = nx;
+ }
+ wp += 4;
+ chksum += nx;
+ nx = code & 0xF;
+ }while(++n == 1);
+ }
+ return wp;
+}
+
+static int
+rdtab(int fd, Squeeze *sq, int shift)
+{
+ uchar b[7*256*5], *p, *ep;
+ ulong v, w;
+ int i;
+
+ if(read(fd, b, 2) != 2)
+ return -1;
+ i = (b[0]<<8) | b[1];
+ if(1)
+ fprint(2, "table: %d\n", i);
+ if((i -= 2) > 0){
+ if(read(fd, b, i) != i)
+ return -1;
+ }
+ sq->n = 0;
+ p = b;
+ ep = b+i;
+ v = 0;
+ while(p < ep){
+ w = 0;
+ do{
+ if(p >= ep)
+ return -1;
+ w = (w<<7) | (*p & 0x7F);
+ }while(*p++ & 0x80);
+ v += w;
+ if(0)
+ fprint(2, "%d %8.8lux %8.8lux\n", sq->n, v, w);
+ sq->tab[sq->n++] = v << shift;
+ }
+ return 0;
+}
diff --git a/utils/srclist/Nt.c b/utils/srclist/Nt.c
new file mode 100644
index 00000000..b86b930d
--- /dev/null
+++ b/utils/srclist/Nt.c
@@ -0,0 +1,8 @@
+#include <windows.h>
+#include "lib9.h"
+
+char*
+mygetwd(char *path, int len)
+{
+ return getcwd(path, len);
+}
diff --git a/utils/srclist/Plan9.c b/utils/srclist/Plan9.c
new file mode 100644
index 00000000..31838bd4
--- /dev/null
+++ b/utils/srclist/Plan9.c
@@ -0,0 +1,7 @@
+#include "lib9.h"
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}
diff --git a/utils/srclist/Posix.c b/utils/srclist/Posix.c
new file mode 100644
index 00000000..ea5c842a
--- /dev/null
+++ b/utils/srclist/Posix.c
@@ -0,0 +1,10 @@
+#include "lib9.h"
+#undef getwd
+#undef getwd
+#include <unistd.h>
+
+char*
+mygetwd(char *path, int len)
+{
+ return getcwd(path, len);
+}
diff --git a/utils/srclist/mkfile b/utils/srclist/mkfile
new file mode 100644
index 00000000..a8c2a4d6
--- /dev/null
+++ b/utils/srclist/mkfile
@@ -0,0 +1,19 @@
+<../../mkconfig
+
+TARG=srclist
+
+OFILES= srclist.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ a.out.h\
+ bio.h\
+ mach.h\
+
+LIBS=mach bio 9 # order matters.
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/srclist/srclist.c b/utils/srclist/srclist.c
new file mode 100644
index 00000000..83b0f0ed
--- /dev/null
+++ b/utils/srclist/srclist.c
@@ -0,0 +1,144 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+
+int conly;
+int exists;
+
+enum {
+ Maxroot = 10,
+};
+
+int nroot;
+char *root[Maxroot];
+int rootlen[Maxroot];
+
+void usage(void);
+void error(char *);
+void addroot(char *);
+void addroots(char *);
+void chomp(char *);
+
+extern char *mygetwd(char*, int);
+
+void
+main(int argc, char **argv)
+{
+ char buf[1024], *cwd;
+
+ cwd = mygetwd(buf, sizeof(buf));
+ ARGBEGIN {
+ case 'c':
+ conly = 1;
+ break;
+ case 'e':
+ exists = 1;
+ break;
+ case 'r':
+ addroots(EARGF(usage()));
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if(argc != 1)
+ usage();
+
+ if(cwd != nil)
+ chdir(cwd);
+ setbinmode();
+ chomp(argv[0]);
+
+ exits(0);
+}
+
+void
+addroot(char *x)
+{
+ if(nroot >= Maxroot){
+ fprint(2, "srclist: too many root directories\n");
+ exits("usage");
+ }
+ root[nroot] = x;
+ rootlen[nroot] = strlen(x);
+ nroot++;
+}
+
+void
+addrootnt(char *r)
+{
+ addroot(r);
+ if(r[1] != ':')
+ return; /* phew! */
+ if(*r >= 'a' && *r <= 'z' || *r >= 'A' && *r <= 'Z')
+ addroot(r+2);
+}
+
+void
+addroots(char *r)
+{
+ char buf[1024], *r2;
+
+ addrootnt(r);
+ if(chdir(r) < 0)
+ return;
+ r2 = mygetwd(buf, sizeof(buf));
+ if(r2 && strcmp(r2, r) != 0)
+ addrootnt(r2);
+}
+
+void
+chomp(char *file)
+{
+ int fd, i, j, len;
+ Fhdr fhdr;
+ Dir *td;
+ char fname[1024];
+
+ fd = open(file, OREAD);
+ if(fd < 0)
+ error("open");
+
+ if(crackhdr(fd, &fhdr) == 0)
+ error("crackhdr");
+
+ if(syminit(fd, &fhdr) < 0)
+ error("syminit");
+
+ for(i = 0; i < 1000; i++)
+ if(filesym(i, fname, sizeof(fname)-1)){
+ cleanname(fname);
+ if(conly){
+ len = strlen(fname);
+ if(len < 2 || strcmp(fname+len-2, ".c") != 0)
+ continue;
+ }
+ if(exists){
+ if((td = dirstat(fname)) == nil)
+ continue;
+ free(td);
+ }
+ if(nroot){
+ for(j = 0; j < nroot; j++)
+ if(strncmp(fname, root[j], rootlen[j]) == 0)
+ break;
+ if(j == nroot)
+ continue;
+ }
+ print("%s\n", fname);
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: srclist [-ce] [-r root] <objfile>\n");
+ exits("usage");
+}
+
+void
+error(char *s)
+{
+ fprint(2, "srclist: %s: %r\n", s);
+ exits(s);
+}
diff --git a/utils/tc/5.out.h b/utils/tc/5.out.h
new file mode 100644
index 00000000..59aebab6
--- /dev/null
+++ b/utils/tc/5.out.h
@@ -0,0 +1,192 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 16
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+#define ALLTHUMBS (1<<2)
+
+#define REGRET 0
+#define REGARG 0
+/* compiler allocates R1 up as temps */
+/* compiler allocates register variables R3 up */
+#define REGEXT 6
+/* compiler allocates external registers R5 down */
+#define REGTMPT 7 /* used by the loader - thumb */
+#define REGTMP 11 /* used by the loader - arm */
+#define REGSB 12
+#define REGSP 13
+#define REGLINK 14
+#define REGPC 15
+
+#define NFREG 8
+#define FREGRET 0
+#define FREGEXT 7
+/* compiler allocates register variables F0 up */
+/* compiler allocates external registers F7 down */
+
+enum as
+{
+
+ AXXX,
+
+ AAND,
+ AEOR,
+ ASUB,
+ ARSB, // not used
+ AADD,
+ AADC,
+ ASBC,
+ ARSC, // not used
+ ATST,
+ ATEQ, // not used
+ ACMP,
+ ACMN,
+ AORR,
+ ABIC,
+
+ AMVN,
+
+ AB,
+ ABL,
+
+ /*
+ * Do not reorder or fragment the conditional branch
+ * opcodes, or the predication code will break
+ */
+
+ ABEQ,
+ ABNE,
+ ABCS,
+ ABHS,
+ ABCC,
+ ABLO,
+ ABMI,
+ ABPL,
+ ABVS,
+ ABVC,
+ ABHI,
+ ABLS,
+ ABGE,
+ ABLT,
+ ABGT,
+ ABLE,
+
+ AMOVWD,
+ AMOVWF,
+ AMOVDW,
+ AMOVFW,
+ AMOVFD,
+ AMOVDF,
+ AMOVF,
+ AMOVD,
+
+ ACMPF,
+ ACMPD,
+ AADDF,
+ AADDD,
+ ASUBF,
+ ASUBD,
+ AMULF,
+ AMULD,
+ ADIVF,
+ ADIVD,
+
+ ASRL, // right logical
+ ASRA, // right arithmetic
+ ASLL, // left logical = left arithmetic
+ AMULU,
+ ADIVU,
+ AMUL,
+ ADIV,
+ AMOD,
+ AMODU,
+
+ AMOVB,
+ AMOVBU,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMOVM,
+ ASWPBU, // not used
+ ASWPW, // not used
+
+ ANOP,
+ ARFE,
+ ASWI,
+ AMULA, // not used
+
+ ADATA,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ ANAME,
+ ARET, // fn return
+ ATEXT, // fn start
+ AWORD,
+ ADYNT, // not used
+ AINIT, // not used
+ ABCASE, // not used
+ ACASE, // not used
+
+ AEND,
+
+ AMULL,
+ AMULAL,
+ AMULLU,
+ AMULALU,
+
+ ABX,
+ ABXRET,
+
+ ADWORD,
+
+ ASIGNAME,
+
+ ALAST,
+
+};
+
+/* type/name */
+#define D_GOK 0
+#define D_NONE 1
+
+/* type */
+#define D_BRANCH (D_NONE+1)
+#define D_OREG (D_NONE+2)
+#define D_CONST (D_NONE+7)
+#define D_FCONST (D_NONE+8)
+#define D_SCONST (D_NONE+9)
+#define D_PSR (D_NONE+10)
+#define D_REG (D_NONE+12)
+#define D_FREG (D_NONE+13)
+#define D_FILE (D_NONE+16)
+#define D_OCONST (D_NONE+17)
+#define D_FILE1 (D_NONE+18)
+
+#define D_SHIFT (D_NONE+19) /* not used */
+#define D_FPCR (D_NONE+20)
+#define D_REGREG (D_NONE+21)
+
+/* name */
+#define D_EXTERN (D_NONE+3)
+#define D_STATIC (D_NONE+4)
+#define D_AUTO (D_NONE+5)
+#define D_PARAM (D_NONE+6)
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/tc/cgen.c b/utils/tc/cgen.c
new file mode 100644
index 00000000..1c1525c4
--- /dev/null
+++ b/utils/tc/cgen.c
@@ -0,0 +1,1234 @@
+#include "gc.h"
+
+static int
+commutes(int o)
+{
+ switch(o){
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLMUL:
+ case OMUL:
+ case OADD:
+ return 1;
+ }
+ return 0;
+}
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, t;
+ long v, curs;
+
+ if(debug['g'] && nn == Z) {
+ // prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED && l->complex < FNX) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case ODIV:
+ case OMOD:
+ if(nn != Z)
+ if((t = vlog(r)) >= 0 && t <= 8) {
+ /* signed div/mod by constant power of 2 */
+ cgen(l, nn);
+ gopcode(OGE, nodconst(0), nn, Z);
+ p1 = p;
+ if(o == ODIV) {
+ gopcode(OADD, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ gopcode(OASHR, nodconst(t), Z, nn);
+ } else {
+ gopcode(OSUB, nn, nodconst(0), nn);
+ regalloc(&nod, l, Z);
+ gopcode(OAS, nodconst((1<<t)-1), Z, &nod);
+ gopcode(OAND, &nod, Z, nn);
+ regfree(&nod);
+ // gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ gopcode(OSUB, nn, nodconst(0), nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ regalloc(&nod, l, Z);
+ gopcode(OAS, nodconst((1<<t)-1), Z, &nod);
+ gopcode(OAND, &nod, Z, nn);
+ regfree(&nod);
+ // gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ }
+ break;
+ }
+ goto muldiv;
+
+ case OADD:
+ case OSUB:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(sconst(r))
+ if(o == OADD || o == OSUB || r->vconst < (vlong)32) {
+ // if(r->op == OCONST)
+ // if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ break;
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ muldiv:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ if(o == OADD || o == OSUB) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ else {
+ if(commutes(o)){
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ }
+ else{
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ }
+ }
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+/*
+ case ONEG:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, Z, &nod);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+*/
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASADD:
+ case OASSUB:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(sconst(r))
+ if(o == OASADD || o == OASSUB || r->vconst < (vlong)32) {
+ // if(r->op == OCONST)
+ // if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASAND:
+ case OASXOR:
+ case OASOR:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ } else {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+
+ regalloc(&nod, n, nn);
+ gmove(&nod2, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(o, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ if(REGARG >= 0)
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG >= 0)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r) && (v = r->vconst+nod.xoffset) >= 0 && v < 32*r->type->width/SZ_LONG) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type)) {
+ if(nocast(n->type, nn->type)) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else {
+ if (v > 0 && v < 8)
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ else if (v < 0 && v > -8)
+ gopcode(OSUB, nodconst(-v), &nod, &nod1);
+ else {
+ regalloc(&nod3, l, Z);
+ gopcode(OAS, nodconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ regfree(&nod3);
+ }
+ }
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else {
+ if (v > 0 && v < 256)
+ gopcode(OADD, nodconst(v), Z, &nod);
+ else if (v < 0 && v > -256)
+ gopcode(OSUB, nodconst(-v), Z, &nod);
+ else {
+ regalloc(&nod3, l, Z);
+ gopcode(OAS, nodconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod);
+ regfree(&nod3);
+ }
+ }
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ if (v > 0 && v < 256)
+ gopcode(OADD, nodconst(v), Z, &nod);
+ else if (v < 0 && v > -256)
+ gopcode(OSUB, nodconst(-v), Z, &nod);
+ else {
+ regalloc(&nod3, l, Z);
+ gopcode(OAS, nodconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod);
+ regfree(&nod3);
+ }
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ if (v > 0 && v < 256)
+ gopcode(OADD, nodconst(v), Z, &nod);
+ else if (v < 0 && v > -256)
+ gopcode(OSUB, nodconst(-v), Z, &nod);
+ else {
+ regalloc(&nod3, l, Z);
+ gopcode(OAS, nodconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod);
+ regfree(&nod3);
+ }
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+ return;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r) && (v = r->vconst+t->xoffset) >= 0 && v < 32*n->type->width/SZ_LONG) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ } else if(n->op == OINDREG) {
+ if((v = n->xoffset) >= 0 && v < (n->reg == REGSP ? 256 : 32)*n->type->width/SZ_LONG) {
+ n->op = OREGISTER;
+ cgen(n, t);
+ t->xoffset += v;
+ n->op = OINDREG;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+reglpcgen(Node *n, Node *nn, int f)
+{
+ Type *t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ if(f)
+ reglcgen(n, nn, Z);
+ else {
+ regialloc(n, nn, Z);
+ lcgen(nn, n);
+ regind(n, nn);
+ }
+ nn->type = t;
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ gopcode(o, nodfconst(0), &nod, Z);
+ } else
+ gopcode(o, nodconst(0), &nod, Z);
+ regfree(&nod);
+ goto com;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(sconst(l)) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ o = invrel[relindex(o)];
+ gopcode(o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(sconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, r, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod, &nod1, Z);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && nn->complex >= FNX) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 2) {
+ if(n->complex > nn->complex) {
+ reglpcgen(&nod1, n, 1);
+ reglpcgen(&nod2, nn, 1);
+ } else {
+ reglpcgen(&nod2, nn, 1);
+ reglpcgen(&nod1, n, 1);
+ }
+ regalloc(&nod3, &regnode, Z);
+ regalloc(&nod4, &regnode, Z);
+ nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg));
+ if(w == 2 && nod1.xoffset == 0)
+ gmovm(&nod1, &nod0);
+ else {
+ gmove(&nod1, &nod3);
+ if(w == 2) {
+ nod1.xoffset += SZ_LONG;
+ gmove(&nod1, &nod4);
+ }
+ }
+ if(w == 2 && nod2.xoffset == 0)
+ gmovm(&nod0, &nod2);
+ else {
+ gmove(&nod3, &nod2);
+ if(w == 2) {
+ nod2.xoffset += SZ_LONG;
+ gmove(&nod4, &nod2);
+ }
+ }
+ regfree(&nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ regfree(&nod4);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ reglpcgen(&nod1, n, 0);
+ reglpcgen(&nod2, nn, 0);
+ } else {
+ reglpcgen(&nod2, nn, 0);
+ reglpcgen(&nod1, n, 0);
+ }
+
+ m = 0;
+ for(c = 0; c < w && c < 3; c++) {
+ i = tmpreg();
+ if (i == 0)
+ break;
+ reg[i]++;
+ m |= 1<<i;
+ }
+ nod4 = *(nodconst(m));
+ if(w < 3*c) {
+ for (; w>c; w-=c) {
+ gmovm(&nod1, &nod4);
+ gmovm(&nod4, &nod2);
+ }
+ goto out;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ gopcode(OAS, nodconst(w/c), Z, &nod3);
+ w %= c;
+
+ pc1 = pc;
+ gmovm(&nod1, &nod4);
+ gmovm(&nod4, &nod2);
+
+ gopcode(OSUB, nodconst(1), Z, &nod3);
+ gopcode(OEQ, nodconst(0), &nod3, Z);
+ p->as = ABGT;
+ patch(p, pc1);
+ regfree(&nod3);
+
+out:
+ if (w) {
+ i = 0;
+ while (c>w) {
+ while ((m&(1<<i)) == 0)
+ i++;
+ m &= ~(1<<i);
+ reg[i] = 0;
+ c--;
+ i++;
+ }
+ nod4.vconst = m;
+ gmovm(&nod1, &nod4);
+ gmovm(&nod4, &nod2);
+ }
+ i = 0;
+ do {
+ while ((m&(1<<i)) == 0)
+ i++;
+ reg[i] = 0;
+ c--;
+ i++;
+ } while (c>0);
+ regfree(&nod1);
+ regfree(&nod2);
+}
diff --git a/utils/tc/enam.c b/utils/tc/enam.c
new file mode 100644
index 00000000..b4a5fbe6
--- /dev/null
+++ b/utils/tc/enam.c
@@ -0,0 +1,98 @@
+char* anames[] =
+{
+ "XXX",
+ "AND",
+ "EOR",
+ "SUB",
+ "RSB",
+ "ADD",
+ "ADC",
+ "SBC",
+ "RSC",
+ "TST",
+ "TEQ",
+ "CMP",
+ "CMN",
+ "ORR",
+ "BIC",
+ "MVN",
+ "B",
+ "BL",
+ "BEQ",
+ "BNE",
+ "BCS",
+ "BHS",
+ "BCC",
+ "BLO",
+ "BMI",
+ "BPL",
+ "BVS",
+ "BVC",
+ "BHI",
+ "BLS",
+ "BGE",
+ "BLT",
+ "BGT",
+ "BLE",
+ "MOVWD",
+ "MOVWF",
+ "MOVDW",
+ "MOVFW",
+ "MOVFD",
+ "MOVDF",
+ "MOVF",
+ "MOVD",
+ "CMPF",
+ "CMPD",
+ "ADDF",
+ "ADDD",
+ "SUBF",
+ "SUBD",
+ "MULF",
+ "MULD",
+ "DIVF",
+ "DIVD",
+ "SRL",
+ "SRA",
+ "SLL",
+ "MULU",
+ "DIVU",
+ "MUL",
+ "DIV",
+ "MOD",
+ "MODU",
+ "MOVB",
+ "MOVBU",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MOVM",
+ "SWPBU",
+ "SWPW",
+ "NOP",
+ "RFE",
+ "SWI",
+ "MULA",
+ "DATA",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "NAME",
+ "RET",
+ "TEXT",
+ "WORD",
+ "DYNT",
+ "INIT",
+ "ABCASE",
+ "ACASE",
+ "END",
+ "MULL",
+ "MULAL",
+ "MULLU",
+ "MULALU",
+ "BX",
+ "BX",
+ "DWORD",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/tc/gc.h b/utils/tc/gc.h
new file mode 100644
index 00000000..e61a1967
--- /dev/null
+++ b/utils/tc/gc.h
@@ -0,0 +1,349 @@
+#include "../cc/cc.h"
+#include "../tc/5.out.h"
+
+/*
+ * 5ct/Thumb
+ * Arm 7500
+ * Thumb
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+
+#define R0ISZERO 0
+
+struct Adr
+{
+ long offset;
+ double dval;
+ char sval[NSNAME];
+ Ieee ieee;
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ char as;
+ char reg;
+ uchar scond; /* not used in 5ct */
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN Multab multab[20];
+EXTERN int retok;
+EXTERN int hintabsize;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN char reg[NREG+NFREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+EXTERN int suppress;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 4
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+int bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+int tmpreg(void);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmovm(Node*, Node*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+void gopcode2(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+int sval(long);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+int Rconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+void constprop(Adr*, Adr*, Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+void predicate(void);
+int isbranch(Prog *);
+int predicable(Prog *p);
+int modifiescpsr(Prog *p);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "R" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/utils/tc/list.c b/utils/tc/list.c
new file mode 100644
index 00000000..1078423e
--- /dev/null
+++ b/utils/tc/list.c
@@ -0,0 +1,276 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ if(a == AMOVM) {
+ if(p->from.type == D_CONST)
+ sprint(str, " %A %R,%D", a, &p->from, &p->to);
+ else
+ if(p->to.type == D_CONST)
+ sprint(str, " %A %D,%R", a, &p->from, &p->to);
+ else
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ } else
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_EXTERN:
+ case D_STATIC:
+ sprint(str, "%N", a);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ sprint(str, "PSR");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(PSR)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ int i, v;
+
+ a = va_arg(fp->args, Adr*);
+ sprint(str, "GOK-reglist");
+ switch(a->type) {
+ case D_CONST:
+ if(a->reg != NREG)
+ break;
+ if(a->sym != S)
+ break;
+ v = a->offset;
+ strcpy(str, "");
+ for(i=0; i<NREG; i++) {
+ if(v & (1<<i)) {
+ if(str[0] == 0)
+ strcat(str, "[R");
+ else
+ strcat(str, ",R");
+ sprint(strchr(str, 0), "%d", i);
+ }
+ }
+ strcat(str, "]");
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/tc/mkenam b/utils/tc/mkenam
new file mode 100644
index 00000000..7cd23551
--- /dev/null
+++ b/utils/tc/mkenam
@@ -0,0 +1,15 @@
+ed - ../5ct/5.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/tc/mkfile b/utils/tc/mkfile
new file mode 100644
index 00000000..60863925
--- /dev/null
+++ b/utils/tc/mkfile
@@ -0,0 +1,28 @@
+<../../mkconfig
+
+TARG=tc
+
+OFILES= cgen.$O\
+ enam.$O\
+ list.$O\
+ mul.$O\
+ peep.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+
+HFILES= gc.h\
+ 5.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/tc/mul.c b/utils/tc/mul.c
new file mode 100644
index 00000000..67370a62
--- /dev/null
+++ b/utils/tc/mul.c
@@ -0,0 +1,609 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int maxmulops = 3; /* max # of ops to replace mul with */
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=maxmulops; g++) {
+ if(g >= maxmulops && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/utils/tc/peep.c b/utils/tc/peep.c
new file mode 100644
index 00000000..2842b3e3
--- /dev/null
+++ b/utils/tc/peep.c
@@ -0,0 +1,759 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
+ if(regtyp(&p->to)) {
+ if(p->from.type == D_CONST)
+ constprop(&p->from, &p->to, r->s1);
+ else if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AEOR:
+ /*
+ * EOR -1,x,y => MVN x,y
+ */
+ if(p->from.type == D_CONST && p->from.offset == -1) {
+ p->as = AMVN;
+ p->from.type = D_REG;
+ if(p->reg != NREG)
+ p->from.reg = p->reg;
+ else
+ p->from.reg = p->to.reg;
+ p->reg = NREG;
+ }
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG)
+ return 1;
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ABL:
+ case ABX:
+ return 0;
+
+ // case ACMP:
+ // case ACMN:
+ case AADD:
+ case ASUB:
+ // case ASLL:
+ // case ASRL:
+ // case ASRA:
+ // case AORR:
+ // case AAND:
+ // case AEOR:
+ // case AMUL:
+ // case ADIV:
+ // case ADIVU:
+
+ // case ACMPF:
+ // case ACMPD:
+ // case AADDD:
+ // case AADDF:
+ // case ASUBD:
+ // case ASUBF:
+ // case AMULD:
+ // case AMULF:
+ // case ADIVD:
+ // case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+
+ case AMOVM:
+ t = 1<<v2->reg;
+ if((p->from.type == D_CONST && (p->from.offset&t)) ||
+ (p->to.type == D_CONST && (p->to.offset&t)))
+ return 0;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant constants.
+ * $c1->v1
+ * ($c1->v2 s/$c1/v1)*
+ * set v1 return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+void
+constprop(Adr *c1, Adr *v1, Reg *r)
+{
+ Prog *p;
+
+ if(debug['C'])
+ print("constprop %D->%D\n", c1, v1);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['C'])
+ print("%P", p);
+ if(uniqp(r) == R) {
+ if(debug['C'])
+ print("; merge; return\n");
+ return;
+ }
+ if(p->as == AMOVW && copyas(&p->from, c1)) {
+ if(debug['C'])
+ print("; sub%D/%D", &p->from, v1);
+ p->from = *v1;
+ } else if(copyu(p, v1, A) > 1) {
+ if(debug['C'])
+ print("; %Dset; return\n", v1);
+ return;
+ }
+ if(debug['C'])
+ print("\n");
+ if(r->s2)
+ constprop(c1, v1, r->s2);
+ }
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+ case AMOVM:
+ if(v->type != D_REG)
+ return 0;
+ if(p->from.type == D_CONST) { /* read reglist, read/rar */
+ if(s != A) {
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->to, v, s, 1))
+ diag(Z, "movm dst being replaced"); // was return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 2; // register updated in thumb // was return 1;
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ } else { /* read/rar, write reglist */
+ if(s != A) {
+ if(p->to.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->from, v, s, 1))
+ diag(Z, "movm src being replaced"); // was return 1;
+ return 0;
+ }
+ if(copyau(&p->from, v)) {
+ // if(p->to.offset&(1<<v->reg))
+ // return 4;
+ return 2; // register updated in thumb // was return 1;
+ }
+ if(p->to.offset&(1<<v->reg))
+ return 3;
+ }
+ return 0;
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFD:
+ case AMOVDF:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case ACMPF:
+ case ACMPD:
+ case ACMP:
+ case ACMN:
+ if(copyas(&p->to, v))
+ return 2;
+ /*FALLTHROUGH*/
+
+ case AADD: /* read, read, write */
+ case ASUB:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AB: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case ABL: /* funny */
+ case ABX:
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+
+ case ACMP:
+ case ACMN:
+
+ case AADD:
+ case ASUB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ return D_REG;
+
+ case ACMPF:
+ case ACMPD:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ } else if(v->type == D_CONST) { /* for constprop */
+ if(a->type == v->type)
+ if(a->name == v->name)
+ if(a->sym == v->sym)
+ if(a->reg == v->reg)
+ if(a->offset == v->offset)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG) {
+ if(a->type == D_OREG) {
+ if(v->reg == a->reg)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a2type(p) == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v)) {
+ a->reg = s->reg;
+ }
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
diff --git a/utils/tc/reg.c b/utils/tc/reg.c
new file mode 100644
index 00000000..54bc76a7
--- /dev/null
+++ b/utils/tc/reg.c
@@ -0,0 +1,1161 @@
+#include "gc.h"
+
+void addsplits(void);
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AB:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ case ABX:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ if(p->as == AMOVM) {
+ if(p->from.type == D_CONST)
+ z = p->from.offset;
+ else
+ z = p->to.offset;
+ for(i=0; z; i++) {
+ if(z&1)
+ regbits |= RtoB(i);
+ z >>= 1;
+ }
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] && debug['v']) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%B", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%B", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%B", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%B", r->calbehind);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == ABL || r->prog->as == ABX)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABL:
+ case ABX:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TVLONG:
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R0
+ * 1 R1
+ * ... ...
+ * 10 R10
+ */
+long
+RtoB(int r)
+{
+
+ if(r < 2 || r >= REGTMPT)
+ return 0;
+ return 1L << r;
+}
+
+int
+BtoR(long b)
+{
+
+ b &= 0x7cL; // r2-r6
+ if(b == 0)
+ return 0;
+ return bitno(b);
+}
+
+/*
+ * bit reg
+ * 18 F2
+ * 19 F3
+ * ... ...
+ * 23 F7
+ */
+long
+FtoB(int f)
+{
+
+ if(f < 2 || f > NFREG-1)
+ return 0;
+ return 1L << (f + 16);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0xfc0000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16;
+}
diff --git a/utils/tc/sgen.c b/utils/tc/sgen.c
new file mode 100644
index 00000000..d76de7de
--- /dev/null
+++ b/utils/tc/sgen.c
@@ -0,0 +1,667 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+ sp->reg |= ALLTHUMBS; /* denotes thumb code */
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG >= 0) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ }
+ }
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int o, f;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ supgen(n->right->left);
+ gen(n->right->right);
+ }
+ else {
+ gen(n->right->left);
+ supgen(n->right->right);
+ }
+ }
+ else {
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+/*
+ case OSUB:
+ xcom(l);
+ xcom(r);
+ if(typefd[n->type->etype] || typev[n->type->etype])
+ break;
+ if(vconst(l) == 0)
+ n->op = ONEG;
+ n->left = l;
+ n->right = Z;
+ }
+ break;
+*/
+
+ case OASHL:
+ case OASHR:
+ case OLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ xcom(l);
+ xcom(r);
+ if(sconst(r) && r->vconst < 0){
+ r->vconst = -r->vconst;
+ switch(n->op){
+ case OASHL: n->op = OASHR; break;
+ case OASHR: n->op = OASHL; break;
+ case OLSHR: n->op = OASHL; break;
+ case OASASHL: n->op = OASASHR; break;
+ case OASASHR: n->op = OASASHL; break;
+ case OASLSHR: n->op = OASASHL; break;
+ }
+ }
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ t = vlog(l);
+ if(t >= 0) {
+ n->op = OASHL;
+ n->left = r;
+ n->right = l;
+ r = l;
+ l = n->left;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ case OEQ:
+ case ONE:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+ return 0;
+}
diff --git a/utils/tc/swt.c b/utils/tc/swt.c
new file mode 100644
index 00000000..1ded1e5c
--- /dev/null
+++ b/utils/tc/swt.c
@@ -0,0 +1,717 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8lux\n", i, iq[i].val);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ swit1(iq, nc, def, n);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8lux\n", q->val);
+ gopcode(OEQ, nodconst(q->val), n, Z);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8lux\n", r->val);
+ gopcode(OGT, nodconst(r->val), n, Z);
+ sp = p;
+ gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8lux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode2(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode2(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode2(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v, vs;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ if(debug['M'] && debug['v'])
+ print("%L multiply: %ld\n", n->lineno, v);
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ vs = v;
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ if(vs < 0) {
+ gopcode(OAS, &nod1, Z, &nod1);
+ gopcode(OSUB, &nod1, nodconst(0), nn);
+ } else
+ gopcode(OAS, &nod1, Z, nn);
+/*
+ if(vs < 0)
+ gopcode(ONEG, &nod1, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+*/
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+
+ if(a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o;
+ p->reg = 4;
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+
+ bf[0] = p->as;
+ bf[1] = 14;
+ bf[2] = p->reg;
+ bf[3] = p->lineno;
+ bf[4] = p->lineno>>8;
+ bf[5] = p->lineno>>16;
+ bf[6] = p->lineno>>24;
+ bp = zaddr(bf+7, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ ulong sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ long l;
+ Ieee e;
+
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ }
+ return bp;
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael2);
+ o = align(o, t, Ael1);
+ w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v = round(v, SZ_LONG);
+ if(v > max)
+ return v;
+ return max;
+}
diff --git a/utils/tc/txt.c b/utils/tc/txt.c
new file mode 100644
index 00000000..7f186bd4
--- /dev/null
+++ b/utils/tc/txt.c
@@ -0,0 +1,1199 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ Type *t;
+
+ thechar = 't';
+ thestring = "arm";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMPT;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ memset(reg, 0, sizeof(reg));
+ // reg[REGTMPT] = 1;
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(reg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NFREG; i++)
+ if(reg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesuv[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+int
+tmpreg(void)
+{
+ int i;
+
+ for(i=REGRET+1; i<NREG; i++)
+ if(reg[i] == 0)
+ return i;
+ diag(Z, "out of fixed tmp registers");
+ return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<REGTMPT; i++) {
+ if(j >= REGTMPT)
+ j = REGRET+1;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NFREG)
+ goto out;
+ }
+ j = 0*2 + NREG;
+ for(i=NREG; i<NREG+NFREG; i++) {
+ if(j >= NREG+NFREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ nodreg(n, tn, 0);
+ return;
+out:
+ reg[i]++;
+/* lasti++; *** StrongARM does register forwarding */
+/*
+ if(lasti >= 5)
+ lasti = 0;
+*/
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_LONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+gmovm(Node *f, Node *t)
+{
+ gins(AMOVM, f, t); // always sets base register now
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod;
+
+// prtree(f, "gmove src");
+// prtree(t, "gmove dst");
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ }
+
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ a = AMOVW;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ }
+ if(typechlp[ft] && typeilp[tt])
+ regalloc(&nod, t, t);
+ else
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TVLONG:
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ a = AMOVD;
+ if(ft == TFLOAT)
+ a = AMOVFD;
+ break;
+ case TFLOAT:
+ a = AMOVDF;
+ if(ft == TFLOAT)
+ a = AMOVF;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVDW;
+ if(ft == TFLOAT)
+ a = AMOVFW;
+ break;
+ }
+ break;
+ case TUINT:
+ case TINT:
+ case TULONG:
+ case TLONG:
+ case TIND:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ gins(AMOVWD, f, t);
+ if(ft == TULONG) {
+ }
+ return;
+ case TFLOAT:
+ gins(AMOVWF, f, t);
+ if(ft == TULONG) {
+ }
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TUINT:
+ case TINT:
+ case TULONG:
+ case TLONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVWD, &nod, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVWF, &nod, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AMOVF || a == AMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et;
+ Adr ta;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADD;
+ if(et == TFLOAT)
+ a = AADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUB;
+ if(et == TFLOAT)
+ a = ASUBF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ASUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AEOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ break;
+
+ case OFUNC:
+ a = ABL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ a = AMUL;
+ if(et == TFLOAT)
+ a = AMULF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AMULD;
+ break;
+
+ case OASDIV:
+ case ODIV:
+ a = ADIV;
+ if(et == TFLOAT)
+ a = ADIVF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ADIVD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ a = AMOD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULU;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ a = AMODU;
+ break;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVU;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMP;
+ if(et == TFLOAT)
+ a = ACMPF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ACMPD;
+ nextpc();
+ p->as = a;
+ naddr(f1, &p->from);
+/*
+ if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
+ p->as = ACMN;
+ p->from.offset = -p->from.offset;
+ }
+*/
+ raddr(f2, p); // expects it to be a register
+ switch(o) {
+ case OEQ:
+ a = ABEQ;
+ break;
+ case ONE:
+ a = ABNE;
+ break;
+ case OLT:
+ a = ABLT;
+ break;
+ case OLE:
+ a = ABLE;
+ break;
+ case OGE:
+ a = ABGE;
+ break;
+ case OGT:
+ a = ABGT;
+ break;
+ case OLO:
+ a = ABLO;
+ break;
+ case OLS:
+ a = ABLS;
+ break;
+ case OHS:
+ a = ABHS;
+ break;
+ case OHI:
+ a = ABHI;
+ break;
+ }
+ f1 = Z;
+ f2 = Z;
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+/* put f1 in a register first */
+void
+gopcode2(int o, Node *f1, Node *f2, Node *t)
+{
+ Node nod;
+
+ if(f2 != Z)
+ diag(Z, "bad parameter in gopcode2");
+ // regalloc(&nod, t, Z);
+ nodreg(&nod, t, REGTMPT);
+ gopcode(OAS, f1, Z, &nod);
+ gopcode(o, &nod, Z, t);
+ // regfree(&nod);
+}
+
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AB;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ if(a == ATEXT)
+ p->reg = (profileflg ? 0 : NOPROF);
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= (vlong)0 && vv < (vlong)256)
+ return 1;
+ /*
+ * should be specialised for constant values which will
+ * fit in different instructionsl; for now, let 5l
+ * sort it out
+ */
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+sval(long v)
+{
+ if(v >= -32768 && v < 32768)
+ return 1;
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= NREG-1)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= NFREG-1)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/test/mkfile b/utils/test/mkfile
new file mode 100644
index 00000000..4bd74e15
--- /dev/null
+++ b/utils/test/mkfile
@@ -0,0 +1,21 @@
+<../../mkconfig
+
+#
+# the test command is only needed on Windows NT and Windows 95
+#
+
+TARG=test
+
+OFILES= test-$TARGMODEL.$O\
+
+HFILES=
+
+LIBS=9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+test-Posix.c test-Inferno.c:QV:
+ echo 'test is only built on Windows NT or Windows 95'
+ exit 1
diff --git a/utils/test/test-Nt.c b/utils/test/test-Nt.c
new file mode 100644
index 00000000..7d2a9fa7
--- /dev/null
+++ b/utils/test/test-Nt.c
@@ -0,0 +1,278 @@
+/*
+ * POSIX standard
+ * test expression
+ * [ expression ]
+ */
+
+#include <lib9.h>
+#include <windows.h>
+
+#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))
+
+int ap;
+int ac;
+char **av;
+char *tmp;
+
+void synbad(char *, char *);
+int length(char *);
+int fsizep(char *);
+int isdir(char *);
+int isreg(char *);
+int Ntisatty(int);
+int isint(char *, int *);
+int tio(char *, int);
+int e(void), e1(void), e2(void), e3(void);
+
+void
+main(int argc, char *argv[])
+{
+
+ ac = argc; av = argv; ap = 1;
+ if(EQ(argv[0],"[")) {
+ if(!EQ(argv[--ac],"]"))
+ synbad("] missing","");
+ }
+ argv[ac] = 0;
+ if (ac<=1) exits("usage");
+ exits(e()?0:"false");
+}
+
+char *
+nxtarg(int mt)
+{
+ if(ap>=ac){
+ if(mt){
+ ap++;
+ return(0);
+ }
+ synbad("argument expected","");
+ }
+ return(av[ap++]);
+}
+
+int
+nxtintarg(int *pans)
+{
+ if(ap<ac && isint(av[ap], pans)){
+ ap++;
+ return 1;
+ }
+ return 0;
+}
+
+int
+e(void) {
+ int p1;
+
+ p1 = e1();
+ if (EQ(nxtarg(1), "-o")) return(p1 || e());
+ ap--;
+ return(p1);
+}
+
+int
+e1(void) {
+ int p1;
+
+ p1 = e2();
+ if (EQ(nxtarg(1), "-a")) return (p1 && e1());
+ ap--;
+ return(p1);
+}
+
+int
+e2(void) {
+ if (EQ(nxtarg(0), "!"))
+ return(!e2());
+ ap--;
+ return(e3());
+}
+
+int
+e3(void) {
+ int p1;
+ char *a;
+ char *p2;
+ int int1, int2;
+
+ a = nxtarg(0);
+ if(EQ(a, "(")) {
+ p1 = e();
+ if(!EQ(nxtarg(0), ")")) synbad(") expected","");
+ return(p1);
+ }
+
+ if(EQ(a, "-f"))
+ return(isreg(nxtarg(0)));
+
+ if(EQ(a, "-d"))
+ return(isdir(nxtarg(0)));
+
+ if(EQ(a, "-r"))
+ return(tio(nxtarg(0), 4));
+
+ if(EQ(a, "-w"))
+ return(tio(nxtarg(0), 2));
+
+ if(EQ(a, "-x"))
+ return(tio(nxtarg(0), 1));
+
+ if(EQ(a, "-e"))
+ return(tio(nxtarg(0), 0));
+
+ if(EQ(a, "-c"))
+ return(0);
+
+ if(EQ(a, "-b"))
+ return(0);
+
+ if(EQ(a, "-u"))
+ return(0);
+
+ if(EQ(a, "-g"))
+ return(0);
+
+ if(EQ(a, "-s"))
+ return(fsizep(nxtarg(0)));
+
+ if(EQ(a, "-t"))
+ if(ap>=ac || !nxtintarg(&int1))
+ return(Ntisatty(1));
+ else
+ return(Ntisatty(int1));
+
+ if(EQ(a, "-n"))
+ return(!EQ(nxtarg(0), ""));
+ if(EQ(a, "-z"))
+ return(EQ(nxtarg(0), ""));
+
+ p2 = nxtarg(1);
+ if (p2==0)
+ return(!EQ(a,""));
+ if(EQ(p2, "="))
+ return(EQ(nxtarg(0), a));
+
+ if(EQ(p2, "!="))
+ return(!EQ(nxtarg(0), a));
+
+ if(!isint(a, &int1))
+ return(!EQ(a,""));
+
+ if(nxtintarg(&int2)){
+ if(EQ(p2, "-eq"))
+ return(int1==int2);
+ if(EQ(p2, "-ne"))
+ return(int1!=int2);
+ if(EQ(p2, "-gt"))
+ return(int1>int2);
+ if(EQ(p2, "-lt"))
+ return(int1<int2);
+ if(EQ(p2, "-ge"))
+ return(int1>=int2);
+ if(EQ(p2, "-le"))
+ return(int1<=int2);
+ }
+
+ synbad("unknown operator ",p2);
+ return 0; /* to shut ken up */
+}
+
+int
+tio(char *a, int f)
+{
+ return access (a, f) >= 0;
+}
+
+/*
+ * dirstat fails for:
+ * [drivename]:
+ * [drivename]:/
+ * <dirname>/
+ * [drivename]:<dirname>/
+ */
+int
+isdir(char *f)
+{
+ Dir *dir;
+ int len;
+
+ len = strlen(f);
+ if (f[(len-1)] == '/') {
+ /* zap trailing '/' */
+ f[(len-1)] = '\0';
+ }
+ if (len == 2) {
+ if (f[1] == ':') {
+ return DMDIR;
+ }
+ }
+ if((dir = dirstat(f))==nil)
+ return(0);
+ return(dir->mode&DMDIR);
+}
+
+int
+isreg(char *f)
+{
+ Dir *dir;
+
+ if((dir = dirstat(f))==nil)
+ return(0);
+ return(!(dir->mode&DMDIR));
+}
+
+int
+Ntisatty(int fd)
+{
+ HANDLE h;
+
+ if(fd < 0)
+ return 0;
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if(h < 0)
+ return 0;
+ return _isatty((int)h);
+}
+
+int
+fsizep(char *f)
+{
+ Dir *dir;
+
+ if((dir = dirstat(f))==nil)
+ return(0);
+ return(dir->length>0);
+}
+
+void
+synbad(char *s1, char *s2)
+{
+ int len;
+
+ write(2, "test: ", 6);
+ if ((len = strlen(s1)) != 0)
+ write(2, s1, len);
+ if ((len = strlen(s2)) != 0)
+ write(2, s2, len);
+ write(2, "\n", 1);
+ exits("bad syntax");
+}
+
+int
+length(char *s)
+{
+ char *es=s;
+ while(*es++);
+ return(es-s-1);
+}
+
+int
+isint(char *s, int *pans)
+{
+ char *ep;
+
+ *pans = strtol(s, &ep, 0);
+ return (*ep == 0);
+}
diff --git a/utils/tr/mkfile b/utils/tr/mkfile
new file mode 100644
index 00000000..410f7a3a
--- /dev/null
+++ b/utils/tr/mkfile
@@ -0,0 +1,13 @@
+<../../mkconfig
+
+TARG=tr
+
+OFILES= tr.$O\
+
+HFILES=
+
+LIBS=9 # libbio.a uses lib9.a so order matters.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
diff --git a/utils/tr/tr.c b/utils/tr/tr.c
new file mode 100644
index 00000000..65243103
--- /dev/null
+++ b/utils/tr/tr.c
@@ -0,0 +1,355 @@
+#include <lib9.h>
+
+typedef struct PCB /* Control block controlling specification parse */
+{
+ char *base; /* start of specification */
+ char *current; /* current parse point */
+ long last; /* last Rune returned */
+ long final; /* final Rune in a span */
+} Pcb;
+
+uchar bits[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+#define SETBIT(a, c) ((a)[(c)/8] |= bits[(c)&07])
+#define CLEARBIT(a,c) ((a)[(c)/8] &= ~bits[(c)&07])
+#define BITSET(a,c) ((a)[(c)/8] & bits[(c)&07])
+
+#define MAXRUNE 0xFFFF
+
+uchar f[(MAXRUNE+1)/8];
+uchar t[(MAXRUNE+1)/8];
+char wbuf[4096];
+char *wptr;
+
+Pcb pfrom, pto;
+
+int cflag;
+int dflag;
+int sflag;
+
+void complement(void);
+void delete(void);
+void squeeze(void);
+void translit(void);
+void error(char*);
+long canon(Pcb*);
+char *getrune(char*, Rune*);
+void Pinit(Pcb*, char*);
+void Prewind(Pcb *p);
+int readrune(int, long*);
+void wflush(int);
+void writerune(int, Rune);
+
+void
+main(int argc, char **argv)
+{
+ ARGBEGIN{
+ case 's': sflag++; break;
+ case 'd': dflag++; break;
+ case 'c': cflag++; break;
+ default: error("bad option");
+ }ARGEND
+ if(argc>0)
+ Pinit(&pfrom, argv[0]);
+ if(argc>1)
+ Pinit(&pto, argv[1]);
+ if(argc>2)
+ error("arg count");
+ if(dflag) {
+ if ((sflag && argc != 2) || (!sflag && argc != 1))
+ error("arg count");
+ delete();
+ } else {
+ if (argc != 2)
+ error("arg count");
+ if (cflag)
+ complement();
+ else translit();
+ }
+ exits(0);
+}
+
+void
+delete(void)
+{
+ long c, last;
+
+ if (cflag) {
+ memset((char *) f, 0xff, sizeof f);
+ while ((c = canon(&pfrom)) >= 0)
+ CLEARBIT(f, c);
+ } else {
+ while ((c = canon(&pfrom)) >= 0)
+ SETBIT(f, c);
+ }
+ if (sflag) {
+ while ((c = canon(&pto)) >= 0)
+ SETBIT(t, c);
+ }
+
+ last = 0x10000;
+ while (readrune(0, &c) > 0) {
+ if(!BITSET(f, c) && (c != last || !BITSET(t,c))) {
+ last = c;
+ writerune(1, (Rune) c);
+ }
+ }
+ wflush(1);
+}
+
+void
+complement(void)
+{
+ Rune *p;
+ int i;
+ long from, to, lastc, high;
+
+ lastc = 0;
+ high = 0;
+ while ((from = canon(&pfrom)) >= 0) {
+ if (from > high) high = from;
+ SETBIT(f, from);
+ }
+ while ((to = canon(&pto)) > 0) {
+ if (to > high) high = to;
+ SETBIT(t,to);
+ }
+ Prewind(&pto);
+ if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
+ error("can't allocate memory");
+ for (i = 0; i <= high; i++){
+ if (!BITSET(f,i)) {
+ if ((to = canon(&pto)) < 0)
+ to = lastc;
+ else lastc = to;
+ p[i] = to;
+ }
+ else p[i] = i;
+ }
+ if (sflag){
+ lastc = 0x10000;
+ while (readrune(0, &from) > 0) {
+ if (from > high)
+ from = to;
+ else
+ from = p[from];
+ if (from != lastc || !BITSET(t,from)) {
+ lastc = from;
+ writerune(1, (Rune) from);
+ }
+ }
+
+ } else {
+ while (readrune(0, &from) > 0){
+ if (from > high)
+ from = to;
+ else
+ from = p[from];
+ writerune(1, (Rune) from);
+ }
+ }
+ wflush(1);
+}
+
+void
+translit(void)
+{
+ Rune *p;
+ int i;
+ long from, to, lastc, high;
+
+ lastc = 0;
+ high = 0;
+ while ((from = canon(&pfrom)) >= 0)
+ if (from > high) high = from;
+ Prewind(&pfrom);
+ if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
+ error("can't allocate memory");
+ for (i = 0; i <= high; i++)
+ p[i] = i;
+ while ((from = canon(&pfrom)) >= 0) {
+ if ((to = canon(&pto)) < 0)
+ to = lastc;
+ else lastc = to;
+ if (BITSET(f,from) && p[from] != to)
+ error("ambiguous translation");
+ SETBIT(f,from);
+ p[from] = to;
+ SETBIT(t,to);
+ }
+ while ((to = canon(&pto)) >= 0) {
+ SETBIT(t,to);
+ }
+ if (sflag){
+ lastc = 0x10000;
+ while (readrune(0, &from) > 0) {
+ if (from <= high)
+ from = p[from];
+ if (from != lastc || !BITSET(t,from)) {
+ lastc = from;
+ writerune(1, (Rune) from);
+ }
+ }
+
+ } else {
+ while (readrune(0, &from) > 0) {
+ if (from <= high)
+ from = p[from];
+ writerune(1, (Rune) from);
+ }
+ }
+ wflush(1);
+}
+
+int
+readrune(int fd, long *rp)
+{
+ Rune r;
+ int j;
+ static int i, n;
+ static char buf[4096];
+
+ j = i;
+ for (;;) {
+ if (i >= n) {
+ wflush(1);
+ if (j != i)
+ memcpy(buf, buf+j, n-j);
+ i = n-j;
+ n = read(fd, &buf[i], sizeof(buf)-i);
+ if (n < 0)
+ error("read error");
+ if (n == 0)
+ return 0;
+ j = 0;
+ n += i;
+ }
+ i++;
+ if (fullrune(&buf[j], i-j))
+ break;
+ }
+ chartorune(&r, &buf[j]);
+ *rp = r;
+ return 1;
+}
+
+void
+writerune(int fd, Rune r)
+{
+ char buf[UTFmax];
+ int n;
+
+ if (!wptr)
+ wptr = wbuf;
+ n = runetochar(buf, (Rune*)&r);
+ if (wptr+n >= wbuf+sizeof(wbuf))
+ wflush(fd);
+ memcpy(wptr, buf, n);
+ wptr += n;
+}
+
+void
+wflush(int fd)
+{
+ if (wptr && wptr > wbuf)
+ if (write(fd, wbuf, wptr-wbuf) != wptr-wbuf)
+ error("write error");
+ wptr = wbuf;
+}
+
+char *
+getrune(char *s, Rune *rp)
+{
+ Rune r;
+ char *save;
+ int i, n;
+
+ s += chartorune(rp, s);
+ if((r = *rp) == '\\' && *s){
+ n = 0;
+ if (*s == 'x') {
+ s++;
+ for (i = 0; i < 4; i++) {
+ save = s;
+ s += chartorune(&r, s);
+ if ('0' <= r && r <= '9')
+ n = 16*n + r - '0';
+ else if ('a' <= r && r <= 'f')
+ n = 16*n + r - 'a' + 10;
+ else if ('A' <= r && r <= 'F')
+ n = 16*n + r - 'A' + 10;
+ else {
+ if (i == 0)
+ *rp = 'x';
+ else *rp = n;
+ return save;
+ }
+ }
+ } else {
+ for(i = 0; i < 3; i++) {
+ save = s;
+ s += chartorune(&r, s);
+ if('0' <= r && r <= '7')
+ n = 8*n + r - '0';
+ else {
+ if (i == 0)
+ {
+ *rp = r;
+ return s;
+ }
+ *rp = n;
+ return save;
+ }
+ }
+ if(n > 0377)
+ error("char>0377");
+ }
+ *rp = n;
+ }
+ return s;
+}
+
+long
+canon(Pcb *p)
+{
+ Rune r;
+
+ if (p->final >= 0) {
+ if (p->last < p->final)
+ return ++p->last;
+ p->final = -1;
+ }
+ if (*p->current == '\0')
+ return -1;
+ if(*p->current == '-' && p->last >= 0 && p->current[1]){
+ p->current = getrune(p->current+1, &r);
+ if (r < p->last)
+ error ("Invalid range specification");
+ if (r > p->last) {
+ p->final = r;
+ return ++p->last;
+ }
+ }
+ p->current = getrune(p->current, &r);
+ p->last = r;
+ return p->last;
+}
+
+void
+Pinit(Pcb *p, char *cp)
+{
+ p->current = p->base = cp;
+ p->last = p->final = -1;
+}
+void
+Prewind(Pcb *p)
+{
+ p->current = p->base;
+ p->last = p->final = -1;
+}
+void
+error(char *s)
+{
+ fprint(2, "tr: %s\n", s);
+ exits(s);
+}
diff --git a/utils/va/a.h b/utils/va/a.h
new file mode 100644
index 00000000..92199a08
--- /dev/null
+++ b/utils/va/a.h
@@ -0,0 +1,181 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../vc/v.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ long value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ long offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int nosched;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(long);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+void macexpand(Sym*, char*);
+void macinc(void);
+void maclin(void);
+void macprag(void);
+void macif(int);
+void macend(void);
+void outhist(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/va/a.y b/utils/va/a.y
new file mode 100644
index 00000000..cbc07fd7
--- /dev/null
+++ b/utils/va/a.y
@@ -0,0 +1,588 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ long lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
+%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token <lval> LCONST LSP LSB LFP LPC LHI LLO LMREG
+%token <lval> LTYPEX LREG LFREG LFCREG LR LM LF
+%token <lval> LFCR LSCHED
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset sreg
+%type <gen> gen vgen lgen vlgen rel reg freg mreg fcreg
+%type <gen> imm ximm ireg name oreg imr nireg fgen
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| LSCHED ';'
+ {
+ nosched = $1;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * Immed-type
+ */
+ LTYPE1 imr ',' sreg ',' reg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPE1 imr ',' reg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * NOR
+ */
+| LTYPE2 imr ',' sreg ',' imr
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPE2 imr ',' imr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * LOAD/STORE, but not MOVW
+ */
+| LTYPE3 lgen ',' gen
+ {
+ if(!isreg(&$2) && !isreg(&$4))
+ print("one side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * SPECIAL
+ */
+| LTYPE4 comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * MOVW
+ */
+| LTYPE5 vlgen ',' vgen
+ {
+ if(!isreg(&$2) && !isreg(&$4))
+ print("one side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * MUL/DIV
+ */
+| LTYPE6 reg ',' sreg comma
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTYPE6 reg ',' sreg ',' reg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * JMP/JAL
+ */
+| LTYPE7 comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE7 comma nireg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 comma nireg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 sreg ',' nireg
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+/*
+ * BEQ/BNE
+ */
+| LTYPE9 gen ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPE9 gen ',' sreg ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * B-other
+ */
+| LTYPEA gen ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTYPEB name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEB name ',' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LTYPEC name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * floating-type
+ */
+| LTYPED freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEE freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEE freg ',' LFREG ',' freg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPEF freg ',' LFREG comma
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+/*
+ * coprocessor branch
+ */
+| LTYPEG comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * word
+ */
+| LTYPEH comma ximm
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * NOP
+ */
+| LTYPEI comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LTYPEI ',' vgen
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPEI vgen comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * BREAK -- overloaded with CACHE opcode
+ */
+| LTYPEJ comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LTYPEJ vgen ',' vgen
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+
+comma:
+| ','
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+vlgen:
+ lgen
+| fgen
+| mreg
+| fcreg
+| LHI
+ {
+ $$ = nullgen;
+ $$.type = D_HI;
+ }
+| LLO
+ {
+ $$ = nullgen;
+ $$.type = D_LO;
+ }
+
+vgen:
+ gen
+| fgen
+| mreg
+| fcreg
+| LHI
+ {
+ $$ = nullgen;
+ $$.type = D_HI;
+ }
+| LLO
+ {
+ $$ = nullgen;
+ $$.type = D_LO;
+ }
+
+lgen:
+ gen
+| ximm
+
+fgen:
+ freg
+
+mreg:
+ LMREG
+ {
+ $$ = nullgen;
+ $$.type = D_MREG;
+ $$.reg = $1;
+ }
+| LM '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_MREG;
+ $$.reg = $3;
+ }
+
+fcreg:
+ LFCREG
+ {
+ $$ = nullgen;
+ $$.type = D_FCREG;
+ $$.reg = $1;
+ }
+| LFCR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCREG;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+ximm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' oreg
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' '*' '$' oreg
+ {
+ $$ = $4;
+ $$.type = D_OCONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+nireg:
+ ireg
+| con ireg
+ {
+ if($1 != 0)
+ yyerror("offset must be zero");
+ $$ = $2;
+ }
+| name
+ {
+ $$ = $1;
+ if($1.name != D_EXTERN && $1.name != D_STATIC) {
+ }
+ }
+
+ireg:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+
+gen:
+ reg
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.offset = $1;
+ }
+| oreg
+
+oreg:
+ name
+| name '(' sreg ')'
+ {
+ $$ = $1;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ }
+| '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+imr:
+ reg
+| imm
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+reg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+sreg:
+ LREG
+| LR '(' con ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
diff --git a/utils/va/l.s b/utils/va/l.s
new file mode 100644
index 00000000..2f8e6341
--- /dev/null
+++ b/utils/va/l.s
@@ -0,0 +1,703 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+
+#define MAXMACH 4 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define MS2HZ 50 /* millisec per clock tick */
+#define TK2SEC(t) ((t)/20) /* ticks to seconds */
+#define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */
+
+/*
+ * CP0 registers
+ */
+
+#define INDEX 0
+#define RANDOM 1
+#define TLBPHYS 2
+#define CONTEXT 4
+#define BADVADDR 8
+#define TLBVIRT 10
+#define STATUS 12
+#define CAUSE 13
+#define EPC 14
+#define PRID 15
+
+/*
+ * M(STATUS) bits
+ */
+#define IEC 0x00000001
+#define KUC 0x00000002
+#define IEP 0x00000004
+#define KUP 0x00000008
+#define INTMASK 0x0000ff00
+#define SW0 0x00000100
+#define SW1 0x00000200
+#define INTR0 0x00000400
+#define INTR1 0x00000800
+#define INTR2 0x00001000
+#define INTR3 0x00002000
+#define INTR4 0x00004000
+#define INTR5 0x00008000
+#define ISC 0x00010000
+#define SWC 0x00020000
+#define CU1 0x20000000
+
+/*
+ * Traps
+ */
+
+#define UTLBMISS (KSEG0+0x00)
+#define EXCEPTION (KSEG0+0x80)
+
+/*
+ * Magic registers
+ */
+
+#define MACH 25 /* R25 is m-> */
+#define USER 24 /* R24 is u-> */
+#define MPID 0xBF000000 /* long; low 3 bits identify mp bus slot */
+#define WBFLUSH 0xBC000000 /* D-CACHE data; used for write buffer flush */
+
+/*
+ * Fundamental addresses
+ */
+
+#define MACHADDR 0x80014000
+#define USERADDR 0xC0000000
+#define UREGADDR (USERADDR+BY2PG-4-0xA0)
+/*
+ * MMU
+ */
+
+#define KUSEG 0x00000000
+#define KSEG0 0x80000000
+#define KSEG1 0xA0000000
+#define KSEG2 0xC0000000
+#define KSEGM 0xE0000000 /* mask to check which seg */
+
+#define PTEGLOBL (1<<8)
+#define PTEVALID (1<<9)
+#define PTEWRITE (1<<10)
+#define PTEPID(n) ((n)<<6)
+
+#define NTLBPID 64 /* number of pids */
+#define NTLB 64 /* number of entries */
+#define TLBROFF 8 /* offset of first randomly indexed entry */
+
+/*
+ * Address spaces
+ */
+
+#define UZERO KUSEG /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define USTKTOP KZERO /* byte just beyond user stack */
+#define TSTKTOP (USERADDR+100*BY2PG) /* top of temporary stack */
+#define KZERO KSEG0 /* base of kernel address space */
+#define KTZERO (KSEG0+0x20000) /* first address in kernel text */
+#define USTACKSIZE (4*1024*1024) /* size of user stack */
+/*
+ * Exception codes
+ */
+#define CINT 0 /* external interrupt */
+#define CTLBM 1 /* TLB modification */
+#define CTLBL 2 /* TLB miss (load or fetch) */
+#define CTLBS 3 /* TLB miss (store) */
+#define CADREL 4 /* address error (load or fetch) */
+#define CADRES 5 /* address error (store) */
+#define CBUSI 6 /* bus error (fetch) */
+#define CBUSD 7 /* bus error (data load or store) */
+#define CSYS 8 /* system call */
+#define CBRK 9 /* breakpoint */
+#define CRES 10 /* reserved instruction */
+#define CCPU 11 /* coprocessor unusable */
+#define COVF 12 /* arithmetic overflow */
+#define CUNK13 13 /* undefined 13 */
+#define CUNK14 14 /* undefined 14 */
+#define CUNK15 15 /* undefined 15 */
+
+#define NSEG 5
+
+#define SP R29
+
+#define PROM (KSEG1+0x1FC00000)
+#define NOOP NOR R0,R0
+#define WAIT NOOP; NOOP
+
+/*
+ * Boot first processor
+ * - why is the processor number loaded from R0 ?????
+ */
+TEXT start(SB), $-4
+
+ MOVW $setR30(SB), R30
+ MOVW $(CU1|INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1
+ MOVW R1, M(STATUS)
+ WAIT
+
+ MOVW $(0x1C<<7), R1
+ MOVW R1, FCR31 /* permit only inexact and underflow */
+ NOOP
+ MOVD $0.5, F26
+ SUBD F26, F26, F24
+ ADDD F26, F26, F28
+ ADDD F28, F28, F30
+
+ MOVD F24, F0
+ MOVD F24, F2
+ MOVD F24, F4
+ MOVD F24, F6
+ MOVD F24, F8
+ MOVD F24, F10
+ MOVD F24, F12
+ MOVD F24, F14
+ MOVD F24, F16
+ MOVD F24, F18
+ MOVD F24, F20
+ MOVD F24, F22
+
+ MOVW $MACHADDR, R(MACH)
+ ADDU $(BY2PG-4), R(MACH), SP
+ MOVW $0, R(USER)
+ MOVW R0, 0(R(MACH))
+
+ MOVW $edata(SB), R1
+ MOVW $end(SB), R2
+
+clrbss:
+ MOVB $0, (R1)
+ ADDU $1, R1
+ BNE R1, R2, clrbss
+
+ MOVW R4, _argc(SB)
+ MOVW R5, _argv(SB)
+ MOVW R6, _env(SB)
+ JAL main(SB)
+ JMP (R0)
+
+/*
+ * Take first processor into user mode
+ * - argument is stack pointer to user
+ */
+
+TEXT touser(SB), $-4
+
+ MOVW M(STATUS), R1
+ OR $(KUP|IEP), R1
+ MOVW R1, M(STATUS)
+ NOOP
+ MOVW 0(FP), SP
+ MOVW $(UTZERO+32), R26 /* header appears in text */
+ RFE (R26)
+
+/*
+ * Bring subsequent processors on line
+ */
+TEXT newstart(SB), $0
+
+ MOVW $setR30(SB), R30
+ MOVW $(INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1
+ MOVW R1, M(STATUS)
+ NOOP
+ MOVW $MACHADDR, R(MACH)
+ MOVB (MPID+3), R1
+ AND $7, R1
+ SLL $PGSHIFT, R1, R2
+ ADDU R2, R(MACH)
+ ADDU $(BY2PG-4), R(MACH), SP
+ MOVW $0, R(USER)
+ MOVW R1, 0(R(MACH))
+ JAL online(SB)
+ JMP (R0)
+
+TEXT firmware(SB), $0
+
+ MOVW $(PROM+0x18), R1 /**/
+/* MOVW $(PROM+0x00), R1 /**/
+ JMP (R1)
+
+TEXT splhi(SB), $0
+
+ MOVW M(STATUS), R1
+ AND $~IEC, R1, R2
+ MOVW R2, M(STATUS)
+ NOOP
+ RET
+
+TEXT spllo(SB), $0
+
+ MOVW M(STATUS), R1
+ OR $IEC, R1, R2
+ MOVW R2, M(STATUS)
+ NOOP
+ RET
+
+TEXT splx(SB), $0
+
+ MOVW 0(FP), R1
+ MOVW M(STATUS), R2
+ AND $IEC, R1
+ AND $~IEC, R2
+ OR R2, R1
+ MOVW R1, M(STATUS)
+ NOOP
+ RET
+
+TEXT wbflush(SB), $-4
+
+ MOVW $WBFLUSH, R1
+ MOVW 0(R1), R1
+ RET
+
+TEXT setlabel(SB), $0
+
+ MOVW 0(FP), R2
+ MOVW $0, R1
+ MOVW R31, 0(R2)
+ MOVW R29, 4(R2)
+ RET
+
+TEXT gotolabel(SB), $0
+
+ MOVW 0(FP), R2
+ MOVW $1, R1
+ MOVW 0(R2), R31
+ MOVW 4(R2), R29
+ RET
+
+TEXT gotopc(SB), $8
+
+ MOVW 0(FP), R7 /* save arguments for later */
+ MOVW _argc(SB), R4
+ MOVW _argv(SB), R5
+ MOVW _env(SB), R6
+ MOVW R0, 4(SP)
+ MOVW $(64*1024), R1
+ MOVW R1, 8(SP)
+ JAL icflush(SB)
+ JMP (R7)
+
+TEXT puttlb(SB), $4
+
+ JAL splhi(SB)
+ MOVW 0(FP), R2
+ MOVW 4(FP), R3
+ MOVW R1, 4(SP)
+ MOVW R2, M(TLBVIRT)
+ MOVW R3, M(TLBPHYS)
+ NOOP
+ TLBP
+ NOOP
+ MOVW M(INDEX), R4
+ BGEZ R4, index
+ TLBWR
+ NOOP
+ JAL splx(SB)
+ RET
+index:
+ TLBWI
+ NOOP
+ JAL splx(SB)
+ RET
+
+TEXT puttlbx(SB), $0
+
+ MOVW 0(FP), R4
+ MOVW 4(FP), R2
+ MOVW 8(FP), R3
+ SLL $8, R4
+ MOVW R2, M(TLBVIRT)
+ MOVW R3, M(TLBPHYS)
+ MOVW R4, M(INDEX)
+ NOOP
+ TLBWI
+ NOOP
+ RET
+
+TEXT tlbp(SB), $0
+ TLBP
+ NOOP
+ MOVW M(INDEX), R1
+ RET
+
+TEXT tlbvirt(SB), $0
+ TLBP
+ NOOP
+ MOVW M(TLBVIRT), R1
+ RET
+
+
+TEXT gettlb(SB), $0
+
+ MOVW 0(FP), R3
+ MOVW 4(FP), R4
+ SLL $8, R3
+ MOVW R3, M(INDEX)
+ NOOP
+ TLBR
+ NOOP
+ MOVW M(TLBVIRT), R1
+ MOVW M(TLBPHYS), R2
+ NOOP
+ MOVW R1, 0(R4)
+ MOVW R2, 4(R4)
+ RET
+
+TEXT gettlbvirt(SB), $0
+
+ MOVW 0(FP), R3
+ SLL $8, R3
+ MOVW R3, M(INDEX)
+ NOOP
+ TLBR
+ NOOP
+ MOVW M(TLBVIRT), R1
+ NOOP
+ RET
+
+TEXT vector80(SB), $-4
+
+ MOVW $exception(SB), R26
+ JMP (R26)
+
+TEXT exception(SB), $-4
+
+ MOVW M(STATUS), R26
+ AND $KUP, R26
+ BEQ R26, waskernel
+
+wasuser:
+ MOVW SP, R26
+ /*
+ * set kernel sp: ureg - ureg* - pc
+ * done in 2 steps because R30 is not set
+ * and the loader will make a literal
+ */
+ MOVW $((UREGADDR-2*BY2WD) & 0xffff0000), SP
+ OR $((UREGADDR-2*BY2WD) & 0xffff), SP
+ MOVW R26, 0x10(SP) /* user SP */
+ MOVW R31, 0x28(SP)
+ MOVW R30, 0x2C(SP)
+ MOVW M(CAUSE), R26
+ MOVW R(MACH), 0x3C(SP)
+ MOVW R(USER), 0x40(SP)
+ AND $(0xF<<2), R26
+ SUB $(CSYS<<2), R26
+
+ JAL saveregs(SB)
+
+ MOVW $setR30(SB), R30
+ SUBU $(UREGADDR-2*BY2WD-USERADDR), SP, R(USER)
+ MOVW $MPID, R1
+ MOVB 3(R1), R1
+ MOVW $MACHADDR, R(MACH) /* locn of mach 0 */
+ AND $7, R1
+ SLL $PGSHIFT, R1
+ ADDU R1, R(MACH) /* add offset for mach # */
+
+ BNE R26, notsys
+
+ JAL syscall(SB)
+
+ MOVW 0x28(SP), R31
+ MOVW 0x08(SP), R26
+ MOVW 0x2C(SP), R30
+ MOVW R26, M(STATUS)
+ NOOP
+ MOVW 0x0C(SP), R26 /* old pc */
+ MOVW 0x10(SP), SP
+ RFE (R26)
+
+notsys:
+ JAL trap(SB)
+
+restore:
+ JAL restregs(SB)
+ MOVW 0x28(SP), R31
+ MOVW 0x2C(SP), R30
+ MOVW 0x3C(SP), R(MACH)
+ MOVW 0x40(SP), R(USER)
+ MOVW 0x10(SP), SP
+ RFE (R26)
+
+waskernel:
+ MOVW $1, R26 /* not sys call */
+ MOVW SP, -0x90(SP) /* drop this if possible */
+ SUB $0xA0, SP
+ MOVW R31, 0x28(SP)
+ JAL saveregs(SB)
+ JAL trap(SB)
+ JAL restregs(SB)
+ MOVW 0x28(SP), R31
+ ADD $0xA0, SP
+ RFE (R26)
+
+TEXT saveregs(SB), $-4
+ MOVW R1, 0x9C(SP)
+ MOVW R2, 0x98(SP)
+ ADDU $8, SP, R1
+ MOVW R1, 0x04(SP) /* arg to base of regs */
+ MOVW M(STATUS), R1
+ MOVW M(EPC), R2
+ MOVW R1, 0x08(SP)
+ MOVW R2, 0x0C(SP)
+
+ BEQ R26, return /* sys call, don't save */
+
+ MOVW M(CAUSE), R1
+ MOVW M(BADVADDR), R2
+ MOVW R1, 0x14(SP)
+ MOVW M(TLBVIRT), R1
+ MOVW R2, 0x18(SP)
+ MOVW R1, 0x1C(SP)
+ MOVW HI, R1
+ MOVW LO, R2
+ MOVW R1, 0x20(SP)
+ MOVW R2, 0x24(SP)
+ /* LINK,SB,SP missing */
+ MOVW R28, 0x30(SP)
+ /* R27, R26 not saved */
+ /* R25, R24 missing */
+ MOVW R23, 0x44(SP)
+ MOVW R22, 0x48(SP)
+ MOVW R21, 0x4C(SP)
+ MOVW R20, 0x50(SP)
+ MOVW R19, 0x54(SP)
+ MOVW R18, 0x58(SP)
+ MOVW R17, 0x5C(SP)
+ MOVW R16, 0x60(SP)
+ MOVW R15, 0x64(SP)
+ MOVW R14, 0x68(SP)
+ MOVW R13, 0x6C(SP)
+ MOVW R12, 0x70(SP)
+ MOVW R11, 0x74(SP)
+ MOVW R10, 0x78(SP)
+ MOVW R9, 0x7C(SP)
+ MOVW R8, 0x80(SP)
+ MOVW R7, 0x84(SP)
+ MOVW R6, 0x88(SP)
+ MOVW R5, 0x8C(SP)
+ MOVW R4, 0x90(SP)
+ MOVW R3, 0x94(SP)
+return:
+ RET
+
+TEXT restregs(SB), $-4
+ /* LINK,SB,SP missing */
+ MOVW 0x30(SP), R28
+ /* R27, R26 not saved */
+ /* R25, R24 missing */
+ MOVW 0x44(SP), R23
+ MOVW 0x48(SP), R22
+ MOVW 0x4C(SP), R21
+ MOVW 0x50(SP), R20
+ MOVW 0x54(SP), R19
+ MOVW 0x58(SP), R18
+ MOVW 0x5C(SP), R17
+ MOVW 0x60(SP), R16
+ MOVW 0x64(SP), R15
+ MOVW 0x68(SP), R14
+ MOVW 0x6C(SP), R13
+ MOVW 0x70(SP), R12
+ MOVW 0x74(SP), R11
+ MOVW 0x78(SP), R10
+ MOVW 0x7C(SP), R9
+ MOVW 0x80(SP), R8
+ MOVW 0x84(SP), R7
+ MOVW 0x88(SP), R6
+ MOVW 0x8C(SP), R5
+ MOVW 0x90(SP), R4
+ MOVW 0x94(SP), R3
+ MOVW 0x24(SP), R2
+ MOVW 0x20(SP), R1
+ MOVW R2, LO
+ MOVW R1, HI
+ MOVW 0x08(SP), R1
+ MOVW 0x98(SP), R2
+ MOVW R1, M(STATUS)
+ NOOP
+ MOVW 0x9C(SP), R1
+ MOVW 0x0C(SP), R26 /* old pc */
+ RET
+
+TEXT rfnote(SB), $0
+ MOVW 0(FP), R26 /* 1st arg is &uregpointer */
+ SUBU $(BY2WD), R26, SP /* pc hole */
+ BNE R26, restore
+
+
+TEXT clrfpintr(SB), $0
+ MOVW FCR31, R1
+ MOVW R1, R2
+ AND $~(0x3F<<12), R2
+ MOVW R2, FCR31
+ RET
+
+TEXT savefpregs(SB), $0
+ MOVW M(STATUS), R3
+ MOVW 0(FP), R1
+ MOVW FCR31, R2
+
+ MOVD F0, 0x00(R1)
+ MOVD F2, 0x08(R1)
+ MOVD F4, 0x10(R1)
+ MOVD F6, 0x18(R1)
+ MOVD F8, 0x20(R1)
+ MOVD F10, 0x28(R1)
+ MOVD F12, 0x30(R1)
+ MOVD F14, 0x38(R1)
+ MOVD F16, 0x40(R1)
+ MOVD F18, 0x48(R1)
+ MOVD F20, 0x50(R1)
+ MOVD F22, 0x58(R1)
+ MOVD F24, 0x60(R1)
+ MOVD F26, 0x68(R1)
+ MOVD F28, 0x70(R1)
+ MOVD F30, 0x78(R1)
+
+ MOVW R2, 0x80(R1)
+ AND $~CU1, R3
+ MOVW R3, M(STATUS)
+ RET
+
+TEXT restfpregs(SB), $0
+
+ MOVW M(STATUS), R3
+ MOVW 0(FP), R1
+ OR $CU1, R3
+ MOVW R3, M(STATUS)
+ MOVW 0x80(R1), R2
+
+ MOVD 0x00(R1), F0
+ MOVD 0x08(R1), F2
+ MOVD 0x10(R1), F4
+ MOVD 0x18(R1), F6
+ MOVD 0x20(R1), F8
+ MOVD 0x28(R1), F10
+ MOVD 0x30(R1), F12
+ MOVD 0x38(R1), F14
+ MOVD 0x40(R1), F16
+ MOVD 0x48(R1), F18
+ MOVD 0x50(R1), F20
+ MOVD 0x58(R1), F22
+ MOVD 0x60(R1), F24
+ MOVD 0x68(R1), F26
+ MOVD 0x70(R1), F28
+ MOVD 0x78(R1), F30
+
+ MOVW R2, FCR31
+ AND $~CU1, R3
+ MOVW R3, M(STATUS)
+ RET
+
+/*
+ * we avoid using R4, R5, R6, and R7 so gotopc can call us without saving them
+ */
+TEXT icflush(SB), $-4 /* icflush(physaddr, nbytes) */
+
+ MOVW M(STATUS), R10
+ MOVW 0(FP), R8
+ MOVW 4(FP), R9
+ MOVW $KSEG0, R3
+ OR R3, R8
+ MOVW $0, M(STATUS)
+ MOVW $WBFLUSH, R1 /* wbflush */
+ MOVW 0(R1), R1
+ NOOP
+ MOVW $KSEG1, R3
+ MOVW $icflush0(SB), R2 /* make sure PC is in uncached address space */
+ MOVW $(SWC|ISC), R1
+ OR R3, R2
+ JMP (R2)
+
+TEXT icflush0(SB), $-4
+
+ MOVW R1, M(STATUS) /* swap and isolate cache, splhi */
+ MOVW $icflush1(SB), R2
+ JMP (R2)
+
+TEXT icflush1(SB), $-4
+
+_icflush1:
+ MOVBU R0, 0x00(R8)
+ MOVBU R0, 0x04(R8)
+ MOVBU R0, 0x08(R8)
+ MOVBU R0, 0x0C(R8)
+ MOVBU R0, 0x10(R8)
+ MOVBU R0, 0x14(R8)
+ MOVBU R0, 0x18(R8)
+ MOVBU R0, 0x1C(R8)
+ MOVBU R0, 0x20(R8)
+ MOVBU R0, 0x24(R8)
+ MOVBU R0, 0x28(R8)
+ MOVBU R0, 0x2C(R8)
+ MOVBU R0, 0x30(R8)
+ MOVBU R0, 0x34(R8)
+ MOVBU R0, 0x38(R8)
+ MOVBU R0, 0x3C(R8)
+ SUB $0x40, R9
+ ADD $0x40, R8
+ BGTZ R9, _icflush1
+ MOVW $icflush2(SB), R2 /* make sure PC is in uncached address space */
+ OR R3, R2
+ JMP (R2)
+
+TEXT icflush2(SB), $-4
+
+ MOVW $0, M(STATUS) /* swap back caches, de-isolate them, and stay splhi */
+ NOOP /* +++ */
+ MOVW R10, M(STATUS)
+ RET
+
+TEXT dcflush(SB), $-4 /* dcflush(physaddr, nbytes) */
+
+ MOVW M(STATUS), R6
+ MOVW 0(FP), R4
+ MOVW 4(FP), R5
+ MOVW $KSEG0, R3
+ OR R3, R4
+ MOVW $0, M(STATUS)
+ MOVW $WBFLUSH, R1
+ MOVW 0(R1), R1
+ NOOP
+ MOVW $ISC, R1
+ MOVW R1, M(STATUS)
+_dcflush0:
+ MOVBU R0, 0x00(R4)
+ MOVBU R0, 0x04(R4)
+ MOVBU R0, 0x08(R4)
+ MOVBU R0, 0x0C(R4)
+ MOVBU R0, 0x10(R4)
+ MOVBU R0, 0x14(R4)
+ MOVBU R0, 0x18(R4)
+ MOVBU R0, 0x1C(R4)
+ MOVBU R0, 0x20(R4)
+ MOVBU R0, 0x24(R4)
+ MOVBU R0, 0x28(R4)
+ MOVBU R0, 0x2C(R4)
+ MOVBU R0, 0x30(R4)
+ MOVBU R0, 0x34(R4)
+ MOVBU R0, 0x38(R4)
+ MOVBU R0, 0x3C(R4)
+ SUB $0x40, R5
+ ADD $0x40, R4
+ BGTZ R5, _dcflush0
+ MOVW $0, M(STATUS)
+ NOOP /* +++ */
+ MOVW R6, M(STATUS)
+ RET
diff --git a/utils/va/lex.c b/utils/va/lex.c
new file mode 100644
index 00000000..fee14c2f
--- /dev/null
+++ b/utils/va/lex.c
@@ -0,0 +1,697 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = 'v';
+ thestring = "mips";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+ "HI", LHI, D_HI,
+ "LO", LLO, D_LO,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+ "R16", LREG, 16,
+ "R17", LREG, 17,
+ "R18", LREG, 18,
+ "R19", LREG, 19,
+ "R20", LREG, 20,
+ "R21", LREG, 21,
+ "R22", LREG, 22,
+ "R23", LREG, 23,
+ "R24", LREG, 24,
+ "R25", LREG, 25,
+ "R26", LREG, 26,
+ "R27", LREG, 27,
+ "R28", LREG, 28,
+ "R29", LREG, 29,
+ "R30", LREG, 30,
+ "R31", LREG, 31,
+
+ "M", LM, 0,
+ "M0", LMREG, 0,
+ "M1", LMREG, 1,
+ "M2", LMREG, 2,
+ "M3", LMREG, 3,
+ "M4", LMREG, 4,
+ "M5", LMREG, 5,
+ "M6", LMREG, 6,
+ "M7", LMREG, 7,
+ "M8", LMREG, 8,
+ "M9", LMREG, 9,
+ "M10", LMREG, 10,
+ "M11", LMREG, 11,
+ "M12", LMREG, 12,
+ "M13", LMREG, 13,
+ "M14", LMREG, 14,
+ "M15", LMREG, 15,
+ "M16", LMREG, 16,
+ "M17", LMREG, 17,
+ "M18", LMREG, 18,
+ "M19", LMREG, 19,
+ "M20", LMREG, 20,
+ "M21", LMREG, 21,
+ "M22", LMREG, 22,
+ "M23", LMREG, 23,
+ "M24", LMREG, 24,
+ "M25", LMREG, 25,
+ "M26", LMREG, 26,
+ "M27", LMREG, 27,
+ "M28", LMREG, 28,
+ "M29", LMREG, 29,
+ "M30", LMREG, 30,
+ "M31", LMREG, 31,
+
+ "F", LF, 0,
+
+ "F0", LFREG, 0,
+ "F1", LFREG, 1,
+ "F2", LFREG, 2,
+ "F3", LFREG, 3,
+ "F4", LFREG, 4,
+ "F5", LFREG, 5,
+ "F6", LFREG, 6,
+ "F7", LFREG, 7,
+ "F8", LFREG, 8,
+ "F9", LFREG, 9,
+ "F10", LFREG, 10,
+ "F11", LFREG, 11,
+ "F12", LFREG, 12,
+ "F13", LFREG, 13,
+ "F14", LFREG, 14,
+ "F15", LFREG, 15,
+ "F16", LFREG, 16,
+ "F17", LFREG, 17,
+ "F18", LFREG, 18,
+ "F19", LFREG, 19,
+ "F20", LFREG, 20,
+ "F21", LFREG, 21,
+ "F22", LFREG, 22,
+ "F23", LFREG, 23,
+ "F24", LFREG, 24,
+ "F25", LFREG, 25,
+ "F26", LFREG, 26,
+ "F27", LFREG, 27,
+ "F28", LFREG, 28,
+ "F29", LFREG, 29,
+ "F30", LFREG, 30,
+ "F31", LFREG, 31,
+
+ "FCR", LFCR, 0,
+ "FCR0", LFCREG, 0,
+ "FCR1", LFCREG, 1,
+ "FCR2", LFCREG, 2,
+ "FCR3", LFCREG, 3,
+ "FCR4", LFCREG, 4,
+ "FCR5", LFCREG, 5,
+ "FCR6", LFCREG, 6,
+ "FCR7", LFCREG, 7,
+ "FCR8", LFCREG, 8,
+ "FCR9", LFCREG, 9,
+ "FCR10", LFCREG, 10,
+ "FCR11", LFCREG, 11,
+ "FCR12", LFCREG, 12,
+ "FCR13", LFCREG, 13,
+ "FCR14", LFCREG, 14,
+ "FCR15", LFCREG, 15,
+ "FCR16", LFCREG, 16,
+ "FCR17", LFCREG, 17,
+ "FCR18", LFCREG, 18,
+ "FCR19", LFCREG, 19,
+ "FCR20", LFCREG, 20,
+ "FCR21", LFCREG, 21,
+ "FCR22", LFCREG, 22,
+ "FCR23", LFCREG, 23,
+ "FCR24", LFCREG, 24,
+ "FCR25", LFCREG, 25,
+ "FCR26", LFCREG, 26,
+ "FCR27", LFCREG, 27,
+ "FCR28", LFCREG, 28,
+ "FCR29", LFCREG, 29,
+ "FCR30", LFCREG, 30,
+ "FCR31", LFCREG, 31,
+
+ "ADD", LTYPE1, AADD,
+ "ADDU", LTYPE1, AADDU,
+ "SUB", LTYPE1, ASUB, /* converted to ADD(-) in loader */
+ "SUBU", LTYPE1, ASUBU,
+ "SGT", LTYPE1, ASGT,
+ "SGTU", LTYPE1, ASGTU,
+ "AND", LTYPE1, AAND,
+ "OR", LTYPE1, AOR,
+ "XOR", LTYPE1, AXOR,
+ "SLL", LTYPE1, ASLL,
+ "SRL", LTYPE1, ASRL,
+ "SRA", LTYPE1, ASRA,
+
+ "ADDV", LTYPE1, AADDV,
+ "ADDVU", LTYPE1, AADDVU,
+ "SUBV", LTYPE1, ASUBV, /* converted to ADD(-) in loader */
+ "SUBVU", LTYPE1, ASUBVU,
+ "SLLV", LTYPE1, ASLLV,
+ "SRLV", LTYPE1, ASRLV,
+ "SRAV", LTYPE1, ASRAV,
+
+ "NOR", LTYPE2, ANOR,
+
+ "MOVB", LTYPE3, AMOVB,
+ "MOVBU", LTYPE3, AMOVBU,
+ "MOVH", LTYPE3, AMOVH,
+ "MOVHU", LTYPE3, AMOVHU,
+ "MOVWL", LTYPE3, AMOVWL,
+ "MOVWR", LTYPE3, AMOVWR,
+ "MOVVL", LTYPE3, AMOVVL,
+ "MOVVR", LTYPE3, AMOVVR,
+
+ "BREAK", LTYPEJ, ABREAK, /* overloaded CACHE opcode */
+ "END", LTYPE4, AEND,
+ "REM", LTYPE6, AREM,
+ "REMU", LTYPE6, AREMU,
+ "RET", LTYPE4, ARET,
+ "SYSCALL", LTYPE4, ASYSCALL,
+ "TLBP", LTYPE4, ATLBP,
+ "TLBR", LTYPE4, ATLBR,
+ "TLBWI", LTYPE4, ATLBWI,
+ "TLBWR", LTYPE4, ATLBWR,
+
+ "MOVW", LTYPE5, AMOVW,
+ "MOVV", LTYPE5, AMOVV,
+ "MOVD", LTYPE5, AMOVD,
+ "MOVF", LTYPE5, AMOVF,
+
+ "DIV", LTYPE6, ADIV,
+ "DIVU", LTYPE6, ADIVU,
+ "MUL", LTYPE6, AMUL,
+ "MULU", LTYPE6, AMULU,
+ "DIVV", LTYPE6, ADIVV,
+ "DIVVU", LTYPE6, ADIVVU,
+ "MULV", LTYPE6, AMULV,
+ "MULVU", LTYPE6, AMULVU,
+
+ "RFE", LTYPE7, ARFE,
+ "JMP", LTYPE7, AJMP,
+
+ "JAL", LTYPE8, AJAL,
+
+ "BEQ", LTYPE9, ABEQ,
+ "BNE", LTYPE9, ABNE,
+
+ "BGEZ", LTYPEA, ABGEZ,
+ "BGEZAL", LTYPEA, ABGEZAL,
+ "BGTZ", LTYPEA, ABGTZ,
+ "BLEZ", LTYPEA, ABLEZ,
+ "BLTZ", LTYPEA, ABLTZ,
+ "BLTZAL", LTYPEA, ABLTZAL,
+
+ "TEXT", LTYPEB, ATEXT,
+ "GLOBL", LTYPEB, AGLOBL,
+
+ "DATA", LTYPEC, ADATA,
+
+ "MOVDF", LTYPE5, AMOVDF,
+ "MOVDW", LTYPE5, AMOVDW,
+ "MOVFD", LTYPE5, AMOVFD,
+ "MOVFW", LTYPE5, AMOVFW,
+ "MOVWD", LTYPE5, AMOVWD,
+ "MOVWF", LTYPE5, AMOVWF,
+
+ "ABSD", LTYPED, AABSD,
+ "ABSF", LTYPED, AABSF,
+ "ABSW", LTYPED, AABSW,
+ "NEGD", LTYPED, ANEGD,
+ "NEGF", LTYPED, ANEGF,
+ "NEGW", LTYPED, ANEGW,
+
+ "CMPEQD", LTYPEF, ACMPEQD,
+ "CMPEQF", LTYPEF, ACMPEQF,
+ "CMPGED", LTYPEF, ACMPGED,
+ "CMPGEF", LTYPEF, ACMPGEF,
+ "CMPGTD", LTYPEF, ACMPGTD,
+ "CMPGTF", LTYPEF, ACMPGTF,
+
+ "ADDD", LTYPEE, AADDD,
+ "ADDF", LTYPEE, AADDF,
+ "ADDW", LTYPEE, AADDW,
+ "DIVD", LTYPEE, ADIVD,
+ "DIVF", LTYPEE, ADIVF,
+ "DIVW", LTYPEE, ADIVW,
+ "MULD", LTYPEE, AMULD,
+ "MULF", LTYPEE, AMULF,
+ "MULW", LTYPEE, AMULW,
+ "SUBD", LTYPEE, ASUBD,
+ "SUBF", LTYPEE, ASUBF,
+ "SUBW", LTYPEE, ASUBW,
+
+ "BFPT", LTYPEG, ABFPT,
+ "BFPF", LTYPEG, ABFPF,
+
+ "WORD", LTYPEH, AWORD,
+ "NOP", LTYPEI, ANOP,
+ "SCHED", LSCHED, 0,
+ "NOSCHED", LSCHED, 0x80,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+int
+isreg(Gen *g)
+{
+
+ USED(g);
+ return 1;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_MREG:
+ case D_FCREG:
+ case D_LO:
+ case D_HI:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+ }
+}
+
+void
+outcode(int a, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+jackpot:
+ sf = 0;
+ s = g1->sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g1->name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, reg|nosched);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/utils/va/mkfile b/utils/va/mkfile
new file mode 100644
index 00000000..73604984
--- /dev/null
+++ b/utils/va/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=va
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../vc/v.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/va/note b/utils/va/note
new file mode 100644
index 00000000..f68e464f
--- /dev/null
+++ b/utils/va/note
@@ -0,0 +1,51 @@
+gen address
+
+$con
+ type = D_CONST
+ offset = con
+
+$name+con(P)
+ type = D_CONST
+ offset = con
+ name = P
+
+$"xxx"
+ type = D_SCONST
+
+$1.0
+ type = D_FCONST
+
+con
+ type = D_OREG
+ offset = con
+
+name+con(P)
+ type = D_OREG
+ offset = con
+ name = P
+
+con(R1)
+ type = D_OREG
+ offset = con
+ reg = 1
+
+name+con(P)(R1)
+ type = D_OREG
+ offset = con
+ name = P
+ reg = 1
+
+R1
+ type = D_REG
+ reg = 1
+
+MOVB[U]
+ LB[U], SB
+MOVH[U]
+ LH[U], SB
+MOVW[LR]
+ LW[LR], SW[LR]
+MOVW
+ LW, SW, LUI, M[FT]HI, M[FT]LO
+BREAK is synonym for CACHE.
+operands make the difference.
diff --git a/utils/vc/cgen.c b/utils/vc/cgen.c
new file mode 100644
index 00000000..5d5262db
--- /dev/null
+++ b/utils/vc/cgen.c
@@ -0,0 +1,1184 @@
+#include "gc.h"
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o;
+ long v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesuv[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED && l->complex < FNX) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[r->type->etype])
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(l->complex >= r->complex) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ } else {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+
+ regalloc(&nod, n, nn);
+ gmove(&nod2, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(o, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type)) {
+ if(nocast(n->type, nn->type)) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ if(nn == Z || typefd[n->type->etype]) {
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ nodreg(&nod1, n, NREG+FREGZERO);
+ gopcode(o, &nod, &nod1, Z);
+ } else
+ gopcode(o, &nod, Z, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(true)
+ gopcode(OCOND, &nod, nodconst(0), &nod);
+ else
+ gopcode(OCOND, nodconst(1), &nod, &nod);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(nn != Z && !typefd[l->type->etype]) {
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ switch(o) {
+ case OEQ:
+ gopcode(OSUB, &nod1, &nod, &nod);
+ gopcode(OCOND, &nod, nodconst(0), &nod);
+ break;
+ case ONE:
+ gopcode(OSUB, &nod1, &nod, &nod);
+ gopcode(OCOND, nodconst(1), &nod, &nod);
+ break;
+ case OLE:
+ gopcode(OCOMMA, &nod1, &nod, &nod);
+ break;
+ case OGT:
+ gopcode(OCOMMA, &nod1, &nod, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OLT:
+ gopcode(OCOMMA, &nod, &nod1, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OGE:
+ gopcode(OCOMMA, &nod, &nod1, &nod);
+ break;
+ case OLS:
+ gopcode(OCOND, &nod1, &nod, &nod);
+ break;
+ case OHI:
+ gopcode(OCOND, &nod1, &nod, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OLO:
+ gopcode(OCOND, &nod, &nod1, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OHS:
+ gopcode(OCOND, &nod, &nod1, &nod);
+ break;
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+ }
+ if(sconst(l)) {
+ switch(o) {
+ default:
+ if(l->vconst != 0)
+ break;
+
+ case OGT:
+ case OHI:
+ case OLE:
+ case OLS:
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ }
+ if(sconst(r)) {
+ switch(o) {
+ default:
+ if(r->vconst != 0)
+ break;
+
+ case OGE:
+ case OHS:
+ case OLT:
+ case OLO:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, r, Z);
+ regfree(&nod);
+ goto com;
+ }
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod1, &nod, Z);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case OCONST:
+ if(n->type && typev[n->type->etype]) {
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+ else
+ gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+ regfree(&nod1);
+ break;
+ }
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no fn call
+ */
+ if(nn != Z && nn->complex >= FNX) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ }
+
+ w /= SZ_LONG;
+ if(w <= 5) {
+ layout(&nod1, &nod2, w, 0, Z);
+ goto out;
+ }
+
+ /*
+ * minimize space for unrolling loop
+ * 3,4,5 times. (6 or more is never minimum)
+ * if small structure, try 2 also.
+ */
+ c = 0; /* set */
+ m = 100;
+ i = 3;
+ if(w <= 15)
+ i = 2;
+ for(; i<=5; i++)
+ if(i + w%i <= m) {
+ c = i;
+ m = c + w%c;
+ }
+
+ regalloc(&nod3, &regnode, Z);
+ layout(&nod1, &nod2, w%c, w/c, &nod3);
+
+ pc1 = pc;
+ layout(&nod1, &nod2, c, 0, Z);
+
+ gopcode(OSUB, nodconst(1), Z, &nod3);
+ nod1.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
+ nod2.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
+
+ gopcode(OEQ, &nod3, Z, Z);
+ p->as = ABGTZ;
+ patch(p, pc1);
+
+ regfree(&nod3);
+out:
+ regfree(&nod1);
+ regfree(&nod2);
+}
+
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, &regnode, Z);
+ regalloc(&t2, &regnode, Z);
+ t1.type = types[TLONG];
+ t2.type = types[TLONG];
+ if(c > 0) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(cn != Z)
+ gopcode(OAS, nodconst(cv), Z, cn);
+ if(c > 1) {
+ gopcode(OAS, f, Z, &t2);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 0) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_LONG;
+ }
+ if(c > 1) {
+ gopcode(OAS, &t2, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_LONG;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
diff --git a/utils/vc/enam.c b/utils/vc/enam.c
new file mode 100644
index 00000000..f9c94f7f
--- /dev/null
+++ b/utils/vc/enam.c
@@ -0,0 +1,118 @@
+char* anames[] =
+{
+ "XXX",
+ "ABSD",
+ "ABSF",
+ "ABSW",
+ "ADD",
+ "ADDD",
+ "ADDF",
+ "ADDU",
+ "ADDW",
+ "AND",
+ "BEQ",
+ "BFPF",
+ "BFPT",
+ "BGEZ",
+ "BGEZAL",
+ "BGTZ",
+ "BLEZ",
+ "BLTZ",
+ "BLTZAL",
+ "BNE",
+ "BREAK",
+ "CMPEQD",
+ "CMPEQF",
+ "CMPGED",
+ "CMPGEF",
+ "CMPGTD",
+ "CMPGTF",
+ "DATA",
+ "DIV",
+ "DIVD",
+ "DIVF",
+ "DIVU",
+ "DIVW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "JAL",
+ "JMP",
+ "MOVB",
+ "MOVBU",
+ "MOVD",
+ "MOVDF",
+ "MOVDW",
+ "MOVF",
+ "MOVFD",
+ "MOVFW",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MOVWD",
+ "MOVWF",
+ "MOVWL",
+ "MOVWR",
+ "MUL",
+ "MULD",
+ "MULF",
+ "MULU",
+ "MULW",
+ "NAME",
+ "NEGD",
+ "NEGF",
+ "NEGW",
+ "NOP",
+ "NOR",
+ "OR",
+ "REM",
+ "REMU",
+ "RET",
+ "RFE",
+ "SGT",
+ "SGTU",
+ "SLL",
+ "SRA",
+ "SRL",
+ "SUB",
+ "SUBD",
+ "SUBF",
+ "SUBU",
+ "SUBW",
+ "SYSCALL",
+ "TEXT",
+ "TLBP",
+ "TLBR",
+ "TLBWI",
+ "TLBWR",
+ "WORD",
+ "XOR",
+ "END",
+ "MOVV",
+ "MOVVL",
+ "MOVVR",
+ "SLLV",
+ "SRAV",
+ "SRLV",
+ "DIVV",
+ "DIVVU",
+ "REMV",
+ "REMVU",
+ "MULV",
+ "MULVU",
+ "ADDV",
+ "ADDVU",
+ "SUBV",
+ "SUBVU",
+ "DYNT",
+ "INIT",
+ "BCASE",
+ "CASE",
+ "TRUNCFV",
+ "TRUNCDV",
+ "TRUNCFW",
+ "TRUNCDW",
+ "MOVWU",
+ "SIGNAME",
+ "LAST",
+};
diff --git a/utils/vc/gc.h b/utils/vc/gc.h
new file mode 100644
index 00000000..c090af40
--- /dev/null
+++ b/utils/vc/gc.h
@@ -0,0 +1,331 @@
+#include "../cc/cc.h"
+#include "../vc/v.out.h"
+
+/*
+ * vc/mips
+ * Mips 3000
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 4
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Adr
+{
+ long offset;
+ double dval;
+ char sval[NSNAME];
+ Ieee ieee;
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ char as;
+ char reg;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ long val;
+ long label;
+ char def;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ long val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 600
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN Multab multab[20];
+EXTERN int retok;
+EXTERN int hintabsize;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[NREG+NREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 4
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void xcom(Node*);
+void bcomplex(Node*);
+void usedset(Node*, int);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+int sval(long);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*, Node*);
+void cas(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
diff --git a/utils/vc/list.c b/utils/vc/list.c
new file mode 100644
index 00000000..f89b17ca
--- /dev/null
+++ b/utils/vc/list.c
@@ -0,0 +1,244 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('D', Dconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCREG:
+ sprint(str, "FCR%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_LO:
+ sprint(str, "LO");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(LO)(REG)", a);
+ break;
+
+ case D_HI:
+ sprint(str, "HI");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(HI)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%ld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%ld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/utils/vc/mkenam b/utils/vc/mkenam
new file mode 100644
index 00000000..f09ef75d
--- /dev/null
+++ b/utils/vc/mkenam
@@ -0,0 +1,15 @@
+ed - ../vc/v.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/utils/vc/mkfile b/utils/vc/mkfile
new file mode 100644
index 00000000..f17af88d
--- /dev/null
+++ b/utils/vc/mkfile
@@ -0,0 +1,32 @@
+<../../mkconfig
+
+TARG=vc
+
+OFILES=\
+ cgen.$O\
+ enam.$O\
+ list.$O\
+ peep.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ v.out.h\
+ ../cc/cc.h\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
diff --git a/utils/vc/mul.c b/utils/vc/mul.c
new file mode 100644
index 00000000..3ef56cd5
--- /dev/null
+++ b/utils/vc/mul.c
@@ -0,0 +1,608 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=6; g++) {
+ if(g >= 6 && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
diff --git a/utils/vc/peep.c b/utils/vc/peep.c
new file mode 100644
index 00000000..a9a43da4
--- /dev/null
+++ b/utils/vc/peep.c
@@ -0,0 +1,694 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
+ if(regtyp(&p->to)) {
+ if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(regzer(&p->from))
+ if(p->to.type == D_REG) {
+ p->from.type = D_REG;
+ p->from.reg = 0;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regzer(Adr *a)
+{
+
+ if(a->type == D_CONST)
+ if(a->sym == S)
+ if(a->offset == 0)
+ return 1;
+ if(a->type == D_REG)
+ if(a->reg == 0)
+ return 1;
+ return 0;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG) {
+ if(a->reg != 0)
+ return 1;
+ return 0;
+ }
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case AJAL:
+ return 0;
+
+ case ASGT:
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDD:
+ case AADDF:
+ case ASUBD:
+ case ASUBF:
+ case AMULD:
+ case AMULF:
+ case ADIVD:
+ case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFD:
+ case AMOVDF:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ASGT: /* read, read, write */
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case ANOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABGTZ:
+ case ABGEZ:
+ case ABLTZ:
+ case ABLEZ:
+
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+ case ABFPF:
+ case ABFPT:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AJMP: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case AJAL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(REGARG && v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+ case ABEQ:
+ case ABNE:
+ case ABGTZ:
+ case ABGEZ:
+ case ABLTZ:
+ case ABLEZ:
+
+ case ASGT:
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+ return D_REG;
+
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v))
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG)
+ if(a->type == D_OREG)
+ if(v->reg == a->reg)
+ return 1;
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v))
+ if(p->from.type == v->type || p->to.type == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v))
+ a->reg = s->reg;
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
diff --git a/utils/vc/reg.c b/utils/vc/reg.c
new file mode 100644
index 00000000..c0d294c9
--- /dev/null
+++ b/utils/vc/reg.c
@@ -0,0 +1,1148 @@
+#include "gc.h"
+
+void addsplits(void);
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case AJAL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] && debug['v']) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%B", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%B", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%B", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%B", r->calbehind);
+ if(bany(&r->regdiff))
+ print(" rd=%B", r->regdiff);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == AJAL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !typechlpfd[et]) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case AJAL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R3
+ * 1 R4
+ * ... ...
+ * 19 R22
+ * 20 R23
+ */
+long
+RtoB(int r)
+{
+
+ if(r < 3 || r > 23)
+ return 0;
+ return 1L << (r-3);
+}
+
+BtoR(long b)
+{
+
+ b &= 0x001fffffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + 3;
+}
+
+/*
+ * bit reg
+ * 22 F4
+ * 23 F6
+ * ... ...
+ * 31 F22
+ */
+long
+FtoB(int f)
+{
+
+ if(f < 4 || f > 22 || (f&1))
+ return 0;
+ return 1L << (f/2 + 20);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0xffc00000L;
+ if(b == 0)
+ return 0;
+ return bitno(b)*2 - 40;
+}
diff --git a/utils/vc/sgen.c b/utils/vc/sgen.c
new file mode 100644
index 00000000..e4aa65e0
--- /dev/null
+++ b/utils/vc/sgen.c
@@ -0,0 +1,580 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG) {
+ if(typesuv[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ } else
+ if(firstarg && typechlp[firstargtype->etype]) {
+ nod1 = *nodret->left;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ nodreg(&nod, &nod1, REGARG);
+ gopcode(OAS, &nod, Z, &nod1);
+ }
+ }
+
+ retok = 0;
+ gen(n);
+ if(!retok)
+ if(thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ sp->to.offset += maxargsafe;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int o;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ retok = 0;
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ retok = 1;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typesuv[n->type->etype]) {
+ sugen(l, nodret, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ retok = 1;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ cas();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typechl[l->type->etype]) {
+ cas();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typechl[l->type->etype]) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ cas();
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right);
+ gbranch(OGOTO);
+ patch(p, breakpc);
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l); /* test */
+ patch(p, breakpc);
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OFOR:
+ l = n->left;
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left);
+ patch(p, breakpc);
+ }
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ break;
+
+ case OIF:
+ l = n->left;
+ bcomplex(l);
+ sp = p;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(l);
+ if(t >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ simplifyshift(n);
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ simplifyshift(n);
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ simplifyshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ if(com64(n))
+ return;
+
+ switch(n->op) {
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ case OEQ:
+ case ONE:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
+
+void
+bcomplex(Node *n)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type != T) {
+ bool64(n);
+ boolgen(n, 1, Z);
+ } else
+ gbranch(OGOTO);
+}
diff --git a/utils/vc/swt.c b/utils/vc/swt.c
new file mode 100644
index 00000000..0ec09b39
--- /dev/null
+++ b/utils/vc/swt.c
@@ -0,0 +1,717 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i;
+ Node tn;
+
+ def = 0;
+ nc = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ nc++;
+ }
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ q->val = c->val;
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8lux\n", i, iq[i].val);
+ if(def == 0)
+ def = breakpc;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val)
+ diag(n, "duplicate cases in switch %ld", iq[i].val);
+ regalloc(&tn, &regnode, Z);
+ swit1(iq, nc, def, n, &tn);
+ regfree(&tn);
+}
+
+void
+swit1(C1 *q, int nc, long def, Node *n, Node *tn)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8lux\n", q->val);
+ gmove(nodconst(q->val), tn);
+ gopcode(OEQ, n, tn, Z);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8lux\n", r->val);
+ gmove(nodconst(r->val), tn);
+ gopcode(OLT, tn, n, Z);
+ sp = p;
+ gopcode(OEQ, n, tn, Z);
+ patch(p, r->label);
+ swit1(q, i, def, n, tn);
+
+ if(debug['W'])
+ print("case < %.8lux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n, tn);
+}
+
+void
+cas(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ if(debug['M'] && debug['v'])
+ print("%L multiply: %ld\n", n->lineno, v);
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ if(v < 0)
+ gopcode(OSUB, &nod1, nodconst(0), &nod1);
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0));
+ p->from.offset += o+e;
+ p->reg = lw;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, a->cstring+e, lw);
+ }
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+
+ if(a->op == OCONST && typev[a->type->etype]) {
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+
+ bf[0] = p->as;
+ bf[1] = p->reg;
+ bf[2] = p->lineno;
+ bf[3] = p->lineno>>8;
+ bf[4] = p->lineno>>16;
+ bf[5] = p->lineno>>24;
+ bp = zaddr(bf+6, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ ulong sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ long l;
+ Ieee e;
+
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_MREG:
+ case D_FCREG:
+ case D_LO:
+ case D_HI:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ }
+ return bp;
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ o += SZ_LONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_LONG-1;
+ if(v > max)
+ max = round(v, SZ_LONG);
+ return max;
+}
diff --git a/utils/vc/txt.c b/utils/vc/txt.c
new file mode 100644
index 00000000..3ff08b93
--- /dev/null
+++ b/utils/vc/txt.c
@@ -0,0 +1,1440 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = 'v';
+ thestring = "mips";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 0;
+ if(i == REGZERO ||
+ (i >= NREG && ((i-NREG)&1)))
+ reg[i] = 1;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(i != REGZERO)
+ if(reg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NREG; i+=2)
+ if(reg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesuv[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typechlp[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gopcode(OAS, n, Z, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+int
+tmpreg(void)
+{
+ int i;
+
+ for(i=REGRET+1; i<NREG; i++)
+ if(reg[i] == 0)
+ return i;
+ diag(Z, "out of fixed registers");
+ return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i > 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<NREG; i++) {
+ if(j >= NREG)
+ j = REGRET+1;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NREG)
+ goto out;
+ }
+ j = 0*2 + NREG;
+ for(i=NREG; i<NREG+NREG; i+=2) {
+ if(j >= NREG+NREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j += 2;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ nodreg(n, tn, 0);
+ return;
+out:
+ reg[i]++;
+ lasti++;
+ if(lasti >= 5)
+ lasti = 0;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_LONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod, nod1, nod2;
+ Prog *p1;
+ double d;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ if(ft == TDOUBLE && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0.0) {
+ a = FREGZERO;
+ goto ffreg;
+ }
+ if(d == 0.5) {
+ a = FREGHALF;
+ goto ffreg;
+ }
+ if(d == 1.0) {
+ a = FREGONE;
+ goto ffreg;
+ }
+ if(d == 2.0) {
+ a = FREGTWO;
+ goto ffreg;
+ }
+ if(d == -.5) {
+ fop(OSUB, FREGHALF, FREGZERO, t);
+ return;
+ }
+ if(d == -1.0) {
+ fop(OSUB, FREGONE, FREGZERO, t);
+ return;
+ }
+ if(d == -2.0) {
+ fop(OSUB, FREGTWO, FREGZERO, t);
+ return;
+ }
+ if(d == 1.5) {
+ fop(OADD, FREGONE, FREGHALF, t);
+ return;
+ }
+ if(d == 2.5) {
+ fop(OADD, FREGTWO, FREGHALF, t);
+ return;
+ }
+ if(d == 3.0) {
+ fop(OADD, FREGTWO, FREGONE, t);
+ return;
+ }
+ }
+ if(ft == TFLOAT && f->op == OCONST) {
+ d = f->fconst;
+ if(d == 0) {
+ a = FREGZERO;
+ ffreg:
+ nodreg(&nod, f, NREG+a);
+ gmove(&nod, t);
+ return;
+ }
+ }
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ if(typefd[tt]) {
+ /* special case can load mem to Freg */
+ regalloc(&nod, t, t);
+ gins(AMOVW, f, &nod);
+ a = AMOVWD;
+ if(tt == TFLOAT)
+ a = AMOVWF;
+ gins(a, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVW;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ }
+ if(typechlp[ft] && typeilp[tt])
+ regalloc(&nod, t, t);
+ else
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ }
+ if(!typefd[ft] && vconst(f) == 0) {
+ gins(a, f, t);
+ return;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TDOUBLE:
+ case TVLONG:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ a = AMOVD;
+ if(ft == TFLOAT)
+ a = AMOVFD;
+ break;
+ case TFLOAT:
+ a = AMOVDF;
+ if(ft == TFLOAT)
+ a = AMOVF;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ if(fproundflg) {
+ /* convert f, t */
+ regalloc(&nod, f, Z);
+ gins(AMOVDW, f, &nod);
+ if(ft == TFLOAT)
+ p->as = AMOVFW;
+ gins(AMOVW, &nod, t);
+ regfree(&nod);
+ gins(AMOVW, t, t);
+ return;
+ }
+ regalloc(&nod1, &regnode, Z);
+ regalloc(&nod2, &regnode, Z);
+
+ /* movw fcr, rx */
+ gins(AMOVW, Z, &nod1);
+ p->from.type = D_FCREG;
+ p->from.reg = 31;
+
+ /* nop */
+ gins(ANOR, nodconst(0), nodconst(0));
+ p->to.type = D_REG;
+ p->to.reg = 0;
+
+ /* nop */
+ gins(ANOR, nodconst(0), nodconst(0));
+ p->to.type = D_REG;
+ p->to.reg = 0;
+
+ /* or $3, rx, ry */
+ gins(AOR, nodconst(3), &nod2);
+ p->reg = nod1.reg;
+
+ /* xor $2, ry */
+ gins(AXOR, nodconst(2), &nod2);
+
+ /* movw ry, fcr */
+ gins(AMOVW, &nod2, Z);
+ p->to.type = D_FCREG;
+ p->to.reg = 31;
+
+ /* nop */
+ gins(ANOR, nodconst(0), nodconst(0));
+ p->to.type = D_REG;
+ p->to.reg = 0;
+
+ /* nop */
+ gins(ANOR, nodconst(0), nodconst(0));
+ p->to.type = D_REG;
+ p->to.reg = 0;
+
+ /* convert f, t */
+ regalloc(&nod, f, Z);
+ gins(AMOVDW, f, &nod);
+ if(ft == TFLOAT)
+ p->as = AMOVFW;
+ gins(AMOVW, &nod, t);
+ regfree(&nod);
+ gins(AMOVW, t, t);
+
+ /* movw rx, fcr */
+ gins(AMOVW, &nod1, Z);
+ p->to.type = D_FCREG;
+ p->to.reg = 31;
+
+ /* nop */
+ gins(ANOR, nodconst(0), nodconst(0));
+ p->to.type = D_REG;
+ p->to.reg = 0;
+
+ /* nop */
+ gins(ANOR, nodconst(0), nodconst(0));
+ p->to.type = D_REG;
+ p->to.reg = 0;
+
+ regfree(&nod1);
+ regfree(&nod2);
+ return;
+ }
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ gins(AMOVW, f, t);
+ gins(AMOVWD, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGED, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVD, nodfconst(4294967296.), &nod);
+ gins(AADDD, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TFLOAT:
+ gins(AMOVW, f, t);
+ gins(AMOVWF, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGEF, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVF, nodfconst(4294967296.), &nod);
+ gins(AADDF, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ case TVLONG:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if(a == AMOVW || a == AMOVF || a == AMOVD)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et;
+ Adr ta;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ et = f1->type->etype;
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADDU;
+ if(et == TFLOAT)
+ a = AADDF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = AADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBU;
+ if(et == TFLOAT)
+ a = ASUBF;
+ else
+ if(et == TDOUBLE || et == TVLONG)
+ a = ASUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AOR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ break;
+
+ case OFUNC:
+ a = AJAL;
+ break;
+
+ case OCOND:
+ a = ASGTU;
+ break;
+
+ case OCOMMA:
+ a = ASGT;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT) {
+ a = AMULF;
+ break;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = AMULD;
+ break;
+ }
+ a = AMUL;
+ goto muldiv;
+
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = ADIVF;
+ break;
+ } else
+ if(et == TDOUBLE || et == TVLONG) {
+ a = ADIVD;
+ break;
+ }
+ a = ADIV;
+ goto muldiv;
+
+ case OASMOD:
+ case OMOD:
+ a = ADIV;
+ o = OMOD;
+ goto muldiv;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULU;
+ goto muldiv;
+
+ case OASLMOD:
+ case OLMOD:
+ a = ADIVU;
+ o = OMOD;
+ goto muldiv;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVU;
+ goto muldiv;
+
+ muldiv:
+ nextpc();
+ naddr(f1, &p->from);
+ if(f2 == Z)
+ raddr(t, p);
+ else
+ raddr(f2, p);
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+
+ nextpc();
+ p->as = AMOVW;
+ a = D_LO;
+ if(o == OMOD)
+ a = D_HI;
+ p->from.type = a;
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+
+ case OEQ:
+ if(!typefd[et]) {
+ a = ABEQ;
+ break;
+ }
+
+ case ONE:
+ if(!typefd[et]) {
+ a = ABNE;
+ break;
+ }
+
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ if(typefd[et]) {
+ nextpc();
+ if(et == TFLOAT) {
+ a = ACMPGTF;
+ if(o == OEQ || o == ONE)
+ a = ACMPEQF;
+ else
+ if(o == OLT || o == OGE)
+ a = ACMPGEF;
+ } else {
+ a = ACMPGTD;
+ if(o == OEQ || o == ONE)
+ a = ACMPEQD;
+ else
+ if(o == OLT || o == OGE)
+ a = ACMPGED;
+ }
+ p->as = a;
+ naddr(f1, &p->from);
+ raddr(f2, p);
+ if(debug['g'])
+ print("%P\n", p);
+ nextpc();
+ a = ABFPF;
+ if(o == OEQ || o == OGE || o == OGT)
+ a = ABFPT;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+ }
+ if(vconst(f1) == 0 || vconst(f2) == 0) {
+ if(vconst(f1) == 0) {
+ o = invrel[relindex(o)];
+ f1 = f2;
+ }
+ switch(o) {
+ case OLT:
+ a = ABLTZ;
+ break;
+ case OLE:
+ a = ABLEZ;
+ break;
+ case OGE:
+ a = ABGEZ;
+ break;
+ case OGT:
+ a = ABGTZ;
+ break;
+ }
+ f2 = Z;
+ break;
+ }
+
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ nextpc();
+ if(o == OLE || o == OGT || o == OLS || o == OHI) {
+ naddr(f1, &p->from);
+ raddr(f2, p);
+ } else {
+ naddr(f2, &p->from);
+ raddr(f1, p);
+ }
+ naddr(&regnode, &p->to);
+ p->to.reg = tmpreg();
+ a = ASGT;
+ if(o == OLO || o == OLS || o == OHS || o == OHI)
+ a = ASGTU;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+
+ nextpc();
+ naddr(&regnode, &p->from);
+ p->from.reg = tmpreg();
+ a = ABEQ;
+ if(o == OLT || o == OGT || o == OLO || o == OHI)
+ a = ABNE;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0)
+ p->reg = REGZERO;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ if(a == ATEXT)
+ p->reg = (profileflg ? 0 : NOPROF);
+ p->from.name = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= (vlong)(-32766) && vv < (vlong)32766)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+sval(long v)
+{
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= 16)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= 16)
+ return 0;
+ o = exfregoffset + NREG;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
diff --git a/utils/vc/v.out.h b/utils/vc/v.out.h
new file mode 100644
index 00000000..2fec2893
--- /dev/null
+++ b/utils/vc/v.out.h
@@ -0,0 +1,201 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 32
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+#define REGZERO 0
+#define REGRET 1
+#define REGARG 1
+/* compiler allocates R1 up as temps */
+/* compiler allocates register variables R3-R23 */
+#define REGEXT 25
+/* compiler allocates external registers R25 down */
+/* dont use R26 R27 */
+#define REGTMP 28
+#define REGSP 29
+#define REGSB 30
+#define REGLINK 31
+
+#define FREGRET 0
+/* compiler allocates register variables F4-F22 */
+/* compiler allocates external registers F22 down */
+#define FREGEXT 22
+#define FREGZERO 24 /* both float and double */
+#define FREGHALF 26 /* double */
+#define FREGONE 28 /* double */
+#define FREGTWO 30 /* double */
+
+enum as
+{
+ AXXX,
+
+ AABSD,
+ AABSF,
+ AABSW,
+ AADD,
+ AADDD,
+ AADDF,
+ AADDU,
+ AADDW,
+ AAND,
+ ABEQ,
+ ABFPF,
+ ABFPT,
+ ABGEZ,
+ ABGEZAL,
+ ABGTZ,
+ ABLEZ,
+ ABLTZ,
+ ABLTZAL,
+ ABNE,
+ ABREAK,
+ ACMPEQD,
+ ACMPEQF,
+ ACMPGED,
+ ACMPGEF,
+ ACMPGTD,
+ ACMPGTF,
+ ADATA,
+ ADIV,
+ ADIVD,
+ ADIVF,
+ ADIVU,
+ ADIVW,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AJAL,
+ AJMP,
+ AMOVB,
+ AMOVBU,
+ AMOVD,
+ AMOVDF,
+ AMOVDW,
+ AMOVF,
+ AMOVFD,
+ AMOVFW,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMOVWD,
+ AMOVWF,
+ AMOVWL,
+ AMOVWR,
+ AMUL,
+ AMULD,
+ AMULF,
+ AMULU,
+ AMULW,
+ ANAME,
+ ANEGD,
+ ANEGF,
+ ANEGW,
+ ANOP,
+ ANOR,
+ AOR,
+ AREM,
+ AREMU,
+ ARET,
+ ARFE,
+ ASGT,
+ ASGTU,
+ ASLL,
+ ASRA,
+ ASRL,
+ ASUB,
+ ASUBD,
+ ASUBF,
+ ASUBU,
+ ASUBW,
+ ASYSCALL,
+ ATEXT,
+ ATLBP,
+ ATLBR,
+ ATLBWI,
+ ATLBWR,
+ AWORD,
+ AXOR,
+
+ AEND,
+
+ AMOVV,
+ AMOVVL,
+ AMOVVR,
+ ASLLV,
+ ASRAV,
+ ASRLV,
+ ADIVV,
+ ADIVVU,
+ AREMV,
+ AREMVU,
+ AMULV,
+ AMULVU,
+ AADDV,
+ AADDVU,
+ ASUBV,
+ ASUBVU,
+
+ ADYNT,
+ AINIT,
+
+ ABCASE,
+ ACASE,
+
+ ATRUNCFV,
+ ATRUNCDV,
+ ATRUNCFW,
+ ATRUNCDW,
+ AMOVWU,
+ AMOVFV,
+ AMOVDV,
+ AMOVVF,
+ AMOVVD,
+
+ ASIGNAME,
+
+ ALAST,
+};
+
+/* type/name */
+#define D_GOK 0
+#define D_NONE 1
+
+/* type */
+#define D_BRANCH (D_NONE+1)
+#define D_OREG (D_NONE+2)
+#define D_EXTERN (D_NONE+3) /* name */
+#define D_STATIC (D_NONE+4) /* name */
+#define D_AUTO (D_NONE+5) /* name */
+#define D_PARAM (D_NONE+6) /* name */
+#define D_CONST (D_NONE+7)
+#define D_FCONST (D_NONE+8)
+#define D_SCONST (D_NONE+9)
+#define D_HI (D_NONE+10)
+#define D_LO (D_NONE+11)
+#define D_REG (D_NONE+12)
+#define D_FREG (D_NONE+13)
+#define D_FCREG (D_NONE+14)
+#define D_MREG (D_NONE+15)
+#define D_FILE (D_NONE+16)
+#define D_OCONST (D_NONE+17)
+#define D_FILE1 (D_NONE+18)
+#define D_VCONST (D_NONE+19)
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
diff --git a/utils/vl/Nt.c b/utils/vl/Nt.c
new file mode 100644
index 00000000..73c6f795
--- /dev/null
+++ b/utils/vl/Nt.c
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
diff --git a/utils/vl/Plan9.c b/utils/vl/Plan9.c
new file mode 100644
index 00000000..f4cf23f4
--- /dev/null
+++ b/utils/vl/Plan9.c
@@ -0,0 +1,57 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/vl/Posix.c b/utils/vl/Posix.c
new file mode 100644
index 00000000..7c3a661f
--- /dev/null
+++ b/utils/vl/Posix.c
@@ -0,0 +1,80 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fials if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
diff --git a/utils/vl/asm.c b/utils/vl/asm.c
new file mode 100644
index 00000000..28ec1a89
--- /dev/null
+++ b/utils/vl/asm.c
@@ -0,0 +1,1403 @@
+#include "l.h"
+
+long OFFSET;
+/*
+long BADOFFSET = -1;
+
+ if(OFFSET <= BADOFFSET && OFFSET+4 > BADOFFSET)\
+ abort();\
+ OFFSET += 4;\
+
+ if(OFFSET == BADOFFSET)\
+ abort();\
+ OFFSET++;\
+*/
+
+#define LPUT(c)\
+ {\
+ cbp[0] = (c)>>24;\
+ cbp[1] = (c)>>16;\
+ cbp[2] = (c)>>8;\
+ cbp[3] = (c);\
+ cbp += 4;\
+ cbc -= 4;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define CPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp++;\
+ cbc--;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+long
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT && s->type != SLEAF)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long t, etext;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asm\n", cputime());
+ Bflush(&bso);
+ OFFSET = HEADR;
+ seek(cout, OFFSET, 0);
+ pc = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ }
+ if(p->pc != pc) {
+ diag("phase error %lux sb %lux",
+ p->pc, pc);
+ if(!debug['a'])
+ prasm(curp);
+ pc = p->pc;
+ }
+ curp = p;
+ o = oplook(p); /* could probably avoid this call */
+ if(asmout(p, o, 0)) {
+ p = p->link;
+ pc += 4;
+ }
+ pc += o->size;
+ }
+ if(debug['a'])
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ cflush();
+
+ etext = INITTEXT + textsize;
+ for(t = pc; t < etext; t += sizeof(buf)-100) {
+ if(etext-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100, 1);
+ else
+ datblk(t, etext-t, 1);
+ }
+
+ Bflush(&bso);
+ cflush();
+
+ curtext = P;
+ switch(HEADTYPE) {
+ case 0:
+ case 4:
+ OFFSET = rnd(HEADR+textsize, 4096);
+ seek(cout, OFFSET, 0);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ OFFSET = HEADR+textsize;
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ for(t = 0; t < datsize; t += sizeof(buf)-100) {
+ if(datsize-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100, 0);
+ else
+ datblk(t, datsize-t, 0);
+ }
+
+ symsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ case 0:
+ case 4:
+ OFFSET = rnd(HEADR+textsize, 4096)+datsize;
+ seek(cout, OFFSET, 0);
+ break;
+ case 3:
+ case 2:
+ case 1:
+ case 5:
+ OFFSET = HEADR+textsize+datsize;
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ cflush();
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f header\n", cputime());
+ Bflush(&bso);
+ OFFSET = 0;
+ seek(cout, OFFSET, 0);
+ switch(HEADTYPE) {
+ case 0:
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+ lput((0413<<16)|0437L); /* magic and version */
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT-HEADR); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ break;
+ case 1:
+ lput(0x160L<<16); /* magic and sections */
+ lput(0L); /* time and date */
+ lput(HEADR+textsize+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+
+ lput((0407<<16)|0437L); /* magic and version */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(lcsize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+ lput(0L); /* complete mystery */
+ break;
+ case 2:
+ lput(0x407); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ lput(entryvalue()); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ break;
+ case 3:
+ lput((0x160L<<16)|3L); /* magic and sections */
+ lput(time(0)); /* time and date */
+ lput(HEADR+textsize+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+
+ lput((0407<<16)|0437L); /* magic and version */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(lcsize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+
+ strnput(".text", 8); /* text segment */
+ lput(INITTEXT); /* address */
+ lput(INITTEXT);
+ lput(textsize);
+ lput(HEADR);
+ lput(0L);
+ lput(HEADR+textsize+datsize+symsize);
+ lput(lcsize); /* line number size */
+ lput(0x20L); /* flags */
+
+ strnput(".data", 8); /* data segment */
+ lput(INITDAT); /* address */
+ lput(INITDAT);
+ lput(datsize);
+ lput(HEADR+textsize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0x40L); /* flags */
+
+ strnput(".bss", 8); /* bss segment */
+ lput(INITDAT+datsize); /* address */
+ lput(INITDAT+datsize);
+ lput(bsssize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0x80L); /* flags */
+ break;
+ case 4:
+
+ lput((0x160L<<16)|3L); /* magic and sections */
+ lput(time(0)); /* time and date */
+ lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(symsize); /* nsyms */
+ lput((0x38L<<16)|7L); /* size of optional hdr and flags */
+
+ lput((0413<<16)|01012L); /* magic and version */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(entryvalue()); /* va of entry */
+ lput(INITTEXT); /* va of base of text */
+ lput(INITDAT); /* va of base of data */
+ lput(INITDAT+datsize); /* va of base of bss */
+ lput(~0L); /* gp reg mask */
+ lput(lcsize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(~0L); /* gp value ?? */
+
+ strnput(".text", 8); /* text segment */
+ lput(INITTEXT); /* address */
+ lput(INITTEXT);
+ lput(textsize);
+ lput(HEADR);
+ lput(0L);
+ lput(HEADR+textsize+datsize+symsize);
+ lput(lcsize); /* line number size */
+ lput(0x20L); /* flags */
+
+ strnput(".data", 8); /* data segment */
+ lput(INITDAT); /* address */
+ lput(INITDAT);
+ lput(datsize);
+ lput(rnd(HEADR+textsize, 4096)); /* sizes */
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0x40L); /* flags */
+
+ strnput(".bss", 8); /* bss segment */
+ lput(INITDAT+datsize); /* address */
+ lput(INITDAT+datsize);
+ lput(bsssize);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0L);
+ lput(0x80L); /* flags */
+ break;
+ case 5:
+ strnput("\177ELF", 4); /* e_ident */
+ CPUT(1); /* class = 32 bit */
+ CPUT(2); /* data = MSB */
+ CPUT(1); /* version = CURRENT */
+ strnput("", 9);
+ lput((2L<<16)|8L); /* type = EXEC; machine = MIPS */
+ lput(1L); /* version = CURRENT */
+ lput(entryvalue()); /* entry vaddr */
+ lput(52L); /* offset to first phdr */
+ lput(0L); /* offset to first shdr */
+ lput(0L); /* flags = MIPS */
+ lput((52L<<16)|32L); /* Ehdr & Phdr sizes*/
+ lput((3L<<16)|0L); /* # Phdrs & Shdr size */
+ lput((0L<<16)|0L); /* # Shdrs & shdr string size */
+
+ lput(1L); /* text - type = PT_LOAD */
+ lput(0L); /* file offset */
+ lput(INITTEXT-HEADR); /* vaddr */
+ lput(INITTEXT-HEADR); /* paddr */
+ lput(HEADR+textsize); /* file size */
+ lput(HEADR+textsize); /* memory size */
+ lput(0x05L); /* protections = RX */
+ lput(0x10000L); /* alignment code?? */
+
+ lput(1L); /* data - type = PT_LOAD */
+ lput(HEADR+textsize); /* file offset */
+ lput(INITDAT); /* vaddr */
+ lput(INITDAT); /* paddr */
+ lput(datsize); /* file size */
+ lput(datsize+bsssize); /* memory size */
+ lput(0x06L); /* protections = RW */
+ lput(0x10000L); /* alignment code?? */
+
+ lput(0L); /* data - type = PT_NULL */
+ lput(HEADR+textsize+datsize); /* file offset */
+ lput(0L);
+ lput(0L);
+ lput(symsize); /* symbol table size */
+ lput(lcsize); /* line number size */
+ lput(0x04L); /* protections = R */
+ lput(0x04L); /* alignment code?? */
+ }
+ cflush();
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s; s++){
+ CPUT(*s);
+ n--;
+ }
+ for(; n > 0; n--)
+ CPUT(0);
+}
+
+void
+lput(long l)
+{
+
+ LPUT(l);
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+nopstat(char *f, Count *c)
+{
+ if(c->outof)
+ Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
+ c->outof - c->count, c->outof,
+ (double)(c->outof - c->count)/c->outof);
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SSTRING:
+ putsymb(s->name, 'T', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->cond) {
+ s = p->from.sym;
+ if(s->type != STEXT && s->type != SLEAF)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+ else
+ putsymb(s->name, 'L', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+4, 0);
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+putsymb(char *s, int t, long v, int ver)
+{
+ int i, f;
+
+ if(t == 'f')
+ s++;
+ LPUT(v);
+ if(ver)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ CPUT(s[i]);
+ CPUT(s[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ CPUT(s[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8lux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8lux %s\n", t, v, s);
+ }
+}
+
+#define MINLC 4
+void
+asmlc(void)
+{
+ long oldpc, oldlc;
+ Prog *p;
+ long v, s;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['L'])
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ continue;
+ }
+ if(debug['L'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['L'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['L']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['L']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6lux %P\n",
+ p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['L'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+void
+datblk(long s, long n, int str)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j, d;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ if(str != (p->from.sym->type == SSTRING))
+ continue;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->reg;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ default:
+ diag("unknown mode in initialization\n%P", p);
+ break;
+
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(p->to.ieee);
+ cast = (char*)&fl;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i+4]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.sval[i];
+ l++;
+ }
+ break;
+
+ case D_CONST:
+ d = p->to.offset;
+ if(p->to.sym) {
+ switch(p->to.sym->type) {
+ case STEXT:
+ case SLEAF:
+ case SSTRING:
+ d += p->to.sym->value;
+ break;
+ case SDATA:
+ case SBSS:
+ d += p->to.sym->value + INITDAT;
+ break;
+ }
+ }
+ cast = (char*)&d;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+#define OP_RRR(op,r1,r2,r3)\
+ (op|(((r1)&31L)<<16)|(((r2)&31L)<<21)|(((r3)&31L)<<11))
+#define OP_IRR(op,i,r2,r3)\
+ (op|((i)&0xffffL)|(((r2)&31L)<<21)|(((r3)&31L)<<16))
+#define OP_SRR(op,s,r2,r3)\
+ (op|(((s)&31L)<<6)|(((r2)&31L)<<16)|(((r3)&31L)<<11))
+#define OP_FRRR(op,r1,r2,r3)\
+ (op|(((r1)&31L)<<16)|(((r2)&31L)<<11)|(((r3)&31L)<<6))
+#define OP_JMP(op,i)\
+ ((op)|((i)&0x3ffffffL))
+
+#define OP(x,y)\
+ (((x)<<3)|((y)<<0))
+#define SP(x,y)\
+ (((x)<<29)|((y)<<26))
+#define BCOND(x,y)\
+ (((x)<<19)|((y)<<16))
+#define MMU(x,y)\
+ (SP(2,0)|(16<<21)|((x)<<3)|((y)<<0))
+#define FPF(x,y)\
+ (SP(2,1)|(16<<21)|((x)<<3)|((y)<<0))
+#define FPD(x,y)\
+ (SP(2,1)|(17<<21)|((x)<<3)|((y)<<0))
+#define FPW(x,y)\
+ (SP(2,1)|(20<<21)|((x)<<3)|((y)<<0))
+
+int vshift(int);
+
+int
+asmout(Prog *p, Optab *o, int aflag)
+{
+ long o1, o2, o3, o4, o5, o6, o7, v;
+ Prog *ct;
+ int r, a;
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ o6 = 0;
+ o7 = 0;
+ switch(o->type) {
+ default:
+ diag("unknown type %d", o->type);
+ if(!debug['a'])
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ if(aflag) {
+ if(p->link) {
+ if(p->as == ATEXT) {
+ ct = curtext;
+ o2 = autosize;
+ curtext = p;
+ autosize = p->to.offset + 4;
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ curtext = ct;
+ autosize = o2;
+ } else
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ }
+ return o1;
+ }
+ break;
+
+ case 1: /* mov[v] r1,r2 ==> OR r1,r0,r2 */
+ o1 = OP_RRR(oprrr(AOR), p->from.reg, REGZERO, p->to.reg);
+ break;
+
+ case 2: /* add/sub r1,[r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 3: /* mov $soreg, r ==> or/add $i,o,r */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ a = AADDU;
+ if(o->a1 == C_ANDCON)
+ a = AOR;
+ o1 = OP_IRR(opirr(a), v, r, p->to.reg);
+ break;
+
+ case 4: /* add $scon,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_IRR(opirr(p->as), v, r, p->to.reg);
+ break;
+
+ case 5: /* syscall */
+ if(aflag)
+ return 0;
+ o1 = oprrr(p->as);
+ break;
+
+ case 6: /* beq r1,[r2],sbra */
+ if(aflag)
+ return 0;
+ if(p->cond == P)
+ v = -4 >> 2;
+ else
+ v = (p->cond->pc - pc-4) >> 2;
+ if(((v << 16) >> 16) != v)
+ diag("short branch too far: %d\n%P", v, p);
+ o1 = OP_IRR(opirr(p->as), v, p->from.reg, p->reg);
+ break;
+
+ case 7: /* mov r, soreg ==> sw o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = OP_IRR(opirr(p->as), v, r, p->from.reg);
+ break;
+
+ case 8: /* mov soreg, r ==> lw o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(p->as+ALAST), v, r, p->to.reg);
+ break;
+
+ case 9: /* asl r1,[r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg);
+ break;
+
+ case 10: /* add $con,[r1],r2 ==> mov $con,t; add t,[r1],r2 */
+ v = regoff(&p->from);
+ r = AOR;
+ if(v < 0)
+ r = AADDU;
+ o1 = OP_IRR(opirr(r), v, 0, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 11: /* jmp lbra */
+ if(aflag)
+ return 0;
+ if(p->cond == P)
+ v = p->pc >> 2;
+ else
+ v = p->cond->pc >> 2;
+ o1 = OP_JMP(opirr(p->as), v);
+ if(!debug['Y'] && p->link && p->cond && isnop(p->link)) {
+ nop.branch.count--;
+ nop.branch.outof--;
+ nop.jump.outof++;
+ o2 = asmout(p->cond, oplook(p->cond), 1);
+ if(o2) {
+ o1 += 1;
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n",
+ p->pc, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ return 1;
+ }
+ }
+ break;
+
+ case 12: /* movbs r,r */
+ v = 16;
+ if(p->as == AMOVB)
+ v = 24;
+ o1 = OP_SRR(opirr(ASLL), v, p->from.reg, p->to.reg);
+ o2 = OP_SRR(opirr(ASRA), v, p->to.reg, p->to.reg);
+ break;
+
+ case 13: /* movbu r,r */
+ if(p->as == AMOVBU)
+ o1 = OP_IRR(opirr(AAND), 0xffL, p->from.reg, p->to.reg);
+ else
+ o1 = OP_IRR(opirr(AAND), 0xffffL, p->from.reg, p->to.reg);
+ break;
+
+ case 16: /* sll $c,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+
+ /* OP_SRR will use only the low 5 bits of the shift value */
+ if(v >= 32 && vshift(p->as))
+ o1 = OP_SRR(opirr(p->as+ALAST), v-32, r, p->to.reg);
+ else
+ o1 = OP_SRR(opirr(p->as), v, r, p->to.reg);
+ break;
+
+ case 18: /* jmp [r1],0(r2) */
+ if(aflag)
+ return 0;
+ r = p->reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = OP_RRR(oprrr(p->as), 0, p->to.reg, r);
+ break;
+
+ case 19: /* mov $lcon,r ==> lu+or */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg);
+ o2 = OP_IRR(opirr(AOR), v, p->to.reg, p->to.reg);
+ break;
+
+ case 20: /* mov lohi,r */
+ r = OP(2,0); /* mfhi */
+ if(p->from.type == D_LO)
+ r = OP(2,2); /* mflo */
+ o1 = OP_RRR(r, REGZERO, REGZERO, p->to.reg);
+ break;
+
+ case 21: /* mov r,lohi */
+ r = OP(2,1); /* mthi */
+ if(p->to.type == D_LO)
+ r = OP(2,3); /* mtlo */
+ o1 = OP_RRR(r, REGZERO, p->from.reg, REGZERO);
+ break;
+
+ case 22: /* mul r1,r2 */
+ o1 = OP_RRR(oprrr(p->as), p->from.reg, p->reg, REGZERO);
+ break;
+
+ case 23: /* add $lcon,r1,r2 ==> lu+or+add */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 24: /* mov $ucon,,r ==> lu r */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg);
+ break;
+
+ case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */
+ v = regoff(&p->from);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 26: /* mov $lsext/auto/oreg,,r2 ==> lu+or+add */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o3 = OP_RRR(oprrr(AADDU), REGTMP, r, p->to.reg);
+ break;
+
+ case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ switch(o->size) {
+ case 20:
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(AMOVF+ALAST), 0, REGTMP, p->to.reg+1);
+ o5 = OP_IRR(opirr(AMOVF+ALAST), 4, REGTMP, p->to.reg);
+ break;
+ case 16:
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(AMOVF+ALAST), 0, REGTMP, p->to.reg);
+ break;
+ case 8:
+ o1 = OP_IRR(opirr(AMOVF+ALAST), v, r, p->to.reg+1);
+ o2 = OP_IRR(opirr(AMOVF+ALAST), v+4, r, p->to.reg);
+ break;
+ case 4:
+ o1 = OP_IRR(opirr(AMOVF+ALAST), v, r, p->to.reg);
+ break;
+ }
+ break;
+
+ case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ switch(o->size) {
+ case 20:
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(AMOVF), 0, REGTMP, p->from.reg+1);
+ o5 = OP_IRR(opirr(AMOVF), 4, REGTMP, p->from.reg);
+ break;
+ case 16:
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(AMOVF), 0, REGTMP, p->from.reg);
+ break;
+ case 8:
+ o1 = OP_IRR(opirr(AMOVF), v, r, p->from.reg+1);
+ o2 = OP_IRR(opirr(AMOVF), v+4, r, p->from.reg);
+ break;
+ case 4:
+ o1 = OP_IRR(opirr(AMOVF), v, r, p->from.reg);
+ break;
+ }
+ break;
+
+ case 30: /* movw r,fr */
+ r = SP(2,1)|(4<<21); /* mtc1 */
+ o1 = OP_RRR(r, p->from.reg, 0, p->to.reg);
+ break;
+
+ case 31: /* movw fr,r */
+ r = SP(2,1)|(0<<21); /* mfc1 */
+ o1 = OP_RRR(r, p->to.reg, 0, p->from.reg);
+ break;
+
+ case 32: /* fadd fr1,[fr2],fr3 */
+ r = p->reg;
+ if(r == NREG)
+ o1 = OP_FRRR(oprrr(p->as), p->from.reg, p->to.reg, p->to.reg);
+ else
+ o1 = OP_FRRR(oprrr(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 33: /* fabs fr1,fr3 */
+ o1 = OP_FRRR(oprrr(p->as), 0, p->from.reg, p->to.reg);
+ break;
+
+ case 34: /* mov $con,fr ==> or/add $i,r,r2 */
+ v = regoff(&p->from);
+ r = AADDU;
+ if(o->a1 == C_ANDCON)
+ r = AOR;
+ o1 = OP_IRR(opirr(r), v, 0, REGTMP);
+ o2 = OP_RRR(SP(2,1)|(4<<21), REGTMP, 0, p->to.reg); /* mtc1 */
+ break;
+
+ case 35: /* mov r,lext/luto/oreg ==> sw o(r) */
+ /*
+ * the lowbits of the constant cannot
+ * be moved into the offset of the load
+ * because the mips 4000 in 64-bit mode
+ * does a 64-bit add and it will screw up.
+ */
+ v = regoff(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(p->as), 0, REGTMP, p->from.reg);
+ break;
+
+ case 36: /* mov lext/lauto/lreg,r ==> lw o(r30) */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP);
+ o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(p->as+ALAST), 0, REGTMP, p->to.reg);
+ break;
+
+ case 37: /* movw r,mr */
+ r = SP(2,0)|(4<<21); /* mtc0 */
+ if(p->as == AMOVV)
+ r = SP(2,0)|(5<<21); /* dmtc0 */
+ o1 = OP_RRR(r, p->from.reg, 0, p->to.reg);
+ break;
+
+ case 38: /* movw mr,r */
+ r = SP(2,0)|(0<<21); /* mfc0 */
+ if(p->as == AMOVV)
+ r = SP(2,0)|(1<<21); /* dmfc0 */
+ o1 = OP_RRR(r, p->to.reg, 0, p->from.reg);
+ break;
+
+ case 39: /* rfe ==> jmp+rfe */
+ if(aflag)
+ return 0;
+ o1 = OP_RRR(oprrr(AJMP), 0, p->to.reg, REGZERO);
+ o2 = oprrr(p->as);
+ break;
+
+ case 40: /* word */
+ if(aflag)
+ return 0;
+ o1 = regoff(&p->to);
+ break;
+
+ case 41: /* movw r,fcr */
+ o1 = OP_RRR(SP(2,1)|(2<<21), REGZERO, 0, p->to.reg); /* mfcc1 */
+ o2 = OP_RRR(SP(2,1)|(6<<21), p->from.reg, 0, p->to.reg);/* mtcc1 */
+ break;
+
+ case 42: /* movw fcr,r */
+ o1 = OP_RRR(SP(2,1)|(2<<21), p->to.reg, 0, p->from.reg);/* mfcc1 */
+ break;
+
+ case 45: /* case r */
+ if(p->link == P)
+ v = p->pc+28;
+ else
+ v = p->link->pc;
+ if(v & (1<<15))
+ o1 = OP_IRR(opirr(ALAST), (v>>16)+1, REGZERO, REGTMP);
+ else
+ o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP);
+ o2 = OP_SRR(opirr(ASLL), 2, p->from.reg, p->from.reg);
+ o3 = OP_RRR(oprrr(AADD), p->from.reg, REGTMP, REGTMP);
+ o4 = OP_IRR(opirr(AMOVW+ALAST), v, REGTMP, REGTMP);
+ o5 = OP_RRR(oprrr(ANOR), REGZERO, REGZERO, REGZERO);
+ o6 = OP_RRR(oprrr(AJMP), 0, REGTMP, REGZERO);
+ o7 = OP_RRR(oprrr(ANOR), REGZERO, REGZERO, REGZERO);
+ break;
+
+ case 46: /* bcase $con,lbra */
+ if(p->cond == P)
+ v = p->pc;
+ else
+ v = p->cond->pc;
+ o1 = v;
+ break;
+ }
+ if(aflag)
+ return o1;
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ LPUT(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ LPUT(o5);
+ break;
+
+ case 28:
+ if(debug['a'])
+ Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, o6, o7, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ LPUT(o5);
+ LPUT(o6);
+ LPUT(o7);
+ break;
+ }
+ return 0;
+}
+
+int
+isnop(Prog *p)
+{
+ if(p->as != ANOR)
+ return 0;
+ if(p->reg != REGZERO && p->reg != NREG)
+ return 0;
+ if(p->from.type != D_REG || p->from.reg != REGZERO)
+ return 0;
+ if(p->to.type != D_REG || p->to.reg != REGZERO)
+ return 0;
+ return 1;
+}
+
+long
+oprrr(int a)
+{
+ switch(a) {
+ case AADD: return OP(4,0);
+ case AADDU: return OP(4,1);
+ case ASGT: return OP(5,2);
+ case ASGTU: return OP(5,3);
+ case AAND: return OP(4,4);
+ case AOR: return OP(4,5);
+ case AXOR: return OP(4,6);
+ case ASUB: return OP(4,2);
+ case ASUBU: return OP(4,3);
+ case ANOR: return OP(4,7);
+ case ASLL: return OP(0,4);
+ case ASRL: return OP(0,6);
+ case ASRA: return OP(0,7);
+
+ case AREM:
+ case ADIV: return OP(3,2);
+ case AREMU:
+ case ADIVU: return OP(3,3);
+ case AMUL: return OP(3,0);
+ case AMULU: return OP(3,1);
+
+ case AJMP: return OP(1,0);
+ case AJAL: return OP(1,1);
+
+ case ABREAK: return OP(1,5);
+ case ASYSCALL: return OP(1,4);
+ case ATLBP: return MMU(1,0);
+ case ATLBR: return MMU(0,1);
+ case ATLBWI: return MMU(0,2);
+ case ATLBWR: return MMU(0,6);
+ case ARFE: return MMU(2,0);
+
+ case ADIVF: return FPF(0,3);
+ case ADIVD: return FPD(0,3);
+ case AMULF: return FPF(0,2);
+ case AMULD: return FPD(0,2);
+ case ASUBF: return FPF(0,1);
+ case ASUBD: return FPD(0,1);
+ case AADDF: return FPF(0,0);
+ case AADDD: return FPD(0,0);
+
+ case AMOVFW: return FPF(4,4);
+ case AMOVDW: return FPD(4,4);
+ case AMOVWF: return FPW(4,0);
+ case AMOVDF: return FPD(4,0);
+ case AMOVWD: return FPW(4,1);
+ case AMOVFD: return FPF(4,1);
+ case AABSF: return FPF(0,5);
+ case AABSD: return FPD(0,5);
+ case AMOVF: return FPF(0,6);
+ case AMOVD: return FPD(0,6);
+ case ANEGF: return FPF(0,7);
+ case ANEGD: return FPD(0,7);
+
+ case ACMPEQF: return FPF(6,2);
+ case ACMPEQD: return FPD(6,2);
+ case ACMPGTF: return FPF(7,4);
+ case ACMPGTD: return FPD(7,4);
+ case ACMPGEF: return FPF(7,6);
+ case ACMPGED: return FPD(7,6);
+
+ case ADIVV: return OP(3,6);
+ case ADIVVU: return OP(3,7);
+ case AADDV: return OP(5,4);
+ case AADDVU: return OP(5,5);
+ }
+ diag("bad rrr %d", a);
+ return 0;
+}
+
+long
+opirr(int a)
+{
+ switch(a) {
+ case AADD: return SP(1,0);
+ case AADDU: return SP(1,1);
+ case ASGT: return SP(1,2);
+ case ASGTU: return SP(1,3);
+ case AAND: return SP(1,4);
+ case AOR: return SP(1,5);
+ case AXOR: return SP(1,6);
+ case ALAST: return SP(1,7);
+ case ASLL: return OP(0,0);
+ case ASRL: return OP(0,2);
+ case ASRA: return OP(0,3);
+
+ case AJMP: return SP(0,2);
+ case AJAL: return SP(0,3);
+ case ABEQ: return SP(0,4);
+ case ABNE: return SP(0,5);
+
+ case ABGEZ: return SP(0,1)|BCOND(0,1);
+ case ABGEZAL: return SP(0,1)|BCOND(2,1);
+ case ABGTZ: return SP(0,7);
+ case ABLEZ: return SP(0,6);
+ case ABLTZ: return SP(0,1)|BCOND(0,0);
+ case ABLTZAL: return SP(0,1)|BCOND(2,0);
+
+ case ABFPT: return SP(2,1)|(257<<16);
+ case ABFPF: return SP(2,1)|(256<<16);
+
+ case AMOVB:
+ case AMOVBU: return SP(5,0);
+ case AMOVH:
+ case AMOVHU: return SP(5,1);
+ case AMOVW: return SP(5,3);
+ case AMOVV: return SP(7,7);
+ case AMOVF: return SP(7,1);
+ case AMOVWL: return SP(5,2);
+ case AMOVWR: return SP(5,6);
+ case AMOVVL: return SP(5,4);
+ case AMOVVR: return SP(5,5);
+
+ case ABREAK: return SP(5,7);
+
+ case AMOVWL+ALAST: return SP(4,2);
+ case AMOVWR+ALAST: return SP(4,6);
+ case AMOVVL+ALAST: return SP(3,2);
+ case AMOVVR+ALAST: return SP(3,3);
+ case AMOVB+ALAST: return SP(4,0);
+ case AMOVBU+ALAST: return SP(4,4);
+ case AMOVH+ALAST: return SP(4,1);
+ case AMOVHU+ALAST: return SP(4,5);
+ case AMOVW+ALAST: return SP(4,3);
+ case AMOVV+ALAST: return SP(6,7);
+ case AMOVF+ALAST: return SP(6,1);
+
+ case ASLLV: return OP(7,0);
+ case ASRLV: return OP(7,2);
+ case ASRAV: return OP(7,3);
+ case ASLLV+ALAST: return OP(7,4);
+ case ASRLV+ALAST: return OP(7,6);
+ case ASRAV+ALAST: return OP(7,7);
+
+ case AADDV: return SP(3,0);
+ case AADDVU: return SP(3,1);
+ }
+ diag("bad irr %d", a);
+abort();
+ return 0;
+}
+
+int
+vshift(int a)
+{
+ switch(a){
+ case ASLLV: return 1;
+ case ASRLV: return 1;
+ case ASRAV: return 1;
+ }
+ return 0;
+}
diff --git a/utils/vl/compat.c b/utils/vl/compat.c
new file mode 100644
index 00000000..5e676913
--- /dev/null
+++ b/utils/vl/compat.c
@@ -0,0 +1,50 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(long n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(long m, long n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, long n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
diff --git a/utils/vl/l.h b/utils/vl/l.h
new file mode 100644
index 00000000..1cac8768
--- /dev/null
+++ b/utils/vl/l.h
@@ -0,0 +1,327 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../vc/v.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Adr Adr;
+typedef struct Sym Sym;
+typedef struct Autom Auto;
+typedef struct Prog Prog;
+typedef struct Optab Optab;
+typedef struct Oprang Oprang;
+typedef uchar Opcross[32][2][32];
+typedef struct Count Count;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ long u0offset;
+ char* u0sval;
+ Ieee* u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ char type;
+ char reg;
+ char name;
+ char class;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0regused;
+ Prog* u0forwd;
+ } u0;
+ Prog* cond;
+ Prog* link;
+ long pc;
+ long line;
+ uchar mark;
+ uchar optab;
+ char as;
+ char reg;
+};
+#define regused u0.u0regused
+#define forwd u0.u0forwd
+
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ long value;
+ Sym* link;
+};
+struct Autom
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Optab
+{
+ char as;
+ char a1;
+ char a2;
+ char a3;
+ char type;
+ char size;
+ char param;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+struct Count
+{
+ long count;
+ long outof;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SLEAF,
+ SFILE,
+ SCONST,
+ SSTRING,
+
+ C_NONE = 0,
+ C_REG,
+ C_FREG,
+ C_FCREG,
+ C_MREG,
+ C_HI,
+ C_LO,
+ C_ZCON,
+ C_SCON,
+ C_ADD0CON,
+ C_AND0CON,
+ C_ADDCON,
+ C_ANDCON,
+ C_UCON,
+ C_LCON,
+ C_SACON,
+ C_SECON,
+ C_LACON,
+ C_LECON,
+ C_SBRA,
+ C_LBRA,
+ C_SAUTO,
+ C_SEXT,
+ C_LAUTO,
+ C_LEXT,
+ C_ZOREG,
+ C_SOREG,
+ C_LOREG,
+ C_GOK,
+
+ NSCHED = 20,
+
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+ SYNC = 1<<3,
+ BRANCH = 1<<4,
+ LOAD = 1<<5,
+ FCMP = 1<<6,
+ NOSCHED = 1<<7,
+
+ BIG = 32766,
+ STRINGSZ = 200,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+};
+
+EXTERN union
+{
+ struct
+ {
+ uchar obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+EXTERN long HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN long INITDAT; /* data location */
+EXTERN long INITRND; /* data round above text location */
+EXTERN long INITTEXT; /* text location */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN long autosize;
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN uchar* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi4[4]; /* for 3l [sic] */
+EXTERN char fnuxi8[8];
+EXTERN char* noname;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char* hunk;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN long instoffset;
+EXTERN Opcross opcross[10];
+EXTERN Oprang oprange[ALAST];
+EXTERN char* outfile;
+EXTERN long pc;
+EXTERN uchar repop[ALAST];
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN long textsize;
+EXTERN long thunk;
+EXTERN int version;
+EXTERN char xcmp[32][32];
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+EXTERN struct
+{
+ Count branch;
+ Count fcmp;
+ Count load;
+ Count mfrom;
+ Count page;
+ Count jump;
+} nop;
+
+extern char* anames[];
+extern Optab optab[];
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Nconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int aclass(Adr*);
+void addhist(long, int);
+void addnop(Prog*);
+void append(Prog*, Prog*);
+void asmb(void);
+void asmlc(void);
+int asmout(Prog*, Optab*, int);
+void asmsym(void);
+long atolwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void buildrep(int, int);
+void cflush(void);
+int cmp(int, int);
+int compound(Prog*);
+double cputime(void);
+void datblk(long, long, int);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+long entryvalue(void);
+void errorexit(void);
+void exchange(Prog*);
+int find1(long, int);
+void follow(void);
+void gethunk(void);
+void histtoauto(void);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+int isnop(Prog*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void lput(long);
+void mkfwd(void);
+void* mysbrk(ulong);
+void names(void);
+void nocache(Prog*);
+void noops(void);
+void nuxiinit(void);
+void objfile(char*);
+int ocmp(const void*, const void*);
+long opirr(int);
+Optab* oplook(Prog*);
+long oprrr(int);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+void putsymb(char*, int, long, int);
+long regoff(Adr*);
+int relinv(int);
+long rnd(long, long);
+void sched(Prog*, Prog*);
+void span(void);
+void strnput(char*, int);
+void undef(void);
+void xdefine(char*, int, long);
+void xfol(Prog*);
+void xfol(Prog*);
+void nopstat(char*, Count*);
diff --git a/utils/vl/list.c b/utils/vl/list.c
new file mode 100644
index 00000000..9261bc8e
--- /dev/null
+++ b/utils/vl/list.c
@@ -0,0 +1,277 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ if(a == ADATA || a == ADYNT || a == AINIT)
+ sprint(str, "(%ld) %A %D/%d,%D",
+ p->line, a, &p->from, p->reg, &p->to);
+ else{
+ s = str;
+ s += sprint(s, "(%ld)", p->line);
+ if(p->mark & NOSCHED)
+ s += sprint(s, "*");
+ if(p->reg == NREG)
+ sprint(s, " %A %D,%D",
+ a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(s, " %A %D,R%d,%D",
+ a, &p->from, p->reg, &p->to);
+ else
+ sprint(s, " %A %D,F%d,%D",
+ a, &p->from, p->reg, &p->to);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ long v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OCONST:
+ sprint(str, "$*$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_MREG:
+ sprint(str, "M%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCREG:
+ sprint(str, "FC%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_LO:
+ sprint(str, "LO");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(LO)(REG)", a);
+ break;
+
+ case D_HI:
+ sprint(str, "HI");
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(HI)(REG)", a);
+ break;
+
+ case D_BRANCH: /* botch */
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(v >= INITTEXT)
+ v -= INITTEXT-HEADR;
+ if(a->sym != S)
+ sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5lux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%ld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%ld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%e", ieeedtod(a->ieee));
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%ld", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(s == S)
+ sprint(str, "%ld(SB)", a->offset);
+ else
+ sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ if(s == S)
+ sprint(str, "<>+%ld(SB)", a->offset);
+ else
+ sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ if(s == S)
+ sprint(str, "%ld(SP)", a->offset);
+ else
+ sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ if(s == S)
+ sprint(str, "%ld(FP)", a->offset);
+ else
+ sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ break;
+ }
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(long); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/utils/vl/mkfile b/utils/vl/mkfile
new file mode 100644
index 00000000..b84163a6
--- /dev/null
+++ b/utils/vl/mkfile
@@ -0,0 +1,31 @@
+<../../mkconfig
+
+TARG=vl
+
+OFILES=\
+ asm.$O\
+ list.$O\
+ noop.$O\
+ sched.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ enam.$O\
+ $TARGMODEL.$O\
+
+HFILES=\
+ l.h\
+ ../vc/v.out.h\
+ ../include/ar.h\
+
+LIBS=bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+enam.$O: ../vc/enam.c
+ $CC $CFLAGS ../vc/enam.c
diff --git a/utils/vl/noop.c b/utils/vl/noop.c
new file mode 100644
index 00000000..337e947d
--- /dev/null
+++ b/utils/vl/noop.c
@@ -0,0 +1,416 @@
+#include "l.h"
+
+void
+noops(void)
+{
+ Prog *p, *p1, *q, *q1;
+ int o, curframe, curbecome, maxbecome;
+
+ /*
+ * find leaf subroutines
+ * become sizes
+ * frame sizes
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+
+ q = P;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == D_OREG && p->to.reg == REGSP)
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ curtext = p;
+ break;
+
+ /* too hard, just leave alone */
+ case AMOVW:
+ if(p->to.type == D_FCREG ||
+ p->to.type == D_MREG) {
+ p->mark |= LABEL|SYNC;
+ break;
+ }
+ if(p->from.type == D_FCREG ||
+ p->from.type == D_MREG) {
+ p->mark |= LABEL|SYNC;
+ addnop(p);
+ addnop(p);
+ nop.mfrom.count += 2;
+ nop.mfrom.outof += 2;
+ break;
+ }
+ break;
+
+ /* too hard, just leave alone */
+ case ACASE:
+ case ASYSCALL:
+ case AWORD:
+ case ATLBWR:
+ case ATLBWI:
+ case ATLBP:
+ case ATLBR:
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ANOR:
+ if(p->to.type == D_REG && p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ARET:
+ /* special form of RET is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+
+ if(p->link != P)
+ p->link->mark |= LABEL;
+ break;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ case ABCASE:
+ p->mark |= LABEL|SYNC;
+ goto dstlab;
+
+ case ABGEZAL:
+ case ABLTZAL:
+ case AJAL:
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+
+ case AJMP:
+ case ABEQ:
+ case ABGEZ:
+ case ABGTZ:
+ case ABLEZ:
+ case ABLTZ:
+ case ABNE:
+ case ABFPT:
+ case ABFPF:
+ p->mark |= BRANCH;
+
+ dstlab:
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != P)
+ q1->mark |= LABEL;
+ break;
+ }
+ q = p;
+ }
+
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+ case AJAL:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ o = maxbecome - curtext->from.sym->frame;
+ if(o <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += o;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, o);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(autosize <= 4)
+ if(curtext->mark & LEAF) {
+ p->to.offset = -4;
+ autosize = 0;
+ }
+
+ q = p;
+ if(autosize) {
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = -autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ } else
+ if(!(curtext->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ curtext->from.sym->name);
+ Bflush(&bso);
+ curtext->mark |= LEAF;
+ }
+
+ if(curtext->mark & LEAF) {
+ if(curtext->from.sym)
+ curtext->from.sym->type = SLEAF;
+ break;
+ }
+
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGLINK;
+ q1->to.type = D_OREG;
+ q1->from.offset = 0;
+ q1->to.reg = REGSP;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case ARET:
+ nocache(p);
+ if(p->from.type == D_CONST)
+ goto become;
+ if(curtext->mark & LEAF) {
+ if(!autosize) {
+ p->as = AJMP;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ p->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_OREG;
+ q->to.offset = 0;
+ q->to.reg = REGLINK;
+ q->mark |= BRANCH;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ q = p;
+ if(autosize) {
+ q = prg();
+ q->as = AADD;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = prg();
+ q1->as = AJMP;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 0;
+ q1->to.reg = 2;
+ q1->mark |= BRANCH;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ become:
+ if(curtext->mark & LEAF) {
+
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ p->as = AADD;
+ p->from = zprg.from;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ break;
+ }
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ q = prg();
+ q->line = p->line;
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+
+ p->as = AMOVW;
+ p->from = zprg.from;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGLINK;
+
+ break;
+ }
+ }
+
+ curtext = P;
+ q = P; /* p - 1 */
+ q1 = firstp; /* top of block */
+ o = 0; /* count of instructions */
+ for(p = firstp; p != P; p = p1) {
+ p1 = p->link;
+ o++;
+ if(p->mark & NOSCHED){
+ if(q1 != p){
+ sched(q1, q);
+ }
+ for(; p != P; p = p->link){
+ if(!(p->mark & NOSCHED))
+ break;
+ q = p;
+ }
+ p1 = p;
+ q1 = p;
+ o = 0;
+ continue;
+ }
+ if(p->mark & (LABEL|SYNC)) {
+ if(q1 != p)
+ sched(q1, q);
+ q1 = p;
+ o = 1;
+ }
+ if(p->mark & (BRANCH|SYNC)) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ if(o >= NSCHED) {
+ sched(q1, p);
+ q1 = p1;
+ o = 0;
+ }
+ q = p;
+ }
+}
+
+void
+addnop(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = ANOR;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGZERO;
+ q->to.type = D_REG;
+ q->to.reg = REGZERO;
+
+ q->link = p->link;
+ p->link = q;
+}
+
+void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
diff --git a/utils/vl/obj.c b/utils/vl/obj.c
new file mode 100644
index 00000000..26c80683
--- /dev/null
+++ b/utils/vl/obj.c
@@ -0,0 +1,1332 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = 'v';
+char *thestring = "mips";
+
+/*
+ * -H0 -T0x40004C -D0x10000000 is abbrev unix
+ * -H1 -T0x80020000 -R4 is bootp() format for 3k
+ * -H2 -T4128 -R4096 is plan9 format
+ * -H3 -T0x80020000 -R8 is bootp() format for 4k
+ * -H4 -T0x400000 -R4 is sgi unix coff executable
+ * -H5 -T0x4000A0 -R4 is sgi unix elf executable
+ */
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ outfile = 0;
+ nerrors = 0;
+ curtext = P;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ /* do something about setting INITTEXT */
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0) {
+ diag("usage: vl [-options] objects");
+ errorexit();
+ }
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 0;
+ if(debug['B'])
+ HEADTYPE = 1;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+
+ case 0: /* unix simple */
+ HEADR = 20L+56L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x40004CL;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000L;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 1: /* boot for 3k */
+ HEADR = 20L+60L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x80020000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 2: /* plan 9 */
+ HEADR = 32L;
+ if(INITTEXT == -1)
+ INITTEXT = 4128;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
+ case 3: /* boot for 4k */
+ HEADR = 20L+56L+3*40L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x80020000L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 8;
+ break;
+ case 4: /* sgi unix coff executable */
+ HEADR = 20L+56L+3*40L;
+ if(INITTEXT == -1)
+ INITTEXT = 0x00400000L+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ case 5: /* sgi unix elf executable */
+ HEADR = rnd(52L+3*32L, 16);
+ if(INITTEXT == -1)
+ INITTEXT = 0x00400000L+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0x10000000;
+ if(INITRND == -1)
+ INITRND = 0;
+ break;
+ }
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.to = zprg.from;
+ buildop();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ dtype = 4;
+ if(outfile == 0)
+ outfile = "v.out";
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("%s: cannot create", outfile);
+ errorexit();
+ }
+ nuxiinit();
+
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ goto out;
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ dodata();
+ follow();
+ if(firstp == P)
+ goto out;
+ noops();
+ span();
+ asmb();
+ undef();
+
+out:
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%ld memory used\n", thunk);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+ errorexit();
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ long off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int i, c;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ c = p[2];
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ p[0] = ALAST+1;
+ return 0;
+ }
+ a->type = p[0];
+ a->reg = p[1];
+ a->sym = h[c];
+ a->name = p[3];
+ c = 4;
+
+ if(a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_MREG:
+ case D_FCREG:
+ case D_LO:
+ case D_HI:
+ break;
+
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ a->offset = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ c += 4;
+ break;
+
+ case D_SCONST:
+ while(nhunk < NSNAME)
+ gethunk();
+ a->sval = (char*)hunk;
+ nhunk -= NSNAME;
+ hunk += NSNAME;
+
+ memmove(a->sval, p+4, NSNAME);
+ c += NSNAME;
+ break;
+
+ case D_FCONST:
+ while(nhunk < sizeof(Ieee))
+ gethunk();
+ a->ieee = (Ieee*)hunk;
+ nhunk -= NSNAME;
+ hunk += NSNAME;
+
+ a->ieee->l = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ a->ieee->h = p[8] | (p[9]<<8) |
+ (p[10]<<16) | (p[11]<<24);
+ c += 8;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ return c;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+
+ while(nhunk < sizeof(Auto))
+ gethunk();
+ u = (Auto*)hunk;
+ nhunk -= sizeof(Auto);
+ hunk += sizeof(Auto);
+
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char name[1024], comp[256], *p;
+ int i;
+
+ if(histfrogp <= 0)
+ return;
+
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ if(debug['9'])
+ sprint(name, "/%s/lib", thestring);
+ else
+ sprint(name, "/usr/%clib", thechar);
+ i = 0;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+ diag("library component too long");
+ return;
+ }
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ long ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ Sym *h[NSYM], *s, *di;
+ int v, o, r, skip;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0]; /* as */
+ if(o <= AXXX || o >= ALAST) {
+ diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o);
+ print(" probably not a .v file\n");
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[1]; /* type */
+ o = bloc[2]; /* sym */
+ bloc += 3;
+ c -= 3;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ if(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ p->as = o;
+ p->reg = bloc[1] & 0x7f;
+ if(bloc[1] & 0x80)
+ p->mark = NOSCHED;
+ p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(p->reg < 0 || p->reg > NREG)
+ diag("register out of range %d", p->reg);
+
+ p->link = P;
+ p->cond = P;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ break;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->reg = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_CONST;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case ADATA:
+ if(p->from.sym == S) {
+ diag("DATA without a sym\n%P", p);
+ break;
+ }
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ curtext = p;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
+ s = p->from.sym;
+ if(s == S) {
+ diag("TEXT must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->reg & DUPOK) {
+ skip = 1;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P", s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->cond = p;
+ etextp = p;
+ break;
+
+ case ASUB:
+ case ASUBU:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE) {
+ p->from.offset = -p->from.offset;
+ if(p->as == ASUB)
+ p->as = AADD;
+ else
+ p->as = AADDU;
+ }
+ goto casedef;
+
+ case AMOVF:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 4;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVD:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee->l, p->from.ieee->h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ while(nhunk < sizeof(Sym))
+ gethunk();
+ s = (Sym*)hunk;
+ nhunk -= sizeof(Sym);
+ hunk += sizeof(Sym);
+
+ s->name = malloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p;
+
+ while(nhunk < sizeof(Prog))
+ gethunk();
+ p = (Prog*)hunk;
+ nhunk -= sizeof(Prog);
+ hunk += sizeof(Prog);
+
+ *p = zprg;
+ return p;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 5L*NHUNK) {
+ nh = 5L*NHUNK;
+ if(thunk >= 25L*NHUNK)
+ nh = 25L*NHUNK;
+ }
+ h = mysbrk(nh);
+ if(h == (char*)-1) {
+ diag("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDU;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->reg = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->reg = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->reg & NOPROF) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * JAL profin, R2
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AJAL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = AJAL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x01020304L, i+1);
+ if(i >= 2)
+ inuxi2[i-2] = c;
+ if(i >= 3)
+ inuxi1[i-3] = c;
+ inuxi4[i] = c;
+
+ fnuxi8[i] = c+4;
+ fnuxi8[i+4] = c;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+long
+ieeedtof(Ieee *ieeep)
+{
+ int exp;
+ long v;
+
+ if(ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (ieeep->h & 0xfffffL) << 3;
+ v |= (ieeep->l >> 29) & 0x7L;
+ if((ieeep->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= ieeep->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
diff --git a/utils/vl/optab.c b/utils/vl/optab.c
new file mode 100644
index 00000000..858ecacc
--- /dev/null
+++ b/utils/vl/optab.c
@@ -0,0 +1,232 @@
+#include "l.h"
+
+/* note: not finished
+ * movd fr,mem
+ * movd mem,fr
+ * addv
+ * addvu
+ * subv
+ * subvu
+ * mulv
+ * mulvu
+ * divv
+ * divvu
+ * remv
+ * remvu
+ */
+
+#define X 99
+
+Optab optab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0 },
+
+ { ASUB, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AAND, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { ASUB, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AAND, C_REG, C_NONE, C_REG, 2, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0 },
+ { ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0 },
+ { AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+ { AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVV, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVB, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVWL, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVV, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWL, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVV, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVB, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVV, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVV, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+
+ { AMOVW, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVV, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVB, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVBU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVV, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVBU, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVV, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVBU, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+
+ { AMOVW, C_SECON,C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVW, C_SACON,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_REG, 26, 12, REGSB },
+ { AMOVW, C_LACON,C_NONE, C_REG, 26, 12, REGSP },
+ { AMOVW, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVW, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO },
+
+ { AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0 },
+
+ { AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0 },
+
+ { AMUL, C_REG, C_REG, C_NONE, 22, 4, 0 },
+
+ { AADD, C_ADD0CON,C_REG,C_REG, 4, 4, 0 },
+ { AADD, C_ADD0CON,C_NONE,C_REG, 4, 4, 0 },
+ { AADD, C_ANDCON,C_REG, C_REG, 10, 8, 0 },
+ { AADD, C_ANDCON,C_NONE,C_REG, 10, 8, 0 },
+
+ { AAND, C_AND0CON,C_REG,C_REG, 4, 4, 0 },
+ { AAND, C_AND0CON,C_NONE,C_REG, 4, 4, 0 },
+ { AAND, C_ADDCON,C_REG, C_REG, 10, 8, 0 },
+ { AAND, C_ADDCON,C_NONE,C_REG, 10, 8, 0 },
+
+ { AADD, C_UCON, C_REG, C_REG, 25, 8, 0 },
+ { AADD, C_UCON, C_NONE, C_REG, 25, 8, 0 },
+ { AAND, C_UCON, C_REG, C_REG, 25, 8, 0 },
+ { AAND, C_UCON, C_NONE, C_REG, 25, 8, 0 },
+
+ { AADD, C_LCON, C_NONE, C_REG, 23, 12, 0 },
+ { AAND, C_LCON, C_NONE, C_REG, 23, 12, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 23, 12, 0 },
+ { AAND, C_LCON, C_REG, C_REG, 23, 12, 0 },
+
+ { ASLL, C_SCON, C_REG, C_REG, 16, 4, 0 },
+ { ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0 },
+
+ { ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0 },
+ { ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0 },
+ { ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0 },
+ { ABFPT, C_NONE, C_NONE, C_SBRA, 6, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+ { AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO },
+ { AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK },
+
+ { AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVD, C_SEXT, C_NONE, C_FREG, 27, 8, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVF, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVD, C_SAUTO,C_NONE, C_FREG, 27, 8, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+ { AMOVF, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+ { AMOVD, C_SOREG,C_NONE, C_FREG, 27, 8, REGZERO },
+
+ { AMOVW, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVF, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVD, C_LEXT, C_NONE, C_FREG, 27, 20, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVD, C_LAUTO,C_NONE, C_FREG, 27, 20, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+ { AMOVD, C_LOREG,C_NONE, C_FREG, 27, 20, REGZERO },
+
+ { AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_SEXT, 28, 8, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 8, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+ { AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+ { AMOVD, C_FREG, C_NONE, C_SOREG, 28, 8, REGZERO },
+
+ { AMOVW, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_LEXT, 28, 20, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 20, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+ { AMOVD, C_FREG, C_NONE, C_LOREG, 28, 20, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0 },
+
+ { AMOVW, C_ADDCON,C_NONE,C_FREG, 34, 8, 0 },
+ { AMOVW, C_ANDCON,C_NONE,C_FREG, 34, 8, 0 },
+ { AMOVW, C_UCON, C_NONE, C_FREG, 35, 8, 0 },
+ { AMOVW, C_LCON, C_NONE, C_FREG, 36, 12, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0 },
+ { AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0 },
+ { AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0 },
+
+ { ARFE, C_NONE, C_NONE, C_ZOREG, 39, 8, 0 },
+ { AWORD, C_NONE, C_NONE, C_LCON, 40, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0 },
+ { AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0 },
+ { AMOVW, C_FCREG,C_NONE, C_REG, 42, 4, 0 },
+ { AMOVV, C_FCREG,C_NONE, C_REG, 42, 4, 0 },
+
+ { ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, /* really CACHE instruction */
+ { ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { ACASE, C_REG, C_NONE, C_NONE, 45, 28, 0 },
+ { ABCASE, C_LCON, C_NONE, C_LBRA, 46, 4, 0 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
diff --git a/utils/vl/pass.c b/utils/vl/pass.c
new file mode 100644
index 00000000..7dc2e5dd
--- /dev/null
+++ b/utils/vl/pass.c
@@ -0,0 +1,505 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i, t;
+ Sym *s;
+ Prog *p, *p1;
+ long orig, orig1, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ v = p->from.offset + p->reg;
+ if(v > s->value)
+ diag("initialize bounds (%ld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ if(debug['t']) {
+ /*
+ * pull out string constants
+ */
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->to.type == D_SCONST)
+ s->type = SSTRING;
+ }
+ }
+
+ /*
+ * pass 1
+ * assign 'small' variables to data segment
+ * (rational is that data segment is more easily
+ * addressed through offset on R30)
+ */
+ orig = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA && t != SBSS)
+ continue;
+ v = s->value;
+ if(v == 0) {
+ diag("%s: no size", s->name);
+ v = 1;
+ }
+ while(v & 3)
+ v++;
+ s->value = v;
+ if(v > MINSIZ)
+ continue;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+ orig1 = orig;
+
+ /*
+ * pass 2
+ * assign 'data' variables to data segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA) {
+ if(t == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ v = s->value;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+
+ while(orig & 7)
+ orig++;
+ datsize = orig;
+
+ /*
+ * pass 3
+ * everything else to bss segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ v = s->value;
+ s->value = orig;
+ orig += v;
+ }
+ while(orig & 7)
+ orig++;
+ bsssize = orig-datsize;
+
+ /*
+ * pass 4
+ * add literals to all large values.
+ * at this time:
+ * small data is allocated DATA
+ * large data is allocated DATA1
+ * large bss is allocated BSS
+ * the new literals are loaded between
+ * small data and large data.
+ */
+ orig = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as != AMOVW)
+ continue;
+ if(p->from.type != D_CONST)
+ continue;
+ if(s = p->from.sym) {
+ t = s->type;
+ if(t != SDATA && t != SDATA1 && t != SBSS)
+ continue;
+ t = p->from.name;
+ if(t != D_EXTERN && t != D_STATIC)
+ continue;
+ v = s->value + p->from.offset;
+ if(v >= 0 && v <= 0xffff)
+ continue;
+ if(!strcmp(s->name, "setR30"))
+ continue;
+ /* size should be 19 max */
+ if(strlen(s->name) >= 10) /* has loader address */
+ sprint(literal, "$%lux.%lux", (long)s, p->from.offset);
+ else
+ sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset);
+ } else {
+ if(p->from.name != D_NONE)
+ continue;
+ if(p->from.reg != NREG)
+ continue;
+ v = p->from.offset;
+ if(v >= -0x7fff && v <= 0xffff)
+ continue;
+ if(!(v & 0xffff))
+ continue;
+ /* size should be 9 max */
+ sprint(literal, "$%lux", v);
+ }
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ s->value = orig1+orig;
+ orig += 4;
+ p1 = prg();
+ p1->line = p->line;
+ p1->as = ADATA;
+ p1->from.type = D_OREG;
+ p1->from.sym = s;
+ p1->from.name = D_EXTERN;
+ p1->reg = 4;
+ p1->to = p->from;
+ p1->link = datap;
+ datap = p1;
+ }
+ if(s->type != SDATA)
+ diag("literal not data: %s", s->name);
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ nocache(p);
+ continue;
+ }
+ while(orig & 7)
+ orig++;
+ /*
+ * pass 5
+ * re-adjust offsets
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t == SBSS) {
+ s->value += orig;
+ continue;
+ }
+ if(t == SDATA1) {
+ s->type = SDATA;
+ s->value += orig;
+ continue;
+ }
+ }
+ datsize += orig;
+ xdefine("setR30", SDATA, 0L+BIG);
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+ xdefine("etext", STEXT, 0L);
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+void
+follow(void)
+{
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+
+ firstp = firstp->link;
+ lastp->link = P;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == P)
+ return;
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(a == AJMP) {
+ q = p->cond;
+ if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ p = p->link;
+ xfol(p);
+ p = q;
+ if(p && !(p->mark & FOLL))
+ goto loop;
+ return;
+ }
+ if(q != P) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == lastp || (q->mark&NOSCHED))
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AJMP || a == ARET || a == ARFE)
+ goto copy;
+ if(!q->cond || (q->cond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ lastp->link = r;
+ lastp = r;
+ continue;
+ }
+ lastp->link = r;
+ lastp = r;
+ if(a == AJMP || a == ARET || a == ARFE)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+ a = AJMP;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ if(a == AJMP || a == ARET || a == ARFE){
+ if(p->mark & NOSCHED){
+ p = p->link;
+ goto loop;
+ }
+ return;
+ }
+ if(p->cond != P)
+ if(a != AJAL && p->link != P) {
+ xfol(p->link);
+ p = p->cond;
+ if(p == P || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ long c, vexit;
+ Prog *p, *q;
+ Sym *s;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if((a == AJAL || a == AJMP || a == ARET) &&
+ p->to.type != D_BRANCH && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s\n%P", s->name, p);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range %ld\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->cond != P) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ long dwn[LOG], cnt[LOG], i;
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != AJMP || (p->mark&NOSCHED))
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+long
+atolwhex(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+long
+rnd(long v, long r)
+{
+ long c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/utils/vl/sched.c b/utils/vl/sched.c
new file mode 100644
index 00000000..efa88a75
--- /dev/null
+++ b/utils/vl/sched.c
@@ -0,0 +1,695 @@
+#include "l.h"
+
+enum
+{
+ E_HILO = 1<<0,
+ E_FCR = 1<<1,
+ E_MCR = 1<<2,
+ E_MEM = 1<<3,
+ E_MEMSP = 1<<4, /* uses offset and size */
+ E_MEMSB = 1<<5, /* uses offset and size */
+ ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
+ DELAY = BRANCH|LOAD|FCMP,
+};
+
+typedef struct Sch Sch;
+typedef struct Dep Dep;
+
+struct Dep
+{
+ ulong ireg;
+ ulong freg;
+ ulong cc;
+};
+struct Sch
+{
+ Prog p;
+ Dep set;
+ Dep used;
+ long soffset;
+ char size;
+ char nop;
+ char comp;
+};
+
+void regsused(Sch*, Prog*);
+int depend(Sch*, Sch*);
+int conflict(Sch*, Sch*);
+int offoverlap(Sch*, Sch*);
+void dumpbits(Sch*, Dep*);
+
+void
+sched(Prog *p0, Prog *pe)
+{
+ Prog *p, *q;
+ Sch sch[NSCHED], *s, *t, *u, *se, stmp;
+
+ /*
+ * build side structure
+ */
+ s = sch;
+ for(p=p0;; p=p->link) {
+ memset(s, 0, sizeof(*s));
+ s->p = *p;
+ regsused(s, p);
+ if(debug['X']) {
+ Bprint(&bso, "%P\t\tset", &s->p);
+ dumpbits(s, &s->set);
+ Bprint(&bso, "; used");
+ dumpbits(s, &s->used);
+ if(s->comp)
+ Bprint(&bso, "; compound");
+ if(s->p.mark & LOAD)
+ Bprint(&bso, "; load");
+ if(s->p.mark & BRANCH)
+ Bprint(&bso, "; branch");
+ if(s->p.mark & FCMP)
+ Bprint(&bso, "; fcmp");
+ Bprint(&bso, "\n");
+ }
+ if(p == pe)
+ break;
+ s++;
+ }
+ se = s;
+
+ /*
+ * prepass to move things around
+ * does nothing, but tries to make
+ * the actual scheduler work better
+ */
+ for(s=sch; s<=se; s++) {
+ if(!(s->p.mark & LOAD))
+ continue;
+ /* always good to put nonconflict loads together */
+ for(t=s+1; t<=se; t++) {
+ if(!(t->p.mark & LOAD))
+ continue;
+ if(t->p.mark & BRANCH)
+ break;
+ if(conflict(s, t))
+ break;
+ for(u=t-1; u>s; u--)
+ if(depend(u, t))
+ goto no11;
+ u = s+1;
+ stmp = *t;
+ memmove(s+2, u, (uchar*)t - (uchar*)u);
+ *u = stmp;
+ break;
+ }
+ no11:
+
+ /* put schedule fodder above load */
+ for(t=s+1; t<=se; t++) {
+ if(t->p.mark & BRANCH)
+ break;
+ if(s > sch && conflict(s-1, t))
+ continue;
+ for(u=t-1; u>=s; u--)
+ if(depend(t, u))
+ goto no1;
+ stmp = *t;
+ memmove(s+1, s, (uchar*)t - (uchar*)s);
+ *s = stmp;
+ if(!(s->p.mark & LOAD))
+ break;
+ no1:;
+ }
+ }
+
+ for(s=se; s>=sch; s--) {
+ if(!(s->p.mark & DELAY))
+ continue;
+ if(s < se)
+ if(!conflict(s, s+1))
+ goto out3;
+ /*
+ * s is load, s+1 is immediate use of result or end of block
+ * t is the trial instruction to insert between s and s+1
+ */
+ if(!debug['Y'])
+ for(t=s-1; t>=sch; t--) {
+ if(t->comp)
+ if(s->p.mark & BRANCH)
+ goto no2;
+ if(t->p.mark & DELAY)
+ if(s >= se || conflict(t, s+1))
+ goto no2;
+ for(u=t+1; u<=s; u++)
+ if(depend(u, t))
+ goto no2;
+ goto out2;
+ no2:;
+ }
+ if(debug['X'])
+ Bprint(&bso, "?l%P\n", &s->p);
+ s->nop = 1;
+ if(debug['v']) {
+ if(s->p.mark & LOAD) {
+ nop.load.count++;
+ nop.load.outof++;
+ }
+ if(s->p.mark & BRANCH) {
+ nop.branch.count++;
+ nop.branch.outof++;
+ }
+ if(s->p.mark & FCMP) {
+ nop.fcmp.count++;
+ nop.fcmp.outof++;
+ }
+ }
+ continue;
+
+ out2:
+ if(debug['X']) {
+ Bprint(&bso, "!l%P\n", &t->p);
+ Bprint(&bso, "%P\n", &s->p);
+ }
+ stmp = *t;
+ memmove(t, t+1, (uchar*)s - (uchar*)t);
+ *s = stmp;
+ s--;
+
+ out3:
+ if(debug['v']) {
+ if(s->p.mark & LOAD)
+ nop.load.outof++;
+ if(s->p.mark & BRANCH)
+ nop.branch.outof++;
+ if(s->p.mark & FCMP)
+ nop.fcmp.outof++;
+ }
+ }
+
+ /* Avoid HI/LO use->set */
+ t = sch+1;
+ for(s=sch; s<se-1; s++, t++) {
+ if((s->used.cc & E_HILO) == 0)
+ continue;
+ if(t->set.cc & E_HILO)
+ s->nop = 2;
+ }
+
+ /*
+ * put it all back
+ */
+ for(s=sch, p=p0; s<=se; s++, p=q) {
+ q = p->link;
+ if(q != s->p.link) {
+ *p = s->p;
+ p->link = q;
+ }
+ while(s->nop--)
+ addnop(p);
+ }
+ if(debug['X']) {
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ }
+}
+
+void
+regsused(Sch *s, Prog *realp)
+{
+ int c, ar, ad, ld, sz;
+ ulong m;
+ Prog *p;
+
+ p = &s->p;
+ s->comp = compound(p);
+ s->nop = 0;
+ if(s->comp) {
+ s->set.ireg |= 1<<REGTMP;
+ s->used.ireg |= 1<<REGTMP;
+ }
+
+ ar = 0; /* dest is really reference */
+ ad = 0; /* source/dest is really address */
+ ld = 0; /* opcode is load instruction */
+ sz = 20; /* size of load/store for overlap computation */
+
+/*
+ * flags based on opcode
+ */
+ switch(p->as) {
+ case ATEXT:
+ curtext = realp;
+ autosize = p->to.offset + 4;
+ ad = 1;
+ break;
+ case AJAL:
+ c = p->reg;
+ if(c == NREG)
+ c = REGLINK;
+ s->set.ireg |= 1<<c;
+ ar = 1;
+ ad = 1;
+ break;
+ case ABGEZAL:
+ case ABLTZAL:
+ s->set.ireg |= 1<<REGLINK;
+ case ABEQ:
+ case ABGEZ:
+ case ABGTZ:
+ case ABLEZ:
+ case ABLTZ:
+ case ABNE:
+ ar = 1;
+ ad = 1;
+ break;
+ case ABFPT:
+ case ABFPF:
+ ad = 1;
+ s->used.cc |= E_FCR;
+ break;
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+ ar = 1;
+ s->set.cc |= E_FCR;
+ p->mark |= FCMP;
+ break;
+ case AJMP:
+ ar = 1;
+ ad = 1;
+ break;
+ case AMOVB:
+ case AMOVBU:
+ sz = 1;
+ ld = 1;
+ break;
+ case AMOVH:
+ case AMOVHU:
+ sz = 2;
+ ld = 1;
+ break;
+ case AMOVF:
+ case AMOVW:
+ case AMOVWL:
+ case AMOVWR:
+ sz = 4;
+ ld = 1;
+ break;
+ case AMOVD:
+ case AMOVV:
+ case AMOVVL:
+ case AMOVVR:
+ sz = 8;
+ ld = 1;
+ break;
+ case ADIV:
+ case ADIVU:
+ case AMUL:
+ case AMULU:
+ case AREM:
+ case AREMU:
+ s->set.cc = E_HILO;
+ case AADD:
+ case AADDU:
+ case AAND:
+ case ANOR:
+ case AOR:
+ case ASGT:
+ case ASGTU:
+ case ASLL:
+ case ASRA:
+ case ASRL:
+ case ASUB:
+ case ASUBU:
+ case AXOR:
+
+ case AADDD:
+ case AADDF:
+ case AADDW:
+ case ASUBD:
+ case ASUBF:
+ case ASUBW:
+ case AMULF:
+ case AMULD:
+ case AMULW:
+ case ADIVF:
+ case ADIVD:
+ case ADIVW:
+ if(p->reg == NREG) {
+ if(p->to.type == D_REG || p->to.type == D_FREG)
+ p->reg = p->to.reg;
+ if(p->reg == NREG)
+ print("botch %P\n", p);
+ }
+ break;
+ }
+
+/*
+ * flags based on 'to' field
+ */
+ c = p->to.class;
+ if(c == 0) {
+ c = aclass(&p->to) + 1;
+ p->to.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->to);
+
+ case C_ZCON:
+ case C_SCON:
+ case C_ADD0CON:
+ case C_AND0CON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_UCON:
+ case C_LCON:
+ case C_NONE:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+
+ case C_HI:
+ case C_LO:
+ s->set.cc |= E_HILO;
+ break;
+ case C_FCREG:
+ s->set.cc |= E_FCR;
+ break;
+ case C_MREG:
+ s->set.cc |= E_MCR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->to.reg;
+ s->used.ireg |= 1<<c;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ if(ar)
+ s->used.cc |= m;
+ else
+ s->set.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ if(ar)
+ s->used.ireg |= 1<<p->to.reg;
+ else
+ s->set.ireg |= 1<<p->to.reg;
+ break;
+ case C_FREG:
+ /* do better -- determine double prec */
+ if(ar) {
+ s->used.freg |= 1<<p->to.reg;
+ s->used.freg |= 1<<(p->to.reg|1);
+ } else {
+ s->set.freg |= 1<<p->to.reg;
+ s->set.freg |= 1<<(p->to.reg|1);
+ }
+ if(ld && p->from.type == D_REG)
+ p->mark |= LOAD;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSP;
+ else
+ s->set.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->to);
+
+ if(ar)
+ s->used.cc |= E_MEMSB;
+ else
+ s->set.cc |= E_MEMSB;
+ break;
+ }
+
+/*
+ * flags based on 'from' field
+ */
+ c = p->from.class;
+ if(c == 0) {
+ c = aclass(&p->from) + 1;
+ p->from.class = c;
+ }
+ c--;
+ switch(c) {
+ default:
+ print("unknown class %d %D\n", c, &p->from);
+
+ case C_ZCON:
+ case C_SCON:
+ case C_ADD0CON:
+ case C_AND0CON:
+ case C_ADDCON:
+ case C_ANDCON:
+ case C_UCON:
+ case C_LCON:
+ case C_NONE:
+ case C_SBRA:
+ case C_LBRA:
+ break;
+ case C_HI:
+ case C_LO:
+ s->used.cc |= E_HILO;
+ break;
+ case C_FCREG:
+ s->used.cc |= E_FCR;
+ break;
+ case C_MREG:
+ s->used.cc |= E_MCR;
+ break;
+ case C_ZOREG:
+ case C_SOREG:
+ case C_LOREG:
+ c = p->from.reg;
+ s->used.ireg |= 1<<c;
+ if(ld)
+ p->mark |= LOAD;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ m = ANYMEM;
+ if(c == REGSB)
+ m = E_MEMSB;
+ if(c == REGSP)
+ m = E_MEMSP;
+
+ s->used.cc |= m;
+ break;
+ case C_SACON:
+ case C_LACON:
+ s->used.ireg |= 1<<REGSP;
+ break;
+ case C_SECON:
+ case C_LECON:
+ s->used.ireg |= 1<<REGSB;
+ break;
+ case C_REG:
+ s->used.ireg |= 1<<p->from.reg;
+ break;
+ case C_FREG:
+ /* do better -- determine double prec */
+ s->used.freg |= 1<<p->from.reg;
+ s->used.freg |= 1<<(p->from.reg|1);
+ if(ld && p->to.type == D_REG)
+ p->mark |= LOAD;
+ break;
+ case C_SAUTO:
+ case C_LAUTO:
+ s->used.ireg |= 1<<REGSP;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSP;
+ break;
+ case C_SEXT:
+ case C_LEXT:
+ s->used.ireg |= 1<<REGSB;
+ if(ld)
+ p->mark |= LOAD;
+ if(ad)
+ break;
+ s->size = sz;
+ s->soffset = regoff(&p->from);
+
+ s->used.cc |= E_MEMSB;
+ break;
+ }
+
+ c = p->reg;
+ if(c != NREG) {
+ if(p->from.type == D_FREG || p->to.type == D_FREG) {
+ s->used.freg |= 1<<c;
+ s->used.freg |= 1<<(c|1);
+ } else
+ s->used.ireg |= 1<<c;
+ }
+ s->set.ireg &= ~(1<<REGZERO); /* R0 cant be set */
+}
+
+/*
+ * test to see if 2 instrictions can be
+ * interchanged without changing semantics
+ */
+int
+depend(Sch *sa, Sch *sb)
+{
+ ulong x;
+
+ if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
+ return 1;
+ if(sb->set.ireg & sa->used.ireg)
+ return 1;
+
+ if(sa->set.freg & (sb->set.freg|sb->used.freg))
+ return 1;
+ if(sb->set.freg & sa->used.freg)
+ return 1;
+
+ /*
+ * special case.
+ * loads from same address cannot pass.
+ * this is for hardware fifo's and the like
+ */
+ if(sa->used.cc & sb->used.cc & E_MEM)
+ if(sa->p.reg == sb->p.reg)
+ if(regoff(&sa->p.from) == regoff(&sb->p.from))
+ return 1;
+
+ x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
+ (sb->set.cc & sa->used.cc);
+ if(x) {
+ /*
+ * allow SB and SP to pass each other.
+ * allow SB to pass SB iff doffsets are ok
+ * anything else conflicts
+ */
+ if(x != E_MEMSP && x != E_MEMSB)
+ return 1;
+ x = sa->set.cc | sb->set.cc |
+ sa->used.cc | sb->used.cc;
+ if(x & E_MEM)
+ return 1;
+ if(offoverlap(sa, sb))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+offoverlap(Sch *sa, Sch *sb)
+{
+
+ if(sa->soffset < sb->soffset) {
+ if(sa->soffset+sa->size > sb->soffset)
+ return 1;
+ return 0;
+ }
+ if(sb->soffset+sb->size > sa->soffset)
+ return 1;
+ return 0;
+}
+
+/*
+ * test 2 adjacent instructions
+ * and find out if inserted instructions
+ * are desired to prevent stalls.
+ */
+int
+conflict(Sch *sa, Sch *sb)
+{
+
+ if(sa->set.ireg & sb->used.ireg)
+ return 1;
+ if(sa->set.freg & sb->used.freg)
+ return 1;
+ if(sa->set.cc & sb->used.cc)
+ return 1;
+
+ return 0;
+}
+
+int
+compound(Prog *p)
+{
+ Optab *o;
+
+ o = oplook(p);
+ if(o->size != 4)
+ return 1;
+ if(p->to.type == D_REG && p->to.reg == REGSB)
+ return 1;
+ return 0;
+}
+
+void
+dumpbits(Sch *s, Dep *d)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(d->ireg & (1<<i))
+ Bprint(&bso, " R%d", i);
+ for(i=0; i<32; i++)
+ if(d->freg & (1<<i))
+ Bprint(&bso, " F%d", i);
+ for(i=0; i<32; i++)
+ switch(d->cc & (1<<i)) {
+ default:
+ break;
+ case E_HILO:
+ Bprint(&bso, " HILO");
+ break;
+ case E_FCR:
+ Bprint(&bso, " FCR");
+ break;
+ case E_MCR:
+ Bprint(&bso, " MCR");
+ break;
+ case E_MEM:
+ Bprint(&bso, " MEM%d", s->size);
+ break;
+ case E_MEMSB:
+ Bprint(&bso, " SB%d", s->size);
+ break;
+ case E_MEMSP:
+ Bprint(&bso, " SP%d", s->size);
+ break;
+ }
+}
diff --git a/utils/vl/span.c b/utils/vl/span.c
new file mode 100644
index 00000000..706d8b0e
--- /dev/null
+++ b/utils/vl/span.c
@@ -0,0 +1,662 @@
+#include "l.h"
+
+void
+pagebug(Prog *p)
+{
+ Prog *q;
+
+ switch(p->as) {
+ case ABGEZAL:
+ case ABLTZAL:
+ case AJAL:
+ case ABEQ:
+ case ABGEZ:
+ case ABGTZ:
+ case ABLEZ:
+ case ABLTZ:
+ case ABNE:
+ case ABFPT:
+ case ABFPF:
+ case AJMP:
+ q = prg();
+ *q = *p;
+ p->link = q;
+ p->as = ANOR;
+ p->optab = 0;
+ p->from = zprg.from;
+ p->from.type = D_REG;
+ p->from.reg = REGZERO;
+ p->to = p->from;
+ }
+}
+
+void
+span(void)
+{
+ Prog *p, *q;
+ Sym *setext, *s;
+ Optab *o;
+ int m, bflag, i;
+ long c, otxt, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+
+ bflag = 0;
+ c = INITTEXT;
+ otxt = c;
+ for(p = firstp; p != P; p = p->link) {
+ /* bug in early 4000 chips delayslot on page boundary */
+ if((c&(0x1000-1)) == 0xffc)
+ pagebug(p);
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ while(bflag) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ /* bug in early 4000 chips delayslot on page boundary */
+ if((c&(0x1000-1)) == 0xffc)
+ pagebug(p);
+ p->pc = c;
+ o = oplook(p);
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AJMP;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AJMP;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ addnop(p->link);
+ addnop(p);
+ bflag = 1;
+ }
+ }
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ }
+
+ if(debug['t']) {
+ /*
+ * add strings to text segment
+ */
+ c = rnd(c, 8);
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SSTRING)
+ continue;
+ v = s->value;
+ while(v & 3)
+ v++;
+ s->value = c;
+ c += v;
+ }
+ }
+
+ c = rnd(c, 8);
+
+ setext = lookup("etext", 0);
+ if(setext != S) {
+ setext->value = c;
+ textsize = c - INITTEXT;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "tsize = %lux\n", textsize);
+ Bflush(&bso);
+}
+
+void
+xdefine(char *p, int t, long v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+}
+
+long
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FCREG:
+ return C_FCREG;
+
+ case D_MREG:
+ return C_MREG;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ instoffset = a->sym->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SEXT;
+ return C_LEXT;
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ if(instoffset == 0)
+ return C_ZOREG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_HI:
+ return C_LO;
+ case D_LO:
+ return C_HI;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ if(s->type == STEXT || s->type == SLEAF)
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+
+ case D_NONE:
+ instoffset = a->offset;
+ consize:
+ if(instoffset > 0) {
+ if(instoffset <= 0x7fff)
+ return C_SCON;
+ if(instoffset <= 0xffff)
+ return C_ANDCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+ }
+ if(instoffset == 0)
+ return C_ZCON;
+ if(instoffset >= -0x8000)
+ return C_ADDCON;
+ if((instoffset & 0xffff) == 0)
+ return C_UCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ switch(t) {
+ case 0:
+ case SXREF:
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ break;
+ case SCONST:
+ instoffset = s->value + a->offset;
+ goto consize;
+ case STEXT:
+ case SLEAF:
+ case SSTRING:
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ instoffset = s->value + a->offset - BIG;
+ if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
+ return C_SECON;
+ instoffset = s->value + a->offset + INITDAT;
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 4L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(&p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0) {
+ a1 = opcross[repop[r]][a1][a2][a3];
+ if(a1) {
+ p->optab = a1+1;
+ return optab+a1;
+ }
+ o = oprange[r].stop; /* just generate an error */
+ }
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ diag("illegal combination %A %d %d %d",
+ p->as, a1, a2, a3);
+ if(!debug['a'])
+ prasm(p);
+ o = optab;
+ p->optab = (o-optab)+1;
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON ||
+ b == C_ADDCON || b == C_ANDCON)
+ return 1;
+ break;
+ case C_ADD0CON:
+ if(b == C_ADDCON)
+ return 1;
+ case C_ADDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_AND0CON:
+ if(b == C_ANDCON)
+ return 1;
+ case C_ANDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ for(i=0; i<32; i++)
+ for(n=0; n<32; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A", r);
+ errorexit();
+ case AABSF:
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ oprange[AMOVWF] = oprange[r];
+ oprange[AMOVFW] = oprange[r];
+ oprange[AMOVWD] = oprange[r];
+ oprange[AMOVDW] = oprange[r];
+ oprange[ANEGF] = oprange[r];
+ oprange[ANEGD] = oprange[r];
+ oprange[AABSD] = oprange[r];
+ break;
+ case AADD:
+ buildrep(1, AADD);
+ oprange[ASGT] = oprange[r];
+ repop[ASGT] = 1;
+ oprange[ASGTU] = oprange[r];
+ repop[ASGTU] = 1;
+ oprange[AADDU] = oprange[r];
+ repop[AADDU] = 1;
+ oprange[AADDVU] = oprange[r];
+ repop[AADDVU] = 1;
+ break;
+ case AADDF:
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AADDD] = oprange[r];
+ break;
+ case AAND:
+ buildrep(2, AAND);
+ oprange[AXOR] = oprange[r];
+ repop[AXOR] = 2;
+ oprange[AOR] = oprange[r];
+ repop[AOR] = 2;
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ break;
+ case ABLEZ:
+ oprange[ABGEZ] = oprange[r];
+ oprange[ABGEZAL] = oprange[r];
+ oprange[ABLTZ] = oprange[r];
+ oprange[ABLTZAL] = oprange[r];
+ oprange[ABGTZ] = oprange[r];
+ break;
+ case AMOVB:
+ buildrep(3, AMOVB);
+ oprange[AMOVH] = oprange[r];
+ repop[AMOVH] = 3;
+ break;
+ case AMOVBU:
+ buildrep(4, AMOVBU);
+ oprange[AMOVHU] = oprange[r];
+ repop[AMOVHU] = 4;
+ break;
+ case AMUL:
+ oprange[AREM] = oprange[r];
+ oprange[AREMU] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ oprange[AMULU] = oprange[r];
+ oprange[ADIV] = oprange[r];
+ oprange[ADIVVU] = oprange[r];
+ oprange[ADIVV] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ oprange[ASLLV] = oprange[r];
+ oprange[ASRAV] = oprange[r];
+ oprange[ASRLV] = oprange[r];
+ break;
+ case ASUB:
+ oprange[ASUBU] = oprange[r];
+ oprange[ANOR] = oprange[r];
+ break;
+ case ASYSCALL:
+ oprange[ATLBP] = oprange[r];
+ oprange[ATLBR] = oprange[r];
+ oprange[ATLBWI] = oprange[r];
+ oprange[ATLBWR] = oprange[r];
+ break;
+ case ACMPEQF:
+ oprange[ACMPGTF] = oprange[r];
+ oprange[ACMPGTD] = oprange[r];
+ oprange[ACMPGEF] = oprange[r];
+ oprange[ACMPGED] = oprange[r];
+ oprange[ACMPEQD] = oprange[r];
+ break;
+ case ABFPT:
+ oprange[ABFPF] = oprange[r];
+ break;
+ case AMOVWL:
+ oprange[AMOVWR] = oprange[r];
+ oprange[AMOVVR] = oprange[r];
+ oprange[AMOVVL] = oprange[r];
+ break;
+ case AMOVW:
+ buildrep(5, AMOVW);
+ break;
+ case AMOVD:
+ buildrep(6, AMOVD);
+ break;
+ case AMOVF:
+ buildrep(7, AMOVF);
+ break;
+ case AMOVV:
+ buildrep(8, AMOVV);
+ break;
+ case ABREAK:
+ case AWORD:
+ case ARFE:
+ case AJAL:
+ case AJMP:
+ case ATEXT:
+ case ACASE:
+ case ABCASE:
+ break;
+ }
+ }
+}
+
+void
+buildrep(int x, int as)
+{
+ Opcross *p;
+ Optab *e, *s, *o;
+ int a1, a2, a3, n;
+
+ if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
+ diag("assumptions fail in buildrep");
+ errorexit();
+ }
+ repop[as] = x;
+ p = (opcross + x);
+ s = oprange[as].start;
+ e = oprange[as].stop;
+ for(o=e-1; o>=s; o--) {
+ n = o-optab;
+ for(a2=0; a2<2; a2++) {
+ if(a2) {
+ if(o->a2 == C_NONE)
+ continue;
+ } else
+ if(o->a2 != C_NONE)
+ continue;
+ for(a1=0; a1<32; a1++) {
+ if(!xcmp[a1][o->a1])
+ continue;
+ for(a3=0; a3<32; a3++)
+ if(xcmp[a3][o->a3])
+ (*p)[a1][a2][a3] = n;
+ }
+ }
+ }
+ oprange[as].start = 0;
+}
diff --git a/utils/yacc/mkfile b/utils/yacc/mkfile
new file mode 100644
index 00000000..05e2709e
--- /dev/null
+++ b/utils/yacc/mkfile
@@ -0,0 +1,20 @@
+<../../mkconfig
+
+TARG=yacc
+
+OFILES= yacc.$O\
+
+HFILES= ../../include/bio.h\
+
+LIBS=bio 9 # libbio.a uses lib9.a so order matters.
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include '-DROOT="'$ROOT'"' '-DPARSER="yaccpar"' '-DPARSERS="yaccpar"'
+
+install:V: $ROOT/utils/lib/yaccpar
+
+$ROOT/utils/lib/yaccpar: yaccpar
+ rm -f $target && cp $prereq $target
diff --git a/utils/yacc/yacc.c b/utils/yacc/yacc.c
new file mode 100644
index 00000000..0a6fdda0
--- /dev/null
+++ b/utils/yacc/yacc.c
@@ -0,0 +1,2933 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+
+#define Bungetrune Bungetc /* ok for now. */
+
+/*
+ * all these are 32 bit
+ */
+#define TBITSET ((32+NTERMS)/32) /* BOTCH?? +31 */
+#define BIT(a,i) ((a)[(i)>>5] & (1<<((i)&037)))
+#define SETBIT(a,i) ((a)[(i)>>5] |= (1<<((i)&037)))
+#define NWORDS(n) (((n)+32)/32)
+
+#ifndef PARSER
+#define PARSER "yaccpar"
+#define PARSERS "yaccpars"
+#endif
+#define TEMPNAME "y.tmp.XXXXXX"
+#define ACTNAME "y.acts.XXXXXX"
+#define OFILE "tab.c"
+#define FILEU "output"
+#define FILED "tab.h"
+#define FILEDEBUG "debug"
+
+enum
+{
+/*
+ * the following are adjustable
+ * according to memory size
+ */
+ ACTSIZE = 30000,
+ MEMSIZE = 30000,
+ NSTATES = 2000,
+ NTERMS = 255,
+ NPROD = 800,
+ NNONTERM = 300,
+ TEMPSIZE = 2000,
+ CNAMSZ = 5000,
+ LSETSIZE = 2400,
+ WSETSIZE = 350,
+
+ NAMESIZE = 50,
+ NTYPES = 63,
+ ISIZE = 400,
+
+ PRIVATE = 0xE000, /* unicode private use */
+
+ /* relationships which must hold:
+ TBITSET ints must hold NTERMS+1 bits...
+ WSETSIZE >= NNONTERM
+ LSETSIZE >= NNONTERM
+ TEMPSIZE >= NTERMS + NNONTERM + 1
+ TEMPSIZE >= NSTATES
+ */
+
+ NTBASE = 010000,
+ ERRCODE = 8190,
+ ACCEPTCODE = 8191,
+
+ NOASC = 0, /* no assoc. */
+ LASC = 1, /* left assoc. */
+ RASC = 2, /* right assoc. */
+ BASC = 3, /* binary assoc. */
+
+ /* flags for state generation */
+
+ DONE = 0,
+ MUSTDO = 1,
+ MUSTLOOKAHEAD = 2,
+
+ /* flags for a rule having an action, and being reduced */
+
+ ACTFLAG = 04,
+ REDFLAG = 010,
+
+ /* output parser flags */
+ YYFLAG1 = -1000,
+
+ /* parse tokens */
+ IDENTIFIER = PRIVATE,
+ MARK,
+ TERM,
+ LEFT,
+ RIGHT,
+ BINARY,
+ PREC,
+ LCURLY,
+ IDENTCOLON,
+ NUMBER,
+ START,
+ TYPEDEF,
+ TYPENAME,
+ UNION,
+
+ ENDFILE = 0,
+
+ EMPTY = 1,
+ WHOKNOWS = 0,
+ OK = 1,
+ NOMORE = -1000,
+};
+
+ /* macros for getting associativity and precedence levels */
+
+#define ASSOC(i) ((i)&03)
+#define PLEVEL(i) (((i)>>4)&077)
+#define TYPE(i) (((i)>>10)&077)
+
+ /* macros for setting associativity and precedence levels */
+
+#define SETASC(i,j) i |= j
+#define SETPLEV(i,j) i |= (j<<4)
+#define SETTYPE(i,j) i |= (j<<10)
+
+ /* looping macros */
+
+#define TLOOP(i) for(i=1; i<=ntokens; i++)
+#define NTLOOP(i) for(i=0; i<=nnonter; i++)
+#define PLOOP(s,i) for(i=s; i<nprod; i++)
+#define SLOOP(i) for(i=0; i<nstate; i++)
+#define WSBUMP(x) x++
+#define WSLOOP(s,j) for(j=s; j<cwp; j++)
+#define ITMLOOP(i,p,q) for(q=pstate[i+1], p=pstate[i]; p<q; p++)
+#define SETLOOP(i) for(i=0; i<tbitset; i++)
+
+ /* command to clobber tempfiles after use */
+
+#define ZAPFILE(x) if(x) remove(x)
+
+ /* I/O descriptors */
+
+Biobuf* faction; /* file for saving actions */
+Biobuf* fdefine; /* file for #defines */
+Biobuf* fdebug; /* y.debug for strings for debugging */
+Biobuf* ftable; /* y.tab.c file */
+Biobuf* ftemp; /* tempfile to pass 2 */
+Biobuf* finput; /* input file */
+Biobuf* foutput; /* y.output file */
+
+ /* communication variables between various I/O routines */
+
+char* infile; /* input file name */
+int numbval; /* value of an input number */
+char tokname[NAMESIZE+4]; /* input token name, slop for runes and 0 */
+
+ /* structure declarations */
+
+typedef
+struct
+{
+ int lset[TBITSET];
+} Lkset;
+
+typedef
+struct
+{
+ int* pitem;
+ Lkset* look;
+} Item;
+
+typedef
+struct
+{
+ char* name;
+ int value;
+} Symb;
+
+typedef
+struct
+{
+ int* pitem;
+ int flag;
+ Lkset ws;
+} Wset;
+
+ /* storage of names */
+
+char cnames[CNAMSZ]; /* place where token and nonterminal names are stored */
+int cnamsz = CNAMSZ; /* size of cnames */
+char* cnamp = cnames; /* place where next name is to be put in */
+int ndefout = 4; /* number of defined symbols output */
+char* tempname;
+char* actname;
+char ttempname[] = TEMPNAME;
+char tactname[] = ACTNAME;
+char* parser = PARSER;
+char* yydebug;
+char par[256]; /* full path of parser */
+
+ /* storage of types */
+int ntypes; /* number of types defined */
+char* typeset[NTYPES]; /* pointers to type tags */
+
+ /* token information */
+
+int ntokens = 0 ; /* number of tokens */
+Symb tokset[NTERMS];
+int toklev[NTERMS]; /* vector with the precedence of the terminals */
+
+ /* nonterminal information */
+
+int nnonter = -1; /* the number of nonterminals */
+Symb nontrst[NNONTERM];
+int start; /* start symbol */
+
+ /* assigned token type values */
+int extval = 0;
+
+char* ytabc = OFILE; /* name of y.tab.c */
+
+ /* grammar rule information */
+
+int mem0[MEMSIZE] ; /* production storage */
+int* mem = mem0;
+int nprod = 1; /* number of productions */
+int* prdptr[NPROD]; /* pointers to descriptions of productions */
+int levprd[NPROD]; /* precedence levels for the productions */
+int rlines[NPROD]; /* line number for this rule */
+
+ /* state information */
+
+int nstate = 0; /* number of states */
+Item* pstate[NSTATES+2]; /* pointers to the descriptions of the states */
+int tystate[NSTATES]; /* contains type information about the states */
+int defact[NSTATES]; /* the default actions of states */
+int tstates[NTERMS]; /* states generated by terminal gotos */
+int ntstates[NNONTERM]; /* states generated by nonterminal gotos */
+int mstates[NSTATES]; /* chain of overflows of term/nonterm generation lists */
+int lastred; /* the number of the last reduction of a state */
+
+ /* lookahead set information */
+
+Lkset lkst[LSETSIZE];
+int nolook; /* flag to turn off lookahead computations */
+int tbitset; /* size of lookahead sets */
+int nlset = 0; /* next lookahead set index */
+int nolook = 0; /* flag to suppress lookahead computations */
+Lkset clset; /* temporary storage for lookahead computations */
+
+ /* working set information */
+
+Wset wsets[WSETSIZE];
+Wset* cwp;
+
+ /* storage for action table */
+
+int amem[ACTSIZE]; /* action table storage */
+int* memp = amem; /* next free action table position */
+int indgo[NSTATES]; /* index to the stored goto table */
+
+ /* temporary vector, indexable by states, terms, or ntokens */
+
+int temp1[TEMPSIZE]; /* temporary storage, indexed by terms + ntokens or states */
+int lineno = 1; /* current input line number */
+int fatfl = 1; /* if on, error is fatal */
+int nerrors = 0; /* number of errors */
+
+ /* statistics collection variables */
+
+int zzgoent;
+int zzgobest;
+int zzacent;
+int zzexcp;
+int zzclose;
+int zzrrconf;
+int zzsrconf;
+
+int* ggreed = lkst[0].lset;
+int* pgo = wsets[0].ws.lset;
+int* yypgo = &nontrst[0].value;
+
+int maxspr = 0; /* maximum spread of any entry */
+int maxoff = 0; /* maximum offset into a array */
+int* pmem = mem0;
+int* maxa;
+int nxdb = 0;
+int adb = 0;
+
+
+ /* storage for information about the nonterminals */
+
+int** pres[NNONTERM+2]; /* vector of pointers to productions yielding each nonterminal */
+Lkset* pfirst[NNONTERM+2]; /* vector of pointers to first sets for each nonterminal */
+int pempty[NNONTERM+1]; /* vector of nonterminals nontrivially deriving e */
+
+ /* random stuff picked out from between functions */
+
+int indebug = 0;
+Wset* zzcwp = wsets;
+int zzgoent = 0;
+int zzgobest = 0;
+int zzacent = 0;
+int zzexcp = 0;
+int zzclose = 0;
+int zzsrconf = 0;
+int* zzmemsz = mem0;
+int zzrrconf = 0;
+int pidebug = 0; /* debugging flag for putitem */
+int gsdebug = 0;
+int cldebug = 0; /* debugging flag for closure */
+int pkdebug = 0;
+int g2debug = 0;
+
+struct
+{
+ char* name;
+ long value;
+} resrv[] =
+{
+ "binary", BINARY,
+ "left", LEFT,
+ "nonassoc", BINARY,
+ "prec", PREC,
+ "right", RIGHT,
+ "start", START,
+ "term", TERM,
+ "token", TERM,
+ "type", TYPEDEF,
+ "union", UNION,
+ 0,
+};
+
+ /* define functions */
+
+void main(int, char**);
+void others(void);
+char* chcopy(char*, char*);
+char* writem(int*);
+char* symnam(int);
+void summary(void);
+void error(char*, ...);
+void aryfil(int*, int, int);
+int setunion(int*, int*);
+void prlook(Lkset*);
+void cpres(void);
+void cpfir(void);
+int state(int);
+void putitem(int*, Lkset*);
+void cempty(void);
+void stagen(void);
+void closure(int);
+Lkset* flset(Lkset*);
+void cleantmp(void);
+void intr(void);
+void setup(int, char**);
+void finact(void);
+int defin(int, char*);
+void defout(int);
+char* cstash(char*);
+long gettok(void);
+int fdtype(int);
+int chfind(int, char*);
+void cpyunion(void);
+void cpycode(void);
+int skipcom(void);
+void cpyact(int);
+void openup(char*, int, int, int, char*);
+void output(void);
+int apack(int*, int);
+void go2out(void);
+void go2gen(int);
+void precftn(int, int, int);
+void wract(int);
+void wrstate(int);
+void warray(char*, int*, int);
+void hideprod(void);
+void callopt(void);
+void gin(int);
+void stin(int);
+int nxti(void);
+void osummary(void);
+void aoutput(void);
+void arout(char*, int*, int);
+int gtnm(void);
+
+void
+main(int argc, char *argv[])
+{
+
+ setup(argc, argv); /* initialize and read productions */
+ tbitset = NWORDS(ntokens);
+ cpres(); /* make table of which productions yield a given nonterminal */
+ cempty(); /* make a table of which nonterminals can match the empty string */
+ cpfir(); /* make a table of firsts of nonterminals */
+ stagen(); /* generate the states */
+ output(); /* write the states and the tables */
+ go2out();
+ hideprod();
+ summary();
+ callopt();
+ others();
+ exits(0);
+}
+
+/*
+ * put out other arrays, copy the parsers
+ */
+void
+others(void)
+{
+ int c, i, j;
+
+ finput = Bopen(parser, OREAD);
+ if(finput == 0)
+ error("cannot find parser %s", parser);
+ warray("yyr1", levprd, nprod);
+ aryfil(temp1, nprod, 0);
+ PLOOP(1, i)
+ temp1[i] = prdptr[i+1]-prdptr[i]-2;
+ warray("yyr2", temp1, nprod);
+
+ aryfil(temp1, nstate, -1000);
+ TLOOP(i)
+ for(j=tstates[i]; j!=0; j=mstates[j])
+ temp1[j] = i;
+ NTLOOP(i)
+ for(j=ntstates[i]; j!=0; j=mstates[j])
+ temp1[j] = -i;
+ warray("yychk", temp1, nstate);
+ warray("yydef", defact, nstate);
+
+ /* put out token translation tables */
+ /* table 1 has 0-256 */
+ aryfil(temp1, 256, 0);
+ c = 0;
+ TLOOP(i) {
+ j = tokset[i].value;
+ if(j >= 0 && j < 256) {
+ if(temp1[j]) {
+ print("yacc bug -- cant have 2 different Ts with same value\n");
+ print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name);
+ nerrors++;
+ }
+ temp1[j] = i;
+ if(j > c)
+ c = j;
+ }
+ }
+ warray("yytok1", temp1, c+1);
+
+ /* table 2 has PRIVATE-PRIVATE+256 */
+ aryfil(temp1, 256, 0);
+ c = 0;
+ TLOOP(i) {
+ j = tokset[i].value - PRIVATE;
+ if(j >= 0 && j < 256) {
+ if(temp1[j]) {
+ print("yacc bug -- cant have 2 different Ts with same value\n");
+ print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name);
+ nerrors++;
+ }
+ temp1[j] = i;
+ if(j > c)
+ c = j;
+ }
+ }
+ warray("yytok2", temp1, c+1);
+
+ /* table 3 has everything else */
+ Bprint(ftable, "long yytok3[] =\n{\n");
+ c = 0;
+ TLOOP(i) {
+ j = tokset[i].value;
+ if(j >= 0 && j < 256)
+ continue;
+ if(j >= PRIVATE && j < 256+PRIVATE)
+ continue;
+
+ Bprint(ftable, "%4d,%4d,", j, i);
+ c++;
+ if(c%5 == 0)
+ Bprint(ftable, "\n");
+ }
+ Bprint(ftable, "%4d\n};\n", 0);
+
+ /* copy parser text */
+ while((c=Bgetrune(finput)) != Beof) {
+ if(c == '$') {
+ if((c = Bgetrune(finput)) != 'A')
+ Bputrune(ftable, '$');
+ else { /* copy actions */
+ faction = Bopen(actname, OREAD);
+ if(faction == 0)
+ error("cannot reopen action tempfile");
+ while((c=Bgetrune(faction)) != Beof)
+ Bputrune(ftable, c);
+ Bterm(faction);
+ ZAPFILE(actname);
+ c = Bgetrune(finput);
+ }
+ }
+ Bputrune(ftable, c);
+ }
+ Bterm(ftable);
+}
+
+/*
+ * copies string q into p, returning next free char ptr
+ */
+char*
+chcopy(char* p, char* q)
+{
+ int c;
+
+ while(c = *q) {
+ if(c == '"')
+ *p++ = '\\';
+ *p++ = c;
+ q++;
+ }
+ *p = 0;
+ return p;
+}
+
+/*
+ * creates output string for item pointed to by pp
+ */
+char*
+writem(int *pp)
+{
+ int i,*p;
+ static char sarr[ISIZE];
+ char* q;
+
+ for(p=pp; *p>0; p++)
+ ;
+ p = prdptr[-*p];
+ q = chcopy(sarr, nontrst[*p-NTBASE].name);
+ q = chcopy(q, ": ");
+ for(;;) {
+ *q = ' ';
+ p++;
+ if(p == pp)
+ *q = '.';
+ q++;
+ *q = '\0';
+ i = *p;
+ if(i <= 0)
+ break;
+ q = chcopy(q, symnam(i));
+ if(q > &sarr[ISIZE-30])
+ error("item too big");
+ }
+
+ /* an item calling for a reduction */
+ i = *pp;
+ if(i < 0 ) {
+ q = chcopy(q, " (");
+ sprint(q, "%d)", -i);
+ }
+ return sarr;
+}
+
+/*
+ * return a pointer to the name of symbol i
+ */
+char*
+symnam(int i)
+{
+ char* cp;
+
+ cp = (i >= NTBASE)? nontrst[i-NTBASE].name: tokset[i].name;
+ if(*cp == ' ')
+ cp++;
+ return cp;
+}
+
+/*
+ * output the summary on y.output
+ */
+void
+summary(void)
+{
+
+ if(foutput != 0) {
+ Bprint(foutput, "\n%d/%d terminals, %d/%d nonterminals\n",
+ ntokens, NTERMS, nnonter, NNONTERM);
+ Bprint(foutput, "%d/%d grammar rules, %d/%d states\n",
+ nprod, NPROD, nstate, NSTATES);
+ Bprint(foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n",
+ zzsrconf, zzrrconf);
+ Bprint(foutput, "%d/%d working sets used\n",
+ (int)(zzcwp-wsets), WSETSIZE);
+ Bprint(foutput, "memory: states,etc. %d/%d, parser %d/%d\n",
+ (int)(zzmemsz-mem0), MEMSIZE, (int)(memp-amem), ACTSIZE);
+ Bprint(foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE);
+ Bprint(foutput, "%d extra closures\n", zzclose - 2*nstate);
+ Bprint(foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp);
+ Bprint(foutput, "%d goto entries\n", zzgoent);
+ Bprint(foutput, "%d entries saved by goto default\n", zzgobest);
+ }
+ if(zzsrconf != 0 || zzrrconf != 0) {
+ print("\nconflicts: ");
+ if(zzsrconf)
+ print("%d shift/reduce", zzsrconf);
+ if(zzsrconf && zzrrconf)
+ print(", ");
+ if(zzrrconf)
+ print("%d reduce/reduce", zzrrconf);
+ print("\n");
+ }
+ if(ftemp != 0) {
+ Bterm(ftemp);
+ ftemp = 0;
+ }
+ if(fdefine != 0) {
+ Bterm(fdefine);
+ fdefine = 0;
+ }
+}
+
+/*
+ * write out error comment -- NEEDS WORK
+ */
+void
+error(char *s, ...)
+{
+
+ nerrors++;
+ fprint(2, "\n fatal error:");
+ fprint(2, s, (&s)[1]);
+ fprint(2, ", %s:%d\n", infile, lineno);
+ if(!fatfl)
+ return;
+ summary();
+ cleantmp();
+ exits("error");
+}
+
+/*
+ * set elements 0 through n-1 to c
+ */
+void
+aryfil(int *v, int n, int c)
+{
+ int i;
+
+ for(i=0; i<n; i++)
+ v[i] = c;
+}
+
+/*
+ * set a to the union of a and b
+ * return 1 if b is not a subset of a, 0 otherwise
+ */
+int
+setunion(int *a, int *b)
+{
+ int i, x, sub;
+
+ sub = 0;
+ SETLOOP(i) {
+ x = *a;
+ *a |= *b;
+ if(*a != x)
+ sub = 1;
+ a++;
+ b++;
+ }
+ return sub;
+}
+
+void
+prlook(Lkset* p)
+{
+ int j, *pp;
+
+ pp = p->lset;
+ if(pp == 0)
+ Bprint(foutput, "\tNULL");
+ else {
+ Bprint(foutput, " { ");
+ TLOOP(j)
+ if(BIT(pp,j))
+ Bprint(foutput, "%s ", symnam(j));
+ Bprint(foutput, "}");
+ }
+}
+
+/*
+ * compute an array with the beginnings of productions yielding given nonterminals
+ * The array pres points to these lists
+ * the array pyield has the lists: the total size is only NPROD+1
+ */
+void
+cpres(void)
+{
+ int c, j, i, **pmem;
+ static int *pyield[NPROD];
+
+ pmem = pyield;
+ NTLOOP(i) {
+ c = i+NTBASE;
+ pres[i] = pmem;
+ fatfl = 0; /* make undefined symbols nonfatal */
+ PLOOP(0, j)
+ if(*prdptr[j] == c)
+ *pmem++ = prdptr[j]+1;
+ if(pres[i] == pmem)
+ error("nonterminal %s not defined!", nontrst[i].name);
+ }
+ pres[i] = pmem;
+ fatfl = 1;
+ if(nerrors) {
+ summary();
+ cleantmp();
+ exits("error");
+ }
+ if(pmem != &pyield[nprod])
+ error("internal Yacc error: pyield %d", pmem-&pyield[nprod]);
+}
+
+/*
+ * compute an array with the first of nonterminals
+ */
+void
+cpfir(void)
+{
+ int *p, **s, i, **t, ch, changes;
+
+ zzcwp = &wsets[nnonter];
+ NTLOOP(i) {
+ aryfil(wsets[i].ws.lset, tbitset, 0);
+ t = pres[i+1];
+ /* initially fill the sets */
+ for(s=pres[i]; s<t; ++s)
+ for(p = *s; (ch = *p) > 0; ++p) {
+ if(ch < NTBASE) {
+ SETBIT(wsets[i].ws.lset, ch);
+ break;
+ }
+ if(!pempty[ch-NTBASE])
+ break;
+ }
+ }
+
+ /* now, reflect transitivity */
+ changes = 1;
+ while(changes) {
+ changes = 0;
+ NTLOOP(i) {
+ t = pres[i+1];
+ for(s = pres[i]; s < t; ++s)
+ for(p = *s; (ch = (*p-NTBASE)) >= 0; ++p) {
+ changes |= setunion(wsets[i].ws.lset, wsets[ch].ws.lset);
+ if(!pempty[ch])
+ break;
+ }
+ }
+ }
+
+ NTLOOP(i)
+ pfirst[i] = flset(&wsets[i].ws);
+ if(!indebug)
+ return;
+ if(foutput != 0)
+ NTLOOP(i) {
+ Bprint(foutput, "\n%s: ", nontrst[i].name);
+ prlook(pfirst[i]);
+ Bprint(foutput, " %d\n", pempty[i]);
+ }
+}
+
+/*
+ * sorts last state,and sees if it equals earlier ones. returns state number
+ */
+int
+state(int c)
+{
+ Item *p1, *p2, *k, *l, *q1, *q2;
+ int size1, size2, i;
+
+ p1 = pstate[nstate];
+ p2 = pstate[nstate+1];
+ if(p1 == p2)
+ return 0; /* null state */
+ /* sort the items */
+ for(k = p2-1; k > p1; k--) /* make k the biggest */
+ for(l = k-1; l >= p1; --l)
+ if(l->pitem > k->pitem) {
+ int *s;
+ Lkset *ss;
+
+ s = k->pitem;
+ k->pitem = l->pitem;
+ l->pitem = s;
+ ss = k->look;
+ k->look = l->look;
+ l->look = ss;
+ }
+ size1 = p2 - p1; /* size of state */
+
+ for(i = (c>=NTBASE)? ntstates[c-NTBASE]: tstates[c]; i != 0; i = mstates[i]) {
+ /* get ith state */
+ q1 = pstate[i];
+ q2 = pstate[i+1];
+ size2 = q2 - q1;
+ if(size1 != size2)
+ continue;
+ k = p1;
+ for(l = q1; l < q2; l++) {
+ if(l->pitem != k->pitem)
+ break;
+ k++;
+ }
+ if(l != q2)
+ continue;
+ /* found it */
+ pstate[nstate+1] = pstate[nstate]; /* delete last state */
+ /* fix up lookaheads */
+ if(nolook)
+ return i;
+ for(l = q1, k = p1; l < q2; ++l, ++k ) {
+ int s;
+
+ SETLOOP(s)
+ clset.lset[s] = l->look->lset[s];
+ if(setunion(clset.lset, k->look->lset)) {
+ tystate[i] = MUSTDO;
+ /* register the new set */
+ l->look = flset( &clset );
+ }
+ }
+ return i;
+ }
+ /* state is new */
+ if(nolook)
+ error("yacc state/nolook error");
+ pstate[nstate+2] = p2;
+ if(nstate+1 >= NSTATES)
+ error("too many states");
+ if(c >= NTBASE) {
+ mstates[nstate] = ntstates[c-NTBASE];
+ ntstates[c-NTBASE] = nstate;
+ } else {
+ mstates[nstate] = tstates[c];
+ tstates[c] = nstate;
+ }
+ tystate[nstate] = MUSTDO;
+ return nstate++;
+}
+
+void
+putitem(int *ptr, Lkset *lptr)
+{
+ Item *j;
+
+ if(pidebug && foutput != 0)
+ Bprint(foutput, "putitem(%s), state %d\n", writem(ptr), nstate);
+ j = pstate[nstate+1];
+ j->pitem = ptr;
+ if(!nolook)
+ j->look = flset(lptr);
+ pstate[nstate+1] = ++j;
+ if((int*)j > zzmemsz) {
+ zzmemsz = (int*)j;
+ if(zzmemsz >= &mem0[MEMSIZE])
+ error("out of state space");
+ }
+}
+
+/*
+ * mark nonterminals which derive the empty string
+ * also, look for nonterminals which don't derive any token strings
+ */
+void
+cempty(void)
+{
+
+ int i, *p;
+
+ /* first, use the array pempty to detect productions that can never be reduced */
+ /* set pempty to WHONOWS */
+ aryfil(pempty, nnonter+1, WHOKNOWS);
+
+ /* now, look at productions, marking nonterminals which derive something */
+more:
+ PLOOP(0, i) {
+ if(pempty[*prdptr[i] - NTBASE])
+ continue;
+ for(p = prdptr[i]+1; *p >= 0; ++p)
+ if(*p >= NTBASE && pempty[*p-NTBASE] == WHOKNOWS)
+ break;
+ /* production can be derived */
+ if(*p < 0) {
+ pempty[*prdptr[i]-NTBASE] = OK;
+ goto more;
+ }
+ }
+
+ /* now, look at the nonterminals, to see if they are all OK */
+ NTLOOP(i) {
+ /* the added production rises or falls as the start symbol ... */
+ if(i == 0)
+ continue;
+ if(pempty[i] != OK) {
+ fatfl = 0;
+ error("nonterminal %s never derives any token string", nontrst[i].name);
+ }
+ }
+
+ if(nerrors) {
+ summary();
+ cleantmp();
+ exits("error");
+ }
+
+ /* now, compute the pempty array, to see which nonterminals derive the empty string */
+ /* set pempty to WHOKNOWS */
+ aryfil( pempty, nnonter+1, WHOKNOWS);
+
+ /* loop as long as we keep finding empty nonterminals */
+
+again:
+ PLOOP(1, i) {
+ /* not known to be empty */
+ if(pempty[*prdptr[i]-NTBASE] == WHOKNOWS) {
+ for(p = prdptr[i]+1; *p >= NTBASE && pempty[*p-NTBASE] == EMPTY ; ++p)
+ ;
+ /* we have a nontrivially empty nonterminal */
+ if(*p < 0) {
+ pempty[*prdptr[i]-NTBASE] = EMPTY;
+ /* got one ... try for another */
+ goto again;
+ }
+ }
+ }
+}
+
+/*
+ * generate the states
+ */
+void
+stagen(void)
+{
+
+ int c, i, j, more;
+ Wset *p, *q;
+
+ /* initialize */
+ nstate = 0;
+
+ /* THIS IS FUNNY from the standpoint of portability
+ * it represents the magic moment when the mem0 array, which has
+ * been holding the productions, starts to hold item pointers, of a
+ * different type...
+ * someday, alloc should be used to allocate all this stuff... for now, we
+ * accept that if pointers don't fit in integers, there is a problem...
+ */
+
+ pstate[0] = pstate[1] = (Item*)mem;
+ aryfil(clset.lset, tbitset, 0);
+ putitem(prdptr[0]+1, &clset);
+ tystate[0] = MUSTDO;
+ nstate = 1;
+ pstate[2] = pstate[1];
+
+ aryfil(amem, ACTSIZE, 0);
+
+ /* now, the main state generation loop */
+ for(more=1; more;) {
+ more = 0;
+ SLOOP(i) {
+ if(tystate[i] != MUSTDO)
+ continue;
+ tystate[i] = DONE;
+ aryfil(temp1, nnonter+1, 0);
+ /* take state i, close it, and do gotos */
+ closure(i);
+ /* generate goto's */
+ WSLOOP(wsets, p) {
+ if(p->flag)
+ continue;
+ p->flag = 1;
+ c = *(p->pitem);
+ if(c <= 1) {
+ if(pstate[i+1]-pstate[i] <= p-wsets)
+ tystate[i] = MUSTLOOKAHEAD;
+ continue;
+ }
+ /* do a goto on c */
+ WSLOOP(p, q)
+ /* this item contributes to the goto */
+ if(c == *(q->pitem)) {
+ putitem(q->pitem+1, &q->ws);
+ q->flag = 1;
+ }
+ if(c < NTBASE)
+ state(c); /* register new state */
+ else
+ temp1[c-NTBASE] = state(c);
+ }
+ if(gsdebug && foutput != 0) {
+ Bprint(foutput, "%d: ", i);
+ NTLOOP(j)
+ if(temp1[j])
+ Bprint(foutput, "%s %d, ",
+ nontrst[j].name, temp1[j]);
+ Bprint(foutput, "\n");
+ }
+ indgo[i] = apack(&temp1[1], nnonter-1) - 1;
+ /* do some more */
+ more = 1;
+ }
+ }
+}
+
+/*
+ * generate the closure of state i
+ */
+void
+closure(int i)
+{
+
+ Wset *u, *v;
+ Item *p, *q;
+ int c, ch, work, k, *pi, **s, **t;
+
+ zzclose++;
+
+ /* first, copy kernel of state i to wsets */
+ cwp = wsets;
+ ITMLOOP(i, p, q) {
+ cwp->pitem = p->pitem;
+ cwp->flag = 1; /* this item must get closed */
+ SETLOOP(k)
+ cwp->ws.lset[k] = p->look->lset[k];
+ WSBUMP(cwp);
+ }
+
+ /* now, go through the loop, closing each item */
+ work = 1;
+ while(work) {
+ work = 0;
+ WSLOOP(wsets, u) {
+ if(u->flag == 0)
+ continue;
+ /* dot is before c */
+ c = *(u->pitem);
+ if(c < NTBASE) {
+ u->flag = 0;
+ /* only interesting case is where . is before nonterminal */
+ continue;
+ }
+
+ /* compute the lookahead */
+ aryfil(clset.lset, tbitset, 0);
+
+ /* find items involving c */
+ WSLOOP(u, v)
+ if(v->flag == 1 && *(pi=v->pitem) == c) {
+ v->flag = 0;
+ if(nolook)
+ continue;
+ while((ch = *++pi) > 0) {
+ /* terminal symbol */
+ if(ch < NTBASE) {
+ SETBIT(clset.lset, ch);
+ break;
+ }
+ /* nonterminal symbol */
+ setunion(clset.lset, pfirst[ch-NTBASE]->lset);
+ if(!pempty[ch-NTBASE])
+ break;
+ }
+ if(ch <= 0)
+ setunion(clset.lset, v->ws.lset);
+ }
+
+ /*
+ * now loop over productions derived from c
+ * c is now nonterminal number
+ */
+ c -= NTBASE;
+ t = pres[c+1];
+ for(s = pres[c]; s < t; ++s) {
+ /*
+ * put these items into the closure
+ * is the item there
+ */
+ WSLOOP(wsets, v)
+ /* yes, it is there */
+ if(v->pitem == *s) {
+ if(nolook)
+ goto nexts;
+ if(setunion(v->ws.lset, clset.lset))
+ v->flag = work = 1;
+ goto nexts;
+ }
+
+ /* not there; make a new entry */
+ if(cwp-wsets+1 >= WSETSIZE)
+ error( "working set overflow");
+ cwp->pitem = *s;
+ cwp->flag = 1;
+ if(!nolook) {
+ work = 1;
+ SETLOOP(k) cwp->ws.lset[k] = clset.lset[k];
+ }
+ WSBUMP(cwp);
+
+ nexts:;
+ }
+ }
+ }
+
+ /* have computed closure; flags are reset; return */
+ if(cwp > zzcwp)
+ zzcwp = cwp;
+ if(cldebug && foutput != 0) {
+ Bprint(foutput, "\nState %d, nolook = %d\n", i, nolook);
+ WSLOOP(wsets, u) {
+ if(u->flag)
+ Bprint(foutput, "flag set!\n");
+ u->flag = 0;
+ Bprint(foutput, "\t%s", writem(u->pitem));
+ prlook(&u->ws);
+ Bprint(foutput, "\n");
+ }
+ }
+}
+
+/*
+ * decide if the lookahead set pointed to by p is known
+ * return pointer to a perminent location for the set
+ */
+Lkset*
+flset(Lkset *p)
+{
+ Lkset *q;
+ int *u, *v, *w, j;
+
+ for(q = &lkst[nlset]; q-- > lkst;) {
+ u = p->lset;
+ v = q->lset;
+ w = &v[tbitset];
+ while(v < w)
+ if(*u++ != *v++)
+ goto more;
+ /* we have matched */
+ return q;
+ more:;
+ }
+ /* add a new one */
+ q = &lkst[nlset++];
+ if(nlset >= LSETSIZE)
+ error("too many lookahead sets");
+ SETLOOP(j)
+ q->lset[j] = p->lset[j];
+ return q;
+}
+
+void
+cleantmp(void)
+{
+ ZAPFILE(actname);
+ ZAPFILE(tempname);
+}
+
+void
+intr(void)
+{
+ cleantmp();
+ exits("interrupted");
+}
+
+void
+setup(int argc, char *argv[])
+{
+ long c, t;
+ int i, j, lev, ty, ytab, *p;
+ int vflag, dflag, stem;
+ char actnm[8], *stemc, *cp;
+
+ ytab = 0;
+ vflag = 0;
+ dflag = 0;
+ stem = 0;
+ stemc = "y";
+ foutput = 0;
+ fdefine = 0;
+ fdebug = 0;
+ ARGBEGIN{
+ case 'v':
+ case 'V':
+ vflag++;
+ break;
+ case 'D':
+ yydebug = ARGF();
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'o':
+ ytab++;
+ ytabc = ARGF();
+ break;
+ case 's':
+ stem++;
+ stemc = ARGF();
+ break;
+ case 'S':
+ parser = PARSERS;
+ break;
+ default:
+ error("illegal option: %c", ARGC());
+ }ARGEND
+
+ cp = getenv("ROOT");
+ if(cp == 0)
+ cp = ROOT;
+ snprint(par, sizeof(par), "%s/utils/lib/%s", cp, parser);
+ parser = par;
+
+ openup(stemc, dflag, vflag, ytab, ytabc);
+
+ ftemp = Bopen(tempname = mktemp(ttempname), OWRITE);
+ faction = Bopen(actname = mktemp(tactname), OWRITE);
+ if(ftemp == 0 || faction == 0)
+ error("cannot open temp file");
+ if(argc < 1)
+ error("no input file");
+ infile = argv[0];
+ finput = Bopen(infile, OREAD);
+ if(finput == 0)
+ error("cannot open '%s'", argv[0]);
+ cnamp = cnames;
+
+ defin(0, "$end");
+ extval = PRIVATE; /* tokens start in unicode 'private use' */
+ defin(0, "error");
+ defin(1, "$accept");
+ defin(0, "$unk");
+ mem = mem0;
+ i = 0;
+
+ for(t = gettok(); t != MARK && t != ENDFILE;)
+ switch(t) {
+ case ';':
+ t = gettok();
+ break;
+
+ case START:
+ if(gettok() != IDENTIFIER)
+ error("bad %%start construction");
+ start = chfind(1, tokname);
+ t = gettok();
+ continue;
+
+ case TYPEDEF:
+ if(gettok() != TYPENAME)
+ error("bad syntax in %%type");
+ ty = numbval;
+ for(;;) {
+ t = gettok();
+ switch(t) {
+ case IDENTIFIER:
+ if((t=chfind(1, tokname)) < NTBASE) {
+ j = TYPE(toklev[t]);
+ if(j != 0 && j != ty)
+ error("type redeclaration of token %s",
+ tokset[t].name);
+ else
+ SETTYPE(toklev[t], ty);
+ } else {
+ j = nontrst[t-NTBASE].value;
+ if(j != 0 && j != ty)
+ error("type redeclaration of nonterminal %s",
+ nontrst[t-NTBASE].name );
+ else
+ nontrst[t-NTBASE].value = ty;
+ }
+ case ',':
+ continue;
+ case ';':
+ t = gettok();
+ default:
+ break;
+ }
+ break;
+ }
+ continue;
+
+ case UNION:
+ /* copy the union declaration to the output */
+ cpyunion();
+ t = gettok();
+ continue;
+
+ case LEFT:
+ case BINARY:
+ case RIGHT:
+ i++;
+
+ case TERM:
+ /* nonzero means new prec. and assoc. */
+ lev = t-TERM;
+ ty = 0;
+
+ /* get identifiers so defined */
+ t = gettok();
+
+ /* there is a type defined */
+ if(t == TYPENAME) {
+ ty = numbval;
+ t = gettok();
+ }
+ for(;;) {
+ switch(t) {
+ case ',':
+ t = gettok();
+ continue;
+
+ case ';':
+ break;
+
+ case IDENTIFIER:
+ j = chfind(0, tokname);
+ if(j >= NTBASE)
+ error("%s defined earlier as nonterminal", tokname);
+ if(lev) {
+ if(ASSOC(toklev[j]))
+ error("redeclaration of precedence of %s", tokname);
+ SETASC(toklev[j], lev);
+ SETPLEV(toklev[j], i);
+ }
+ if(ty) {
+ if(TYPE(toklev[j]))
+ error("redeclaration of type of %s", tokname);
+ SETTYPE(toklev[j],ty);
+ }
+ t = gettok();
+ if(t == NUMBER) {
+ tokset[j].value = numbval;
+ if(j < ndefout && j > 3)
+ error("please define type number of %s earlier",
+ tokset[j].name);
+ t = gettok();
+ }
+ continue;
+ }
+ break;
+ }
+ continue;
+
+ case LCURLY:
+ defout(0);
+ cpycode();
+ t = gettok();
+ continue;
+
+ default:
+ error("syntax error");
+ }
+ if(t == ENDFILE)
+ error("unexpected EOF before %%");
+
+ /* t is MARK */
+ Bprint(ftable, "extern int yyerrflag;\n");
+ Bprint(ftable, "#ifndef YYMAXDEPTH\n");
+ Bprint(ftable, "#define YYMAXDEPTH 150\n");
+ Bprint(ftable, "#endif\n" );
+ if(!ntypes) {
+ Bprint(ftable, "#ifndef YYSTYPE\n");
+ Bprint(ftable, "#define YYSTYPE int\n");
+ Bprint(ftable, "#endif\n");
+ }
+ Bprint(ftable, "YYSTYPE yylval;\n");
+ Bprint(ftable, "YYSTYPE yyval;\n");
+
+ prdptr[0] = mem;
+
+ /* added production */
+ *mem++ = NTBASE;
+
+ /* if start is 0, we will overwrite with the lhs of the first rule */
+ *mem++ = start;
+ *mem++ = 1;
+ *mem++ = 0;
+ prdptr[1] = mem;
+ while((t=gettok()) == LCURLY)
+ cpycode();
+ if(t != IDENTCOLON)
+ error("bad syntax on first rule");
+
+ if(!start)
+ prdptr[0][1] = chfind(1, tokname);
+
+ /* read rules */
+ while(t != MARK && t != ENDFILE) {
+ /* process a rule */
+ rlines[nprod] = lineno;
+ if(t == '|')
+ *mem++ = *prdptr[nprod-1];
+ else
+ if(t == IDENTCOLON) {
+ *mem = chfind(1, tokname);
+ if(*mem < NTBASE)
+ error("token illegal on LHS of grammar rule");
+ mem++;
+ } else
+ error("illegal rule: missing semicolon or | ?");
+ /* read rule body */
+ t = gettok();
+
+ more_rule:
+ while(t == IDENTIFIER) {
+ *mem = chfind(1, tokname);
+ if(*mem < NTBASE)
+ levprd[nprod] = toklev[*mem];
+ mem++;
+ t = gettok();
+ }
+ if(t == PREC) {
+ if(gettok() != IDENTIFIER)
+ error("illegal %%prec syntax");
+ j = chfind(2, tokname);
+ if(j >= NTBASE)
+ error("nonterminal %s illegal after %%prec",
+ nontrst[j-NTBASE].name);
+ levprd[nprod] = toklev[j];
+ t = gettok();
+ }
+ if(t == '=') {
+ levprd[nprod] |= ACTFLAG;
+ Bprint(faction, "\ncase %d:", nprod);
+ cpyact(mem-prdptr[nprod]-1);
+ Bprint(faction, " break;");
+ if((t=gettok()) == IDENTIFIER) {
+
+ /* action within rule... */
+ sprint(actnm, "$$%d", nprod);
+
+ /* make it a nonterminal */
+ j = chfind(1, actnm);
+
+ /*
+ * the current rule will become rule number nprod+1
+ * move the contents down, and make room for the null
+ */
+ for(p = mem; p >= prdptr[nprod]; --p)
+ p[2] = *p;
+ mem += 2;
+
+ /* enter null production for action */
+ p = prdptr[nprod];
+ *p++ = j;
+ *p++ = -nprod;
+
+ /* update the production information */
+ levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
+ levprd[nprod] = ACTFLAG;
+ if(++nprod >= NPROD)
+ error("more than %d rules", NPROD);
+ prdptr[nprod] = p;
+
+ /* make the action appear in the original rule */
+ *mem++ = j;
+
+ /* get some more of the rule */
+ goto more_rule;
+ }
+ }
+
+ while(t == ';')
+ t = gettok();
+ *mem++ = -nprod;
+
+ /* check that default action is reasonable */
+ if(ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].value) {
+
+ /* no explicit action, LHS has value */
+ int tempty;
+
+ tempty = prdptr[nprod][1];
+ if(tempty < 0)
+ error("must return a value, since LHS has a type");
+ else
+ if(tempty >= NTBASE)
+ tempty = nontrst[tempty-NTBASE].value;
+ else
+ tempty = TYPE(toklev[tempty]);
+ if(tempty != nontrst[*prdptr[nprod]-NTBASE].value)
+ error("default action causes potential type clash");
+ }
+ nprod++;
+ if(nprod >= NPROD)
+ error("more than %d rules", NPROD);
+ prdptr[nprod] = mem;
+ levprd[nprod] = 0;
+ }
+
+ /* end of all rules */
+ defout(1);
+
+ finact();
+ if(t == MARK) {
+ Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ while((c=Bgetrune(finput)) != Beof)
+ Bputrune(ftable, c);
+ }
+ Bterm(finput);
+}
+
+/*
+ * finish action routine
+ */
+void
+finact(void)
+{
+
+ Bterm(faction);
+ Bprint(ftable, "#define YYEOFCODE %d\n", 1);
+ Bprint(ftable, "#define YYERRCODE %d\n", 2);
+}
+
+/*
+ * define s to be a terminal if t=0
+ * or a nonterminal if t=1
+ */
+int
+defin(int nt, char *s)
+{
+ int val;
+ Rune rune;
+
+ val = 0;
+ if(nt) {
+ nnonter++;
+ if(nnonter >= NNONTERM)
+ error("too many nonterminals, limit %d",NNONTERM);
+ nontrst[nnonter].name = cstash(s);
+ return NTBASE + nnonter;
+ }
+
+ /* must be a token */
+ ntokens++;
+ if(ntokens >= NTERMS)
+ error("too many terminals, limit %d", NTERMS);
+ tokset[ntokens].name = cstash(s);
+
+ /* establish value for token */
+ /* single character literal */
+ if(s[0] == ' ') {
+ val = chartorune(&rune, &s[1]);
+ if(s[val+1] == 0) {
+ val = rune;
+ goto out;
+ }
+ }
+
+ /* escape sequence */
+ if(s[0] == ' ' && s[1] == '\\') {
+ if(s[3] == 0) {
+ /* single character escape sequence */
+ switch(s[2]) {
+ case 'n': val = '\n'; break;
+ case 'r': val = '\r'; break;
+ case 'b': val = '\b'; break;
+ case 't': val = '\t'; break;
+ case 'f': val = '\f'; break;
+ case '\'': val = '\''; break;
+ case '"': val = '"'; break;
+ case '\\': val = '\\'; break;
+ default: error("invalid escape");
+ }
+ goto out;
+ }
+
+ /* \nnn sequence */
+ if(s[2] >= '0' && s[2] <= '7') {
+ if(s[3] < '0' ||
+ s[3] > '7' ||
+ s[4] < '0' ||
+ s[4] > '7' ||
+ s[5] != 0)
+ error("illegal \\nnn construction");
+ val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
+ if(val == 0)
+ error("'\\000' is illegal");
+ goto out;
+ }
+ error("unknown escape");
+ }
+ val = extval++;
+
+out:
+ tokset[ntokens].value = val;
+ toklev[ntokens] = 0;
+ return ntokens;
+}
+
+/*
+ * write out the defines (at the end of the declaration section)
+ */
+void
+defout(int last)
+{
+ int i, c;
+ char sar[NAMESIZE+10];
+
+ for(i=ndefout; i<=ntokens; i++) {
+ /* non-literals */
+ c = tokset[i].name[0];
+ if(c != ' ' && c != '$') {
+ Bprint(ftable, "#define %s %d\n",
+ tokset[i].name, tokset[i].value);
+ if(fdefine)
+ Bprint(fdefine, "#define\t%s\t%d\n",
+ tokset[i].name, tokset[i].value);
+ }
+ }
+ ndefout = ntokens+1;
+ if(last && fdebug) {
+ Bprint(fdebug, "char* yytoknames[] =\n{\n");
+ TLOOP(i) {
+ if(tokset[i].name) {
+ chcopy(sar, tokset[i].name);
+ Bprint(fdebug, "\t\"%s\",\n", sar);
+ continue;
+ }
+ Bprint(fdebug, "\t0,\n");
+ }
+ Bprint(fdebug, "};\n");
+ }
+}
+
+char*
+cstash(char *s)
+{
+ char *temp;
+
+ temp = cnamp;
+ do {
+ if(cnamp >= &cnames[cnamsz])
+ error("too many characters in id's and literals");
+ else
+ *cnamp++ = *s;
+ } while(*s++);
+ return temp;
+}
+
+long
+gettok(void)
+{
+ long c;
+ Rune rune;
+ int i, base, match, reserve;
+ static int peekline;
+
+begin:
+ reserve = 0;
+ lineno += peekline;
+ peekline = 0;
+ c = Bgetrune(finput);
+ while(c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r') {
+ if(c == '\n')
+ lineno++;
+ c = Bgetrune(finput);
+ }
+
+ /* skip comment */
+ if(c == '/') {
+ lineno += skipcom();
+ goto begin;
+ }
+ switch(c) {
+ case Beof:
+ return ENDFILE;
+
+ case '{':
+ Bungetrune(finput);
+ return '=';
+
+ case '<':
+ /* get, and look up, a type name (union member name) */
+ i = 0;
+ while((c=Bgetrune(finput)) != '>' && c >= 0 && c != '\n' && c != '\r') {
+ rune = c;
+ c = runetochar(&tokname[i], &rune);
+ if(i < NAMESIZE)
+ i += c;
+ }
+ if(c != '>')
+ error("unterminated < ... > clause");
+ tokname[i] = 0;
+ for(i=1; i<=ntypes; i++)
+ if(!strcmp(typeset[i], tokname)) {
+ numbval = i;
+ return TYPENAME;
+ }
+ ntypes++;
+ numbval = ntypes;
+ typeset[numbval] = cstash(tokname);
+ return TYPENAME;
+
+ case '"':
+ case '\'':
+ match = c;
+ tokname[0] = ' ';
+ i = 1;
+ for(;;) {
+ c = Bgetrune(finput);
+ if(c == '\n' || c == '\r' || c <= 0)
+ error("illegal or missing ' or \"" );
+ if(c == '\\') {
+ tokname[i] = '\\';
+ if(i < NAMESIZE)
+ i++;
+ c = Bgetrune(finput);
+ } else
+ if(c == match)
+ break;
+ rune = c;
+ c = runetochar(&tokname[i], &rune);
+ if(i < NAMESIZE)
+ i += c;
+ }
+ break;
+
+ case '%':
+ case '\\':
+ switch(c = Bgetrune(finput)) {
+ case '0': return TERM;
+ case '<': return LEFT;
+ case '2': return BINARY;
+ case '>': return RIGHT;
+ case '%':
+ case '\\': return MARK;
+ case '=': return PREC;
+ case '{': return LCURLY;
+ default: reserve = 1;
+ }
+
+ default:
+ /* number */
+ if(isdigit(c)) {
+ numbval = c-'0';
+ base = (c=='0')? 8: 10;
+ for(c = Bgetrune(finput); isdigit(c); c = Bgetrune(finput))
+ numbval = numbval*base + (c-'0');
+ Bungetrune(finput);
+ return NUMBER;
+ }
+ if(islower(c) || isupper(c) || c=='_' || c=='.' || c=='$') {
+ i = 0;
+ while(islower(c) || isupper(c) || isdigit(c) ||
+ c == '-' || c=='_' || c=='.' || c=='$') {
+ if(reserve && isupper(c))
+ c += 'a'-'A';
+ rune = c;
+ c = runetochar(&tokname[i], &rune);
+ if(i < NAMESIZE)
+ i += c;
+ c = Bgetrune(finput);
+ }
+ } else
+ return c;
+ Bungetrune(finput);
+ }
+ tokname[i] = 0;
+
+ /* find a reserved word */
+ if(reserve) {
+ for(c=0; resrv[c].name; c++)
+ if(strcmp(tokname, resrv[c].name) == 0)
+ return resrv[c].value;
+ error("invalid escape, or illegal reserved word: %s", tokname);
+ }
+
+ /* look ahead to distinguish IDENTIFIER from IDENTCOLON */
+ c = Bgetrune(finput);
+ while(c == ' ' || c == '\t'|| c == '\n' || c == '\r' || c == '\f' || c == '/') {
+ if(c == '\n')
+ peekline++;
+ /* look for comments */
+ if(c == '/')
+ peekline += skipcom();
+ c = Bgetrune(finput);
+ }
+ if(c == ':')
+ return IDENTCOLON;
+ Bungetrune(finput);
+ return IDENTIFIER;
+}
+
+/*
+ * determine the type of a symbol
+ */
+int
+fdtype(int t)
+{
+ int v;
+
+ if(t >= NTBASE)
+ v = nontrst[t-NTBASE].value;
+ else
+ v = TYPE(toklev[t]);
+ if(v <= 0)
+ error("must specify type for %s", (t>=NTBASE)?
+ nontrst[t-NTBASE].name: tokset[t].name);
+ return v;
+}
+
+int
+chfind(int t, char *s)
+{
+ int i;
+
+ if(s[0] == ' ')
+ t = 0;
+ TLOOP(i)
+ if(!strcmp(s, tokset[i].name))
+ return i;
+ NTLOOP(i)
+ if(!strcmp(s, nontrst[i].name))
+ return NTBASE+i;
+
+ /* cannot find name */
+ if(t > 1)
+ error("%s should have been defined earlier", s);
+ return defin(t, s);
+}
+
+/*
+ * copy the union declaration to the output, and the define file if present
+ */
+void
+cpyunion(void)
+{
+ long c;
+ int level;
+
+ Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ Bprint(ftable, "typedef union ");
+ if(fdefine != 0)
+ Bprint(fdefine, "\ntypedef union ");
+
+ level = 0;
+ for(;;) {
+ if((c=Bgetrune(finput)) == Beof)
+ error("EOF encountered while processing %%union");
+ Bputrune(ftable, c);
+ if(fdefine != 0)
+ Bputrune(fdefine, c);
+ switch(c) {
+ case '\n':
+ lineno++;
+ break;
+ case '{':
+ level++;
+ break;
+ case '}':
+ level--;
+
+ /* we are finished copying */
+ if(level == 0) {
+ Bprint(ftable, " YYSTYPE;\n");
+ if(fdefine != 0)
+ Bprint(fdefine, "\tYYSTYPE;\nextern\tYYSTYPE\tyylval;\n");
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * copies code between \{ and \}
+ */
+void
+cpycode(void)
+{
+
+ long c;
+
+ c = Bgetrune(finput);
+ if(c == '\n') {
+ c = Bgetrune(finput);
+ lineno++;
+ }
+ Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ while(c != Beof) {
+ if(c == '\\') {
+ if((c=Bgetrune(finput)) == '}')
+ return;
+ Bputc(ftable, '\\');
+ }
+ if(c == '%') {
+ if((c=Bgetrune(finput)) == '}')
+ return;
+ Bputc(ftable, '%');
+ }
+ Bputrune(ftable, c);
+ if(c == '\n')
+ lineno++;
+ c = Bgetrune(finput);
+ }
+ error("eof before %%}");
+}
+
+/*
+ * skip over comments
+ * skipcom is called after reading a '/'
+ */
+int
+skipcom(void)
+{
+ long c;
+ int i;
+
+ /* i is the number of lines skipped */
+ i = 0;
+ if(Bgetrune(finput) != '*')
+ error("illegal comment");
+ c = Bgetrune(finput);
+ while(c != Beof) {
+ while(c == '*')
+ if((c=Bgetrune(finput)) == '/')
+ return i;
+ if(c == '\n')
+ i++;
+ c = Bgetrune(finput);
+ }
+ error("EOF inside comment");
+ return 0;
+}
+
+/*
+ * copy C action to the next ; or closing }
+ */
+void
+cpyact(int offset)
+{
+ long c;
+ int brac, match, j, s, fnd, tok;
+
+ Bprint(faction, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ brac = 0;
+
+loop:
+ c = Bgetrune(finput);
+swt:
+ switch(c) {
+ case ';':
+ if(brac == 0) {
+ Bputrune(faction, c);
+ return;
+ }
+ goto lcopy;
+
+ case '{':
+ brac++;
+ goto lcopy;
+
+ case '$':
+ s = 1;
+ tok = -1;
+ c = Bgetrune(finput);
+
+ /* type description */
+ if(c == '<') {
+ Bungetrune(finput);
+ if(gettok() != TYPENAME)
+ error("bad syntax on $<ident> clause");
+ tok = numbval;
+ c = Bgetrune(finput);
+ }
+ if(c == '$') {
+ Bprint(faction, "yyval");
+
+ /* put out the proper tag... */
+ if(ntypes) {
+ if(tok < 0)
+ tok = fdtype(*prdptr[nprod]);
+ Bprint(faction, ".%s", typeset[tok]);
+ }
+ goto loop;
+ }
+ if(c == '-') {
+ s = -s;
+ c = Bgetrune(finput);
+ }
+ if(isdigit(c)) {
+ j = 0;
+ while(isdigit(c)) {
+ j = j*10 + (c-'0');
+ c = Bgetrune(finput);
+ }
+ Bungetrune(finput);
+ j = j*s - offset;
+ if(j > 0)
+ error("Illegal use of $%d", j+offset);
+
+ dollar:
+ Bprint(faction, "yypt[-%d].yyv", -j);
+
+ /* put out the proper tag */
+ if(ntypes) {
+ if(j+offset <= 0 && tok < 0)
+ error("must specify type of $%d", j+offset);
+ if(tok < 0)
+ tok = fdtype(prdptr[nprod][j+offset]);
+ Bprint(faction, ".%s", typeset[tok]);
+ }
+ goto loop;
+ }
+ if(isupper(c) || islower(c) || c == '_' || c == '.') {
+ int tok; /* tok used oustide for type info */
+
+ /* look for $name */
+ Bungetrune(finput);
+ if(gettok() != IDENTIFIER)
+ error("$ must be followed by an identifier");
+ tok = chfind(2, tokname);
+ if((c = Bgetrune(finput)) != '#') {
+ Bungetrune(finput);
+ fnd = -1;
+ } else
+ if(gettok() != NUMBER) {
+ error("# must be followed by number");
+ fnd = -1;
+ } else
+ fnd = numbval;
+ for(j=1; j<=offset; ++j)
+ if(tok == prdptr[nprod][j]) {
+ if(--fnd <= 0) {
+ j -= offset;
+ goto dollar;
+ }
+ }
+ error("$name or $name#number not found");
+ }
+ Bputc(faction, '$');
+ if(s < 0 )
+ Bputc(faction, '-');
+ goto swt;
+
+ case '}':
+ brac--;
+ if(brac)
+ goto lcopy;
+ Bputrune(faction, c);
+ return;
+
+ case '/':
+ /* look for comments */
+ Bputrune(faction, c);
+ c = Bgetrune(finput);
+ if(c != '*')
+ goto swt;
+
+ /* it really is a comment */
+ Bputrune(faction, c);
+ c = Bgetrune(finput);
+ while(c >= 0) {
+ while(c == '*') {
+ Bputrune(faction, c);
+ if((c=Bgetrune(finput)) == '/')
+ goto lcopy;
+ }
+ Bputrune(faction, c);
+ if(c == '\n')
+ lineno++;
+ c = Bgetrune(finput);
+ }
+ error("EOF inside comment");
+
+ case '\'':
+ /* character constant */
+ match = '\'';
+ goto string;
+
+ case '"':
+ /* character string */
+ match = '"';
+
+ string:
+ Bputrune(faction, c);
+ while(c = Bgetrune(finput)) {
+ if(c == '\\') {
+ Bputrune(faction, c);
+ c = Bgetrune(finput);
+ if(c == '\n')
+ lineno++;
+ } else
+ if(c == match)
+ goto lcopy;
+ if(c == '\n')
+ error("newline in string or char. const.");
+ Bputrune(faction, c);
+ }
+ error("EOF in string or character constant");
+
+ case Beof:
+ error("action does not terminate");
+
+ case '\n':
+ lineno++;
+ goto lcopy;
+ }
+
+lcopy:
+ Bputrune(faction, c);
+ goto loop;
+}
+
+void
+openup(char *stem, int dflag, int vflag, int ytab, char *ytabc)
+{
+ char buf[256];
+
+ if(vflag) {
+ sprint(buf, "%s.%s", stem, FILEU);
+ foutput = Bopen(buf, OWRITE);
+ if(foutput == 0)
+ error("cannot open %s", buf);
+ }
+ if(yydebug) {
+ sprint(buf, "%s.%s", stem, FILEDEBUG);
+ if((fdebug = Bopen(buf, OWRITE)) == 0)
+ error("can't open %s", buf);
+ }
+ if(dflag) {
+ sprint(buf, "%s.%s", stem, FILED);
+ fdefine = Bopen(buf, OWRITE);
+ if(fdefine == 0)
+ error("can't create %s", buf);
+ }
+ if(ytab == 0)
+ sprint(buf, "%s.%s", stem, OFILE);
+ else
+ strcpy(buf, ytabc);
+ ftable = Bopen(buf, OWRITE);
+ if(ftable == 0)
+ error("cannot open table file %s", buf);
+}
+
+/*
+ * print the output for the states
+ */
+void
+output(void)
+{
+ int i, k, c;
+ Wset *u, *v;
+
+ Bprint(ftable, "short yyexca[] =\n{");
+ if(fdebug)
+ Bprint(fdebug, "char* yystates[] =\n{\n");
+
+ /* output the stuff for state i */
+ SLOOP(i) {
+ nolook = tystate[i]!=MUSTLOOKAHEAD;
+ closure(i);
+
+ /* output actions */
+ nolook = 1;
+ aryfil(temp1, ntokens+nnonter+1, 0);
+ WSLOOP(wsets, u) {
+ c = *(u->pitem);
+ if(c > 1 && c < NTBASE && temp1[c] == 0) {
+ WSLOOP(u, v)
+ if(c == *(v->pitem))
+ putitem(v->pitem+1, (Lkset*)0);
+ temp1[c] = state(c);
+ } else
+ if(c > NTBASE && temp1[(c -= NTBASE) + ntokens] == 0)
+ temp1[c+ntokens] = amem[indgo[i]+c];
+ }
+ if(i == 1)
+ temp1[1] = ACCEPTCODE;
+
+ /* now, we have the shifts; look at the reductions */
+ lastred = 0;
+ WSLOOP(wsets, u) {
+ c = *u->pitem;
+
+ /* reduction */
+ if(c <= 0) {
+ lastred = -c;
+ TLOOP(k)
+ if(BIT(u->ws.lset, k)) {
+ if(temp1[k] == 0)
+ temp1[k] = c;
+ else
+ if(temp1[k] < 0) { /* reduce/reduce conflict */
+ if(foutput)
+ Bprint(foutput,
+ "\n%d: reduce/reduce conflict"
+ " (red'ns %d and %d ) on %s",
+ i, -temp1[k], lastred,
+ symnam(k));
+ if(-temp1[k] > lastred)
+ temp1[k] = -lastred;
+ zzrrconf++;
+ } else
+ /* potential shift/reduce conflict */
+ precftn( lastred, k, i );
+ }
+ }
+ }
+ wract(i);
+ }
+
+ if(fdebug)
+ Bprint(fdebug, "};\n");
+ Bprint(ftable, "};\n");
+ Bprint(ftable, "#define YYNPROD %d\n", nprod);
+ Bprint(ftable, "#define YYPRIVATE %d\n", PRIVATE);
+ if(yydebug)
+ Bprint(ftable, "#define yydebug %s\n", yydebug);
+}
+
+/*
+ * pack state i from temp1 into amem
+ */
+int
+apack(int *p, int n)
+{
+ int *pp, *qq, *rr, off, *q, *r;
+
+ /* we don't need to worry about checking because
+ * we will only look at entries known to be there...
+ * eliminate leading and trailing 0's
+ */
+
+ q = p+n;
+ for(pp = p, off = 0; *pp == 0 && pp <= q; ++pp, --off)
+ ;
+ /* no actions */
+ if(pp > q)
+ return 0;
+ p = pp;
+
+ /* now, find a place for the elements from p to q, inclusive */
+ r = &amem[ACTSIZE-1];
+ for(rr = amem; rr <= r; rr++, off++) {
+ for(qq = rr, pp = p; pp <= q; pp++, qq++)
+ if(*pp != 0)
+ if(*pp != *qq && *qq != 0)
+ goto nextk;
+
+ /* we have found an acceptable k */
+ if(pkdebug && foutput != 0)
+ Bprint(foutput, "off = %d, k = %d\n", off, (int)(rr-amem));
+ for(qq = rr, pp = p; pp <= q; pp++, qq++)
+ if(*pp) {
+ if(qq > r)
+ error("action table overflow");
+ if(qq > memp)
+ memp = qq;
+ *qq = *pp;
+ }
+ if(pkdebug && foutput != 0)
+ for(pp = amem; pp <= memp; pp += 10) {
+ Bprint(foutput, "\t");
+ for(qq = pp; qq <= pp+9; qq++)
+ Bprint(foutput, "%d ", *qq);
+ Bprint(foutput, "\n");
+ }
+ return(off);
+ nextk:;
+ }
+ error("no space in action table");
+ return 0;
+}
+
+/*
+ * output the gotos for the nontermninals
+ */
+void
+go2out(void)
+{
+ int i, j, k, best, count, cbest, times;
+
+ /* mark begining of gotos */
+ Bprint(ftemp, "$\n");
+ for(i = 1; i <= nnonter; i++) {
+ go2gen(i);
+
+ /* find the best one to make default */
+ best = -1;
+ times = 0;
+
+ /* is j the most frequent */
+ for(j = 0; j <= nstate; j++) {
+ if(tystate[j] == 0)
+ continue;
+ if(tystate[j] == best)
+ continue;
+
+ /* is tystate[j] the most frequent */
+ count = 0;
+ cbest = tystate[j];
+ for(k = j; k <= nstate; k++)
+ if(tystate[k] == cbest)
+ count++;
+ if(count > times) {
+ best = cbest;
+ times = count;
+ }
+ }
+
+ /* best is now the default entry */
+ zzgobest += times-1;
+ for(j = 0; j <= nstate; j++)
+ if(tystate[j] != 0 && tystate[j] != best) {
+ Bprint(ftemp, "%d,%d,", j, tystate[j]);
+ zzgoent++;
+ }
+
+ /* now, the default */
+ if(best == -1)
+ best = 0;
+ zzgoent++;
+ Bprint(ftemp, "%d\n", best);
+ }
+}
+
+/*
+ * output the gotos for nonterminal c
+ */
+void
+go2gen(int c)
+{
+ int i, work, cc;
+ Item *p, *q;
+
+
+ /* first, find nonterminals with gotos on c */
+ aryfil(temp1, nnonter+1, 0);
+ temp1[c] = 1;
+ work = 1;
+ while(work) {
+ work = 0;
+ PLOOP(0, i)
+
+ /* cc is a nonterminal */
+ if((cc=prdptr[i][1]-NTBASE) >= 0)
+ /* cc has a goto on c */
+ if(temp1[cc] != 0) {
+
+ /* thus, the left side of production i does too */
+ cc = *prdptr[i]-NTBASE;
+ if(temp1[cc] == 0) {
+ work = 1;
+ temp1[cc] = 1;
+ }
+ }
+ }
+
+ /* now, we have temp1[c] = 1 if a goto on c in closure of cc */
+ if(g2debug && foutput != 0) {
+ Bprint(foutput, "%s: gotos on ", nontrst[c].name);
+ NTLOOP(i)
+ if(temp1[i])
+ Bprint(foutput, "%s ", nontrst[i].name);
+ Bprint(foutput, "\n");
+ }
+
+ /* now, go through and put gotos into tystate */
+ aryfil(tystate, nstate, 0);
+ SLOOP(i)
+ ITMLOOP(i, p, q)
+ if((cc = *p->pitem) >= NTBASE)
+ /* goto on c is possible */
+ if(temp1[cc-NTBASE]) {
+ tystate[i] = amem[indgo[i]+c];
+ break;
+ }
+}
+
+/*
+ * decide a shift/reduce conflict by precedence.
+ * r is a rule number, t a token number
+ * the conflict is in state s
+ * temp1[t] is changed to reflect the action
+ */
+void
+precftn(int r, int t, int s)
+{
+ int lp, lt, action;
+
+ lp = levprd[r];
+ lt = toklev[t];
+ if(PLEVEL(lt) == 0 || PLEVEL(lp) == 0) {
+
+ /* conflict */
+ if(foutput != 0)
+ Bprint(foutput,
+ "\n%d: shift/reduce conflict (shift %d(%d), red'n %d(%d)) on %s",
+ s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t));
+ zzsrconf++;
+ return;
+ }
+ if(PLEVEL(lt) == PLEVEL(lp))
+ action = ASSOC(lt);
+ else
+ if(PLEVEL(lt) > PLEVEL(lp))
+ action = RASC; /* shift */
+ else
+ action = LASC; /* reduce */
+ switch(action) {
+ case BASC: /* error action */
+ temp1[t] = ERRCODE;
+ break;
+ case LASC: /* reduce */
+ temp1[t] = -r;
+ break;
+ }
+}
+
+/*
+ * output state i
+ * temp1 has the actions, lastred the default
+ */
+void
+wract(int i)
+{
+ int p, p0, p1, ntimes, tred, count, j, flag;
+
+ /* find the best choice for lastred */
+ lastred = 0;
+ ntimes = 0;
+ TLOOP(j) {
+ if(temp1[j] >= 0)
+ continue;
+ if(temp1[j]+lastred == 0)
+ continue;
+ /* count the number of appearances of temp1[j] */
+ count = 0;
+ tred = -temp1[j];
+ levprd[tred] |= REDFLAG;
+ TLOOP(p)
+ if(temp1[p]+tred == 0)
+ count++;
+ if(count > ntimes) {
+ lastred = tred;
+ ntimes = count;
+ }
+ }
+
+ /*
+ * for error recovery, arrange that, if there is a shift on the
+ * error recovery token, `error', that the default be the error action
+ */
+ if(temp1[2] > 0)
+ lastred = 0;
+
+ /* clear out entries in temp1 which equal lastred */
+ TLOOP(p)
+ if(temp1[p]+lastred == 0)
+ temp1[p] = 0;
+
+ wrstate(i);
+ defact[i] = lastred;
+ flag = 0;
+ TLOOP(p0)
+ if((p1=temp1[p0]) != 0) {
+ if(p1 < 0) {
+ p1 = -p1;
+ goto exc;
+ }
+ if(p1 == ACCEPTCODE) {
+ p1 = -1;
+ goto exc;
+ }
+ if(p1 == ERRCODE) {
+ p1 = 0;
+ exc:
+ if(flag++ == 0)
+ Bprint(ftable, "-1, %d,\n", i);
+ Bprint(ftable, "\t%d, %d,\n", p0, p1);
+ zzexcp++;
+ continue;
+ }
+ Bprint(ftemp, "%d,%d,", p0, p1);
+ zzacent++;
+ }
+ if(flag) {
+ defact[i] = -2;
+ Bprint(ftable, "\t-2, %d,\n", lastred);
+ }
+ Bprint(ftemp, "\n");
+}
+
+/*
+ * writes state i
+ */
+void
+wrstate(int i)
+{
+ int j0, j1;
+ Item *pp, *qq;
+ Wset *u;
+
+ if(fdebug) {
+ if(lastred) {
+ Bprint(fdebug, " 0, /*%d*/\n", i);
+ } else {
+ Bprint(fdebug, " \"");
+ ITMLOOP(i, pp, qq)
+ Bprint(fdebug, "%s\\n", writem(pp->pitem));
+ if(tystate[i] == MUSTLOOKAHEAD)
+ WSLOOP(wsets + (pstate[i+1] - pstate[i]), u)
+ if(*u->pitem < 0)
+ Bprint(fdebug, "%s\\n", writem(u->pitem));
+ Bprint(fdebug, "\", /*%d*/\n", i);
+ }
+ }
+ if(foutput == 0)
+ return;
+ Bprint(foutput, "\nstate %d\n", i);
+ ITMLOOP(i, pp, qq)
+ Bprint(foutput, "\t%s\n", writem(pp->pitem));
+ if(tystate[i] == MUSTLOOKAHEAD)
+ /* print out empty productions in closure */
+ WSLOOP(wsets+(pstate[i+1]-pstate[i]), u)
+ if(*u->pitem < 0)
+ Bprint(foutput, "\t%s\n", writem(u->pitem));
+
+ /* check for state equal to another */
+ TLOOP(j0)
+ if((j1=temp1[j0]) != 0) {
+ Bprint(foutput, "\n\t%s ", symnam(j0));
+ /* shift, error, or accept */
+ if(j1 > 0) {
+ if(j1 == ACCEPTCODE)
+ Bprint(foutput, "accept");
+ else
+ if(j1 == ERRCODE)
+ Bprint(foutput, "error");
+ else
+ Bprint(foutput, "shift %d", j1);
+ } else
+ Bprint(foutput, "reduce %d (src line %d)", -j1, rlines[-j1]);
+ }
+
+ /* output the final production */
+ if(lastred)
+ Bprint(foutput, "\n\t. reduce %d (src line %d)\n\n",
+ lastred, rlines[lastred]);
+ else
+ Bprint(foutput, "\n\t. error\n\n");
+
+ /* now, output nonterminal actions */
+ j1 = ntokens;
+ for(j0 = 1; j0 <= nnonter; j0++) {
+ j1++;
+ if(temp1[j1])
+ Bprint(foutput, "\t%s goto %d\n", symnam(j0+NTBASE), temp1[j1]);
+ }
+}
+
+void
+warray(char *s, int *v, int n)
+{
+ int i;
+
+ Bprint(ftable, "short %s[] =\n{", s);
+ for(i=0;;) {
+ if(i%10 == 0)
+ Bprint(ftable, "\n");
+ Bprint(ftable, "%4d", v[i]);
+ i++;
+ if(i >= n) {
+ Bprint(ftable, "\n};\n");
+ break;
+ }
+ Bprint(ftable, ",");
+ }
+}
+
+/*
+ * in order to free up the mem and amem arrays for the optimizer,
+ * and still be able to output yyr1, etc., after the sizes of
+ * the action array is known, we hide the nonterminals
+ * derived by productions in levprd.
+ */
+
+void
+hideprod(void)
+{
+ int i, j;
+
+ j = 0;
+ levprd[0] = 0;
+ PLOOP(1, i) {
+ if(!(levprd[i] & REDFLAG)) {
+ j++;
+ if(foutput != 0)
+ Bprint(foutput, "Rule not reduced: %s\n", writem(prdptr[i]));
+ }
+ levprd[i] = *prdptr[i] - NTBASE;
+ }
+ if(j)
+ print("%d rules never reduced\n", j);
+}
+
+void
+callopt(void)
+{
+ int i, *p, j, k, *q;
+
+ /* read the arrays from tempfile and set parameters */
+ finput = Bopen(tempname, OREAD);
+ if(finput == 0)
+ error("optimizer cannot open tempfile");
+ pgo[0] = 0;
+ temp1[0] = 0;
+ nstate = 0;
+ nnonter = 0;
+ for(;;) {
+ switch(gtnm()) {
+ case '\n':
+ nstate++;
+ pmem--;
+ temp1[nstate] = pmem - mem0;
+ case ',':
+ continue;
+ case '$':
+ break;
+ default:
+ error("bad tempfile");
+ }
+ break;
+ }
+
+ pmem--;
+ temp1[nstate] = yypgo[0] = pmem - mem0;
+ for(;;) {
+ switch(gtnm()) {
+ case '\n':
+ nnonter++;
+ yypgo[nnonter] = pmem-mem0;
+ case ',':
+ continue;
+ case -1:
+ break;
+ default:
+ error("bad tempfile");
+ }
+ break;
+ }
+ pmem--;
+ yypgo[nnonter--] = pmem - mem0;
+ for(i = 0; i < nstate; i++) {
+ k = 32000;
+ j = 0;
+ q = mem0 + temp1[i+1];
+ for(p = mem0 + temp1[i]; p < q ; p += 2) {
+ if(*p > j)
+ j = *p;
+ if(*p < k)
+ k = *p;
+ }
+ /* nontrivial situation */
+ if(k <= j) {
+ /* j is now the range */
+/* j -= k; /* call scj */
+ if(k > maxoff)
+ maxoff = k;
+ }
+ tystate[i] = (temp1[i+1]-temp1[i]) + 2*j;
+ if(j > maxspr)
+ maxspr = j;
+ }
+
+ /* initialize ggreed table */
+ for(i = 1; i <= nnonter; i++) {
+ ggreed[i] = 1;
+ j = 0;
+
+ /* minimum entry index is always 0 */
+ q = mem0 + yypgo[i+1] - 1;
+ for(p = mem0+yypgo[i]; p < q ; p += 2) {
+ ggreed[i] += 2;
+ if(*p > j)
+ j = *p;
+ }
+ ggreed[i] = ggreed[i] + 2*j;
+ if(j > maxoff)
+ maxoff = j;
+ }
+
+ /* now, prepare to put the shift actions into the amem array */
+ for(i = 0; i < ACTSIZE; i++)
+ amem[i] = 0;
+ maxa = amem;
+ for(i = 0; i < nstate; i++) {
+ if(tystate[i] == 0 && adb > 1)
+ Bprint(ftable, "State %d: null\n", i);
+ indgo[i] = YYFLAG1;
+ }
+ while((i = nxti()) != NOMORE)
+ if(i >= 0)
+ stin(i);
+ else
+ gin(-i);
+
+ /* print amem array */
+ if(adb > 2 )
+ for(p = amem; p <= maxa; p += 10) {
+ Bprint(ftable, "%4d ", (int)(p-amem));
+ for(i = 0; i < 10; ++i)
+ Bprint(ftable, "%4d ", p[i]);
+ Bprint(ftable, "\n");
+ }
+
+ /* write out the output appropriate to the language */
+ aoutput();
+ osummary();
+ Bterm(finput);
+ ZAPFILE(tempname);
+}
+
+void
+gin(int i)
+{
+ int *p, *r, *s, *q1, *q2;
+
+ /* enter gotos on nonterminal i into array amem */
+ ggreed[i] = 0;
+
+ q2 = mem0+ yypgo[i+1] - 1;
+ q1 = mem0 + yypgo[i];
+
+ /* now, find amem place for it */
+ for(p = amem; p < &amem[ACTSIZE]; p++) {
+ if(*p)
+ continue;
+ for(r = q1; r < q2; r += 2) {
+ s = p + *r + 1;
+ if(*s)
+ goto nextgp;
+ if(s > maxa)
+ if((maxa = s) > &amem[ACTSIZE])
+ error("a array overflow");
+ }
+ /* we have found amem spot */
+ *p = *q2;
+ if(p > maxa)
+ if((maxa = p) > &amem[ACTSIZE])
+ error("a array overflow");
+ for(r = q1; r < q2; r += 2) {
+ s = p + *r + 1;
+ *s = r[1];
+ }
+ pgo[i] = p-amem;
+ if(adb > 1)
+ Bprint(ftable, "Nonterminal %d, entry at %d\n", i, pgo[i]);
+ return;
+
+ nextgp:;
+ }
+ error("cannot place goto %d\n", i);
+}
+
+void
+stin(int i)
+{
+ int *r, *s, n, flag, j, *q1, *q2;
+
+ tystate[i] = 0;
+
+ /* enter state i into the amem array */
+ q2 = mem0+temp1[i+1];
+ q1 = mem0+temp1[i];
+ /* find an acceptable place */
+ for(n = -maxoff; n < ACTSIZE; n++) {
+ flag = 0;
+ for(r = q1; r < q2; r += 2) {
+ if((s = *r + n + amem) < amem)
+ goto nextn;
+ if(*s == 0)
+ flag++;
+ else
+ if(*s != r[1])
+ goto nextn;
+ }
+
+ /* check that the position equals another only if the states are identical */
+ for(j=0; j<nstate; j++) {
+ if(indgo[j] == n) {
+
+ /* we have some disagreement */
+ if(flag)
+ goto nextn;
+ if(temp1[j+1]+temp1[i] == temp1[j]+temp1[i+1]) {
+
+ /* states are equal */
+ indgo[i] = n;
+ if(adb > 1)
+ Bprint(ftable,
+ "State %d: entry at %d equals state %d\n",
+ i, n, j);
+ return;
+ }
+
+ /* we have some disagreement */
+ goto nextn;
+ }
+ }
+
+ for(r = q1; r < q2; r += 2) {
+ if((s = *r+n+amem) >= &amem[ACTSIZE])
+ error("out of space in optimizer a array");
+ if(s > maxa)
+ maxa = s;
+ if(*s != 0 && *s != r[1])
+ error("clobber of a array, pos'n %d, by %d", s-amem, r[1]);
+ *s = r[1];
+ }
+ indgo[i] = n;
+ if(adb > 1)
+ Bprint(ftable, "State %d: entry at %d\n", i, indgo[i]);
+ return;
+ nextn:;
+ }
+ error("Error; failure to place state %d\n", i);
+}
+
+/*
+ * finds the next i
+ */
+int
+nxti(void)
+{
+ int i, max, maxi;
+
+ max = 0;
+ maxi = 0;
+ for(i = 1; i <= nnonter; i++)
+ if(ggreed[i] >= max) {
+ max = ggreed[i];
+ maxi = -i;
+ }
+ for(i = 0; i < nstate; ++i)
+ if(tystate[i] >= max) {
+ max = tystate[i];
+ maxi = i;
+ }
+ if(nxdb)
+ Bprint(ftable, "nxti = %d, max = %d\n", maxi, max);
+ if(max == 0)
+ return NOMORE;
+ return maxi;
+}
+
+/*
+ * write summary
+ */
+void
+osummary(void)
+{
+
+ int i, *p;
+
+ if(foutput == 0)
+ return;
+ i = 0;
+ for(p = maxa; p >= amem; p--)
+ if(*p == 0)
+ i++;
+
+ Bprint(foutput, "Optimizer space used: input %d/%d, output %d/%d\n",
+ (int)(pmem-mem0+1), MEMSIZE, (int)(maxa-amem+1), ACTSIZE);
+ Bprint(foutput, "%d table entries, %d zero\n", (int)(maxa-amem+1), i);
+ Bprint(foutput, "maximum spread: %d, maximum offset: %d\n", maxspr, maxoff);
+}
+
+/*
+ * this version is for C
+ * write out the optimized parser
+ */
+void
+aoutput(void)
+{
+ Bprint(ftable, "#define\tYYLAST\t%d\n", (int)(maxa-amem+1));
+ arout("yyact", amem, (maxa-amem)+1);
+ arout("yypact", indgo, nstate);
+ arout("yypgo", pgo, nnonter+1);
+}
+
+void
+arout(char *s, int *v, int n)
+{
+ int i;
+
+ Bprint(ftable, "short %s[] =\n{", s);
+ for(i = 0; i < n;) {
+ if(i%10 == 0)
+ Bprint(ftable, "\n");
+ Bprint(ftable, "%4d", v[i]);
+ i++;
+ if(i == n)
+ Bprint(ftable, "\n};\n");
+ else
+ Bprint(ftable, ",");
+ }
+}
+
+/*
+ * read and convert an integer from the standard input
+ * return the terminating character
+ * blanks, tabs, and newlines are ignored
+ */
+int
+gtnm(void)
+{
+ int sign, val, c;
+
+ sign = 0;
+ val = 0;
+ while((c=Bgetrune(finput)) != Beof) {
+ if(isdigit(c)) {
+ val = val*10 + c-'0';
+ continue;
+ }
+ if(c == '-') {
+ sign = 1;
+ continue;
+ }
+ break;
+ }
+ if(sign)
+ val = -val;
+ *pmem++ = val;
+ if(pmem >= &mem0[MEMSIZE])
+ error("out of space");
+ return c;
+}
diff --git a/utils/yacc/yaccpar b/utils/yacc/yaccpar
new file mode 100644
index 00000000..efc1da06
--- /dev/null
+++ b/utils/yacc/yaccpar
@@ -0,0 +1,241 @@
+#define YYFLAG -1000
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+
+#ifdef yydebug
+#include "y.debug"
+#else
+#define yydebug 0
+char* yytoknames[1]; /* for debugging */
+char* yystates[1]; /* for debugging */
+#endif
+
+/* parser for yacc output */
+
+int yynerrs = 0; /* number of errors */
+int yyerrflag = 0; /* error recovery flag */
+
+extern int fprint(int, char*, ...);
+extern int sprint(char*, char*, ...);
+
+char*
+yytokname(int yyc)
+{
+ static char x[10];
+
+ if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
+ if(yytoknames[yyc-1])
+ return yytoknames[yyc-1];
+ sprint(x, "<%d>", yyc);
+ return x;
+}
+
+char*
+yystatname(int yys)
+{
+ static char x[10];
+
+ if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
+ if(yystates[yys])
+ return yystates[yys];
+ sprint(x, "<%d>\n", yys);
+ return x;
+}
+
+long
+yylex1(void)
+{
+ long yychar;
+ long *t3p;
+ int c;
+
+ yychar = yylex();
+ if(yychar <= 0) {
+ c = yytok1[0];
+ goto out;
+ }
+ if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
+ c = yytok1[yychar];
+ goto out;
+ }
+ if(yychar >= YYPRIVATE)
+ if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
+ c = yytok2[yychar-YYPRIVATE];
+ goto out;
+ }
+ for(t3p=yytok3;; t3p+=2) {
+ c = t3p[0];
+ if(c == yychar) {
+ c = t3p[1];
+ goto out;
+ }
+ if(c == 0)
+ break;
+ }
+ c = 0;
+
+out:
+ if(c == 0)
+ c = yytok2[1]; /* unknown char */
+ if(yydebug >= 3)
+ fprint(2, "lex %.4lux %s\n", yychar, yytokname(c));
+ return c;
+}
+
+int
+yyparse(void)
+{
+ struct
+ {
+ YYSTYPE yyv;
+ int yys;
+ } yys[YYMAXDEPTH], *yyp, *yypt;
+ short *yyxi;
+ int yyj, yym, yystate, yyn, yyg;
+ long yychar;
+ YYSTYPE save1, save2;
+ int save3, save4;
+
+ save1 = yylval;
+ save2 = yyval;
+ save3 = yynerrs;
+ save4 = yyerrflag;
+
+ yystate = 0;
+ yychar = -1;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yyp = &yys[-1];
+ goto yystack;
+
+ret0:
+ yyn = 0;
+ goto ret;
+
+ret1:
+ yyn = 1;
+ goto ret;
+
+ret:
+ yylval = save1;
+ yyval = save2;
+ yynerrs = save3;
+ yyerrflag = save4;
+ return yyn;
+
+yystack:
+ /* put a state and value onto the stack */
+ if(yydebug >= 4)
+ fprint(2, "char %s in %s", yytokname(yychar), yystatname(yystate));
+
+ yyp++;
+ if(yyp >= &yys[YYMAXDEPTH]) {
+ yyerror("yacc stack overflow");
+ goto ret1;
+ }
+ yyp->yys = yystate;
+ yyp->yyv = yyval;
+
+yynewstate:
+ yyn = yypact[yystate];
+ if(yyn <= YYFLAG)
+ goto yydefault; /* simple state */
+ if(yychar < 0)
+ yychar = yylex1();
+ yyn += yychar;
+ if(yyn < 0 || yyn >= YYLAST)
+ goto yydefault;
+ yyn = yyact[yyn];
+ if(yychk[yyn] == yychar) { /* valid shift */
+ yychar = -1;
+ yyval = yylval;
+ yystate = yyn;
+ if(yyerrflag > 0)
+ yyerrflag--;
+ goto yystack;
+ }
+
+yydefault:
+ /* default state action */
+ yyn = yydef[yystate];
+ if(yyn == -2) {
+ if(yychar < 0)
+ yychar = yylex1();
+
+ /* look through exception table */
+ for(yyxi=yyexca;; yyxi+=2)
+ if(yyxi[0] == -1 && yyxi[1] == yystate)
+ break;
+ for(yyxi += 2;; yyxi += 2) {
+ yyn = yyxi[0];
+ if(yyn < 0 || yyn == yychar)
+ break;
+ }
+ yyn = yyxi[1];
+ if(yyn < 0)
+ goto ret0;
+ }
+ if(yyn == 0) {
+ /* error ... attempt to resume parsing */
+ switch(yyerrflag) {
+ case 0: /* brand new error */
+ yyerror("syntax error");
+ yynerrs++;
+ if(yydebug >= 1) {
+ fprint(2, "%s", yystatname(yystate));
+ fprint(2, "saw %s\n", yytokname(yychar));
+ }
+
+ case 1:
+ case 2: /* incompletely recovered error ... try again */
+ yyerrflag = 3;
+
+ /* find a state where "error" is a legal shift action */
+ while(yyp >= yys) {
+ yyn = yypact[yyp->yys] + YYERRCODE;
+ if(yyn >= 0 && yyn < YYLAST) {
+ yystate = yyact[yyn]; /* simulate a shift of "error" */
+ if(yychk[yystate] == YYERRCODE)
+ goto yystack;
+ }
+
+ /* the current yyp has no shift onn "error", pop stack */
+ if(yydebug >= 2)
+ fprint(2, "error recovery pops state %d, uncovers %d\n",
+ yyp->yys, (yyp-1)->yys );
+ yyp--;
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1;
+
+ case 3: /* no shift yet; clobber input char */
+ if(yydebug >= 2)
+ fprint(2, "error recovery discards %s\n", yytokname(yychar));
+ if(yychar == YYEOFCODE)
+ goto ret1;
+ yychar = -1;
+ goto yynewstate; /* try again in the same state */
+ }
+ }
+
+ /* reduction by production yyn */
+ if(yydebug >= 2)
+ fprint(2, "reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+ yypt = yyp;
+ yyp -= yyr2[yyn];
+ yyval = (yyp+1)->yyv;
+ yym = yyn;
+
+ /* consult goto table to find next state */
+ yyn = yyr1[yyn];
+ yyg = yypgo[yyn];
+ yyj = yyg + yyp->yys + 1;
+
+ if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+ yystate = yyact[yyg];
+ switch(yym) {
+ $A
+ }
+ goto yystack; /* stack new state and value */
+}