-
Notifications
You must be signed in to change notification settings - Fork 0
/
rtl-traverse.scm
2222 lines (1949 loc) · 74.1 KB
/
rtl-traverse.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;; RTL traversing support.
;; Copyright (C) 2000, 2001, 2009, 2010 Red Hat, Inc.
;; This file is part of CGEN.
;; See file COPYING.CGEN for details.
;; Canonicalization support.
;; Canonicalizing an rtl expression involves adding possibly missing options
;; and mode, and converting occurrences of DFLT into usable modes.
;; Various error checks are done as well.
;; This is done differently than traversal support because it has a more
;; specific purpose, it doesn't need to support arbitrary "expr-fns".
;; ??? At present the internal form is also the source form (easier debugging).
(define /rtx-canon-debug? #f)
;; Canonicalization state.
;; This carries the immutable elements only!
;; OUTER-EXPR is the EXPR argument to rtx-canonicalize.
(define (/make-cstate context isa-name-list outer-expr)
(vector context isa-name-list outer-expr)
)
(define (/cstate-context cstate) (vector-ref cstate 0))
(define (/cstate-isas cstate) (vector-ref cstate 1))
(define (/cstate-outer-expr cstate) (vector-ref cstate 2))
;; Flag an error while canonicalizing rtl.
(define (/rtx-canon-error cstate errmsg expr parent-expr op-num)
(let* ((pretty-parent-expr (rtx-pretty-strdump (/cstate-outer-expr cstate)))
(intro (if parent-expr
(string-append "While canonicalizing "
(rtx-strdump parent-expr)
(if op-num
(string-append ", operand #"
(number->string op-num))
"")
" of:\n"
pretty-parent-expr)
(string-append "While canonicalizing:\n" pretty-parent-expr))))
(context-error (/cstate-context cstate) intro errmsg (rtx-dump expr)))
)
;; Lookup h/w object HW-NAME and return it (as a <hardware-base> object).
;; If multiple h/w objects with the same name are defined, require
;; all to have the same mode.
;; CHECK-KIND is a function of one argument to verify the h/w objects
;; are valid and if not flag an error.
(define (/rtx-lookup-hw cstate hw-name parent-expr check-kind)
(let ((hw-objs (current-hw-sem-lookup hw-name)))
(if (null? hw-objs)
(/rtx-canon-error cstate "unknown h/w object"
hw-name parent-expr #f))
;; Just check the first one with CHECK-KIND.
(check-kind (car hw-objs))
(let* ((hw1 (car hw-objs))
(hw1-mode (hw-mode hw1))
(hw1-mode-name (obj:name hw1-mode)))
;; Allow multiple h/w objects with the same name
;; as long has they have the same mode.
(if (> (length hw-objs) 1)
(let ((other-hw-mode-names (map (lambda (hw)
(obj:name (hw-mode hw)))
(cdr hw-objs))))
(if (not (all-true? (map (lambda (mode-name)
(eq? mode-name hw1-mode-name))
other-hw-mode-names)))
(/rtx-canon-error cstate "multiple h/w objects with different modes selected"
hw-name parent-expr #f))))
hw1))
)
;; Return the mode name to use in an expression given the requested mode
;; and the mode used in the expression.
;; If both are DFLT, leave it alone and hope the expression provides
;; enough info to pick a usable mode.
;; If both are provided, prefer the mode used in the expression.
;; If the modes are incompatible, return #f.
(define (/rtx-pick-mode cstate requested-mode-name expr-mode-name)
(cond ((eq? requested-mode-name 'DFLT)
expr-mode-name)
((eq? expr-mode-name 'DFLT)
requested-mode-name)
(else
(let ((requested-mode (mode:lookup requested-mode-name))
(expr-mode (mode:lookup expr-mode-name)))
(if (not requested-mode)
(/rtx-canon-error cstate "invalid mode" requested-mode-name #f #f))
(if (not expr-mode)
(/rtx-canon-error cstate "invalid mode" expr-mode-name #f #f))
;; FIXME: 'would prefer samesize or "no precision lost", sigh
(if (mode-compatible? 'sameclass requested-mode expr-mode)
expr-mode-name
expr-mode-name)))) ;; FIXME: should be #f, disabled pending completion of rtl mode handling rewrite
)
;; Return the mode name (as a symbol) to use in an object's rtl given
;; the requested mode, the mode used in the expression, and the object's
;; real mode.
;; If both requested mode and expr mode are DFLT, use the real mode.
;; If requested mode is DFLT, prefer expr mode.
;; If expr mode is DFLT, prefer the real mode.
;; If both requested mode and expr mode are specified, prefer expr-mode.
;; If there's an error the result is the error message (as a string).
;;
;; E.g. in (set SI dest (ifield DFLT f-r1)), the mode of the ifield's
;; expression is DFLT, the requested mode is SI, and the real mode of f-r1
;; may be INT.
;;
;; REAL-MODE is a <mode> object.
(define (/rtx-pick-mode3 requested-mode-name expr-mode-name real-mode)
;; Leave checking for (symbol? requested-mode-name) to caller (or higher).
(let ((expr-mode (mode:lookup expr-mode-name)))
(cond ((not expr-mode)
"unknown mode")
((eq? requested-mode-name 'DFLT)
(if (eq? expr-mode-name 'DFLT)
(obj:name real-mode)
(if (rtx-mode-compatible? expr-mode real-mode)
expr-mode-name
(string-append "expression mode "
(symbol->string expr-mode-name)
" is incompatible with real mode "
(obj:str-name real-mode)))))
((eq? expr-mode-name 'DFLT)
(if (rtx-mode-compatible? (mode:lookup requested-mode-name)
real-mode)
(obj:name real-mode)
(string-append "mode of containing expression "
(symbol->string requested-mode-name)
" is incompatible with real mode "
(obj:str-name real-mode))))
(else
(let ((requested-mode (mode:lookup requested-mode-name)))
(cond ((not (rtx-mode-compatible? requested-mode expr-mode))
(string-append "mode of containing expression "
(symbol->string requested-mode-name)
" is incompatible with expression mode "
(symbol->string expr-mode-name)))
((not (rtx-mode-compatible? expr-mode real-mode))
(string-append "expression mode "
(symbol->string expr-mode-name)
" is incompatible with real mode "
(obj:str-name real-mode)))
(else
expr-mode-name))))))
)
;; Return the mode name (as a symbol) to use in an operand's rtl given
;; the requested mode, the mode used in the expression, and the operand's
;; real mode.
;; If both requested mode and expr mode are DFLT, use the real mode.
;; If requested mode is DFLT, prefer expr mode.
;; If expr mode is DFLT, prefer the real mode.
;; If both requested mode and expr mode are specified, prefer expr-mode.
;; If the modes are incompatible an error is signalled.
;;
;; E.g. in (set QI (mem QI src2) src1), the mode to set is QI, but if src1
;; is a 32-bit (SI) register we want QI.
;; OTOH, in (set QI (mem QI src2) uimm8), the mode to set is QI, but we want
;; the real mode of uimm8.
;;
;; ??? This is different from /rtx-pick-mode3 for compatibility with
;; pre-full-canonicalization versions.
; It's currently a toss-up on whether it improves things.
;;
;; OP is an <operand> object.
;;
;; Things are complicated because multiple versions of a h/w object can be
;; defined, and the operand refers to the h/w by name.
;; op:type, which op:mode calls, will flag an error if multiple versions of
;; a h/w object are defined - only one should have been kept during .cpu
;; file loading. This is for semantic code generation, but for generating
;; files covering the entire architecture we need to keep all the versions.
;; Things are ok, as far as canonicalization is concerned, if all h/w versions
;; have the same mode (which could be WI for 32/64 arches).
(define (/rtx-pick-op-mode cstate requested-mode-name expr-mode-name op
parent-expr)
;; Leave checking for (symbol? requested-mode-name) to caller (or higher).
(let* ((op-mode-name (op:mode-name op))
(hw (/rtx-lookup-hw cstate (op:hw-name op) parent-expr
(lambda (hw) *UNSPECIFIED*)))
(op-mode (if (eq? op-mode-name 'DFLT)
(hw-mode hw)
(mode:lookup op-mode-name)))
(expr-mode (mode:lookup expr-mode-name)))
(cond ((not expr-mode)
(/rtx-canon-error cstate "unknown mode" expr-mode-name
parent-expr #f))
((eq? requested-mode-name 'DFLT)
(if (eq? expr-mode-name 'DFLT)
(obj:name op-mode)
(if (rtx-mode-compatible? expr-mode op-mode)
expr-mode-name
(/rtx-canon-error cstate
(string-append
"expression mode "
(symbol->string expr-mode-name)
" is incompatible with operand mode "
(obj:str-name op-mode))
expr-mode-name parent-expr #f))))
((eq? expr-mode-name 'DFLT)
(if (rtx-mode-compatible? (mode:lookup requested-mode-name)
op-mode)
; FIXME: Experiment. It's currently a toss-up on whether it improves things.
; (cond ((pc? op)
; (obj:name op-mode))
; ((register? hw)
; requested-mode-name)
; (else
; (obj:name op-mode)))
(obj:name op-mode)
(/rtx-canon-error cstate
(string-append
"mode of containing expression "
(symbol->string requested-mode-name)
" is incompatible with operand mode "
(obj:str-name op-mode))
requested-mode-name parent-expr #f)))
(else
(let ((requested-mode (mode:lookup requested-mode-name)))
(cond ((not (rtx-mode-compatible? requested-mode expr-mode))
(/rtx-canon-error cstate
(string-append
"mode of containing expression "
(symbol->string requested-mode-name)
" is incompatible with expression mode "
(symbol->string expr-mode-name))
requested-mode-name parent-expr #f))
((not (rtx-mode-compatible? expr-mode op-mode))
(/rtx-canon-error cstate
(string-append
"expression mode "
(symbol->string expr-mode-name)
" is incompatible with operand mode "
(obj:str-name op-mode))
expr-mode-name parent-expr #f))
(else
expr-mode-name))))))
)
;; Return the last rtx in cond or case expression EXPR.
(define (/rtx-get-last-cond-case-rtx expr)
(let ((len (length expr)))
(list-ref expr (- len 1)))
)
;; Canonicalize a list of rtx's.
;; The mode of rtxes prior to the last one must be VOID.
(define (/rtx-canon-rtx-list rtx-list mode parent-expr op-num cstate env depth)
(let* ((nr-rtxes (length rtx-list))
(last-op-num (- nr-rtxes 1)))
(map (lambda (rtx op-num)
(/rtx-canon rtx 'RTX
(if (= op-num last-op-num) mode 'VOID)
parent-expr op-num cstate env depth))
rtx-list (iota nr-rtxes)))
)
;; Rtx canonicalizers.
;; These are defined as individual functions that are then built into a table
;; mostly for simplicity.
;
;; The result is either a pair of the parsed VAL and new environment,
;; or #f meaning there is no change (saves lots of unnecessarying cons'ing).
(define (/rtx-canon-options val mode parent-expr op-num cstate env depth)
#f
)
(define (/rtx-canon-anyintmode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(or (memq (mode:class val-obj) '(INT UINT))
(eq? val 'DFLT)))
#f
(/rtx-canon-error cstate "expecting an integer mode"
val parent-expr op-num)))
)
(define (/rtx-canon-anyfloatmode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(or (memq (mode:class val-obj) '(FLOAT))
(eq? val 'DFLT)))
#f
(/rtx-canon-error cstate "expecting a float mode"
val parent-expr op-num)))
)
(define (/rtx-canon-anynummode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(or (memq (mode:class val-obj) '(INT UINT FLOAT))
(eq? val 'DFLT)))
#f
(/rtx-canon-error cstate "expecting a numeric mode"
val parent-expr op-num)))
)
(define (/rtx-canon-anyexprmode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(or (memq (mode:class val-obj) '(INT UINT FLOAT))
(memq val '(DFLT PTR VOID SYM))))
#f
(/rtx-canon-error cstate "expecting a numeric mode, PTR, VOID, or SYM"
val parent-expr op-num)))
)
(define (/rtx-canon-anycexprmode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(or (memq (mode:class val-obj) '(INT UINT FLOAT))
(memq val '(DFLT PTR VOID))))
#f
(/rtx-canon-error cstate "expecting a numeric mode, PTR, or VOID"
val parent-expr op-num)))
)
(define (/rtx-canon-explnummode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(memq (mode:class val-obj) '(INT UINT FLOAT)))
#f
(/rtx-canon-error cstate "expecting an explicit numeric mode"
val parent-expr op-num)))
)
(define (/rtx-canon-voidornummode val mode parent-expr op-num cstate env depth)
(let ((val-obj (mode:lookup val)))
(if (and val-obj
(or (memq (mode:class val-obj) '(INT UINT FLOAT))
(memq val '(DFLT VOID))))
#f
(/rtx-canon-error cstate "expecting void or a numeric mode"
val parent-expr op-num)))
)
(define (/rtx-canon-voidmode val mode parent-expr op-num cstate env depth)
(if (memq val '(DFLT VOID))
(cons 'VOID env)
(/rtx-canon-error cstate "expecting VOID mode"
val parent-expr op-num))
)
(define (/rtx-canon-bimode val mode parent-expr op-num cstate env depth)
(if (memq val '(DFLT BI))
(cons 'BI env)
(/rtx-canon-error cstate "expecting BI mode"
val parent-expr op-num))
)
(define (/rtx-canon-intmode val mode parent-expr op-num cstate env depth)
(if (memq val '(DFLT INT))
(cons 'INT env)
(/rtx-canon-error cstate "expecting INT mode"
val parent-expr op-num))
)
(define (/rtx-canon-symmode val mode parent-expr op-num cstate env depth)
(if (memq val '(DFLT SYM))
(cons 'SYM env)
(/rtx-canon-error cstate "expecting SYM mode"
val parent-expr op-num))
)
(define (/rtx-canon-insnmode val mode parent-expr op-num cstate env depth)
(if (memq val '(DFLT INSN))
(cons 'INSN env)
(/rtx-canon-error cstate "expecting INSN mode"
val parent-expr op-num))
)
(define (/rtx-canon-machmode val mode parent-expr op-num cstate env depth)
(if (memq val '(DFLT MACH))
(cons 'MACH env)
(/rtx-canon-error cstate "expecting MACH mode"
val parent-expr op-num))
)
(define (/rtx-canon-rtx val mode parent-expr op-num cstate env depth)
; Commented out 'cus it doesn't quite work yet.
; (if (not (rtx? val))
; (/rtx-canon-error cstate "expecting an rtx" val parent-expr op-num))
(cons (/rtx-canon val 'RTX mode parent-expr op-num cstate env depth)
env)
)
(define (/rtx-canon-setrtx val mode parent-expr op-num cstate env depth)
; Commented out 'cus it doesn't quite work yet.
; (if (not (rtx? val))
; (/rtx-canon-error cstate "expecting an rtx" val parent-expr op-num))
(let ((dest (/rtx-canon val 'SETRTX mode parent-expr op-num cstate env depth)))
(cons dest env))
)
;; This is the test of an `if'.
(define (/rtx-canon-testrtx val mode parent-expr op-num cstate env depth)
; Commented out 'cus it doesn't quite work yet.
; (if (not (rtx? val))
; (/rtx-canon-error cstate "expecting an rtx"
; val parent-expr op-num))
(cons (/rtx-canon val 'RTX mode parent-expr op-num cstate env depth)
env)
)
(define (/rtx-canon-condrtx val mode parent-expr op-num cstate env depth)
(if (not (pair? val))
(/rtx-canon-error cstate "expecting an expression"
val parent-expr op-num))
(if (eq? (car val) 'else)
(begin
(if (!= (+ op-num 2) (length parent-expr))
(/rtx-canon-error cstate "`else' clause not last"
val parent-expr op-num))
(cons (cons 'else
(/rtx-canon-rtx-list
(cdr val) mode parent-expr op-num cstate env depth))
env))
(cons (cons
;; ??? Entries after the first are conditional.
(/rtx-canon (car val) 'RTX 'INT parent-expr op-num cstate env depth)
(/rtx-canon-rtx-list
(cdr val) mode parent-expr op-num cstate env depth))
env))
)
(define (/rtx-canon-casertx val mode parent-expr op-num cstate env depth)
(if (or (not (list? val))
(< (length val) 2))
(/rtx-canon-error cstate "invalid `case' expression"
val parent-expr op-num))
;; car is either 'else or list of symbols/numbers
(if (not (or (eq? (car val) 'else)
(and (list? (car val))
(not (null? (car val)))
(all-true? (map /rtx-symornum?
(car val))))))
(/rtx-canon-error cstate "invalid `case' choice"
val parent-expr op-num))
(if (and (eq? (car val) 'else)
(!= (+ op-num 2) (length parent-expr)))
(/rtx-canon-error cstate "`else' clause not last"
val parent-expr op-num))
(cons (cons (car val)
(/rtx-canon-rtx-list
(cdr val) mode parent-expr op-num cstate env depth))
env)
)
(define (/rtx-canon-locals val mode parent-expr op-num cstate env depth)
(if (not (list? val))
(/rtx-canon-error cstate "bad locals list"
val parent-expr op-num))
(for-each (lambda (var)
(if (or (not (list? var))
(!= (length var) 2)
(not (/rtx-any-mode? (car var)))
(not (symbol? (cadr var))))
(/rtx-canon-error cstate "bad locals list"
val parent-expr op-num)))
val)
(let ((new-env (rtx-env-make-locals val)))
(cons val (cons new-env env)))
)
(define (/rtx-canon-iteration val mode parent-expr op-num cstate env depth)
(if (not (symbol? val))
(/rtx-canon-error cstate "bad iteration variable name"
val parent-expr op-num))
(let ((new-env (rtx-env-make-iteration-locals val)))
(cons val (cons new-env env)))
)
(define (/rtx-canon-symbol-list val mode parent-expr op-num cstate env depth)
(if (or (not (list? val))
(not (all-true? (map symbol? val))))
(/rtx-canon-error cstate "bad symbol list"
val parent-expr op-num))
#f
)
(define (/rtx-canon-env-stack val mode parent-expr op-num cstate env depth)
;; VAL is an environment stack.
(if (not (list? val))
(/rtx-canon-error cstate "environment not a list"
val parent-expr op-num))
;; FIXME: Shouldn't this push VAL onto ENV?
(cons val env)
)
(define (/rtx-canon-attrs val mode parent-expr op-num cstate env depth)
; (cons val ; (atlist-source-form (atlist-parse (make-prefix-cstate "with-attr") val ""))
; env)
#f
)
(define (/rtx-canon-symbol val mode parent-expr op-num cstate env depth)
(if (not (symbol? val))
(/rtx-canon-error cstate "expecting a symbol"
val parent-expr op-num))
#f
)
(define (/rtx-canon-string val mode parent-expr op-num cstate env depth)
(if (not (string? val))
(/rtx-canon-error cstate "expecting a string"
val parent-expr op-num))
#f
)
(define (/rtx-canon-number val mode parent-expr op-num cstate env depth)
(if (not (number? val))
(/rtx-canon-error cstate "expecting a number"
val parent-expr op-num))
#f
)
(define (/rtx-canon-symornum val mode parent-expr op-num cstate env depth)
(if (not (or (symbol? val) (number? val)))
(/rtx-canon-error cstate "expecting a symbol or number"
val parent-expr op-num))
#f
)
(define (/rtx-canon-object val mode parent-expr op-num cstate env depth)
#f
)
;; Table of rtx canonicalizers.
;; This is a vector of size rtx-max-num.
;; Each entry is a list of (arg-type-name . canonicalizer) elements
;; for rtx-arg-types.
;; FIXME: Initialized in rtl.scm (i.e. outside this file).
(define /rtx-canoner-table #f)
;; Return a hash table of standard operand canonicalizers.
;; The result of each canonicalizer is a pair of the canonical form
;; of `val' and a possibly new environment or #f if there is no change.
(define (/rtx-make-canon-table)
(let ((hash-tab (make-hash-table 31))
(canoners
(list
(cons 'OPTIONS /rtx-canon-options)
(cons 'ANYINTMODE /rtx-canon-anyintmode)
(cons 'ANYFLOATMODE /rtx-canon-anyfloatmode)
(cons 'ANYNUMMODE /rtx-canon-anynummode)
(cons 'ANYEXPRMODE /rtx-canon-anyexprmode)
(cons 'ANYCEXPRMODE /rtx-canon-anycexprmode)
(cons 'EXPLNUMMODE /rtx-canon-explnummode)
(cons 'VOIDORNUMMODE /rtx-canon-voidornummode)
(cons 'VOIDMODE /rtx-canon-voidmode)
(cons 'BIMODE /rtx-canon-bimode)
(cons 'INTMODE /rtx-canon-intmode)
(cons 'SYMMODE /rtx-canon-symmode)
(cons 'INSNMODE /rtx-canon-insnmode)
(cons 'MACHMODE /rtx-canon-machmode)
(cons 'RTX /rtx-canon-rtx)
(cons 'SETRTX /rtx-canon-setrtx)
(cons 'TESTRTX /rtx-canon-testrtx)
(cons 'CONDRTX /rtx-canon-condrtx)
(cons 'CASERTX /rtx-canon-casertx)
(cons 'LOCALS /rtx-canon-locals)
(cons 'ITERATION /rtx-canon-iteration)
(cons 'SYMBOLLIST /rtx-canon-symbol-list)
(cons 'ENVSTACK /rtx-canon-env-stack)
(cons 'ATTRS /rtx-canon-attrs)
(cons 'SYMBOL /rtx-canon-symbol)
(cons 'STRING /rtx-canon-string)
(cons 'NUMBER /rtx-canon-number)
(cons 'SYMORNUM /rtx-canon-symornum)
(cons 'OBJECT /rtx-canon-object)
)))
(for-each (lambda (canoner)
(hashq-set! hash-tab (car canoner) (cdr canoner)))
canoners)
hash-tab)
)
;; Standard expression operand canonicalizer.
;; Loop over the operands, verifying them according to the argument type
;; and mode matcher, and replace DFLT with a usable mode.
(define (/rtx-canon-operands rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
;; ??? Might want to just leave operands as a list.
(let* ((operands (list->vector args))
(nr-operands (vector-length operands))
(this-expr (cons func args)) ;; For error messages.
(expr-mode
;; For sets, the requested mode is DFLT or VOID (the mode of the
;; result), but the mode we want is the mode of the set destination.
(if (rtx-result-mode rtx-obj)
(cadr args) ;; mode of arg2 doesn't come from containing expr
(/rtx-pick-mode cstate requested-mode-name (cadr args))))
(all-arg-types (vector-ref /rtx-canoner-table (rtx-num rtx-obj))))
(if (not expr-mode)
(/rtx-canon-error cstate
(string-append "requested mode "
(symbol->string requested-mode-name)
" is incompatible with expression mode "
(symbol->string (cadr args)))
this-expr parent-expr #f))
(if /rtx-canon-debug?
(begin
(display (spaces (* 4 depth)))
(display "expr-mode ")
(display expr-mode)
(newline)
(force-output)))
(let loop ((env env)
(op-num 0)
(arg-types all-arg-types)
(arg-modes (rtx-arg-modes rtx-obj)))
(let ((varargs? (and (pair? arg-types) (symbol? (car arg-types)))))
(if /rtx-canon-debug?
(begin
(display (spaces (* 4 depth)))
(if (= op-num nr-operands)
(display "end of operands")
(begin
(display "op-num ") (display op-num) (display ": ")
(display (rtx-dump (vector-ref operands op-num)))
(display ", ")
(display (if varargs? (car arg-types) (caar arg-types)))
(display ", ")
(display (if varargs? arg-modes (car arg-modes)))
))
(newline)
(force-output)))
(cond ((= op-num nr-operands)
;; Out of operands, check if we have the expected number.
(if (or (null? arg-types)
varargs?)
;; We're theoretically done.
(let ((set-mode-from-arg!
(lambda (arg-num)
(if /rtx-canon-debug?
(begin
(display (spaces (* 4 depth)))
(display "Computing expr mode from arguments.")
(newline)))
(let* ((expr-to-match
(case func
((cond case)
(/rtx-get-last-cond-case-rtx (vector-ref operands arg-num)))
(else
(vector-ref operands arg-num))))
(expr-to-match-obj (rtx-lookup (rtx-name expr-to-match)))
(new-expr-mode (or (rtx-result-mode expr-to-match-obj)
(let ((expr-mode (rtx-mode expr-to-match)))
(if (eq? expr-mode 'DFLT)
(if (eq? requested-mode-name 'DFLT)
(/rtx-canon-error cstate
"unable to determine mode of expression from arguments, please specify a mode"
this-expr parent-expr #f)
requested-mode-name)
expr-mode)))))
;; Verify the mode to be recorded matches the spec.
(let* ((expr-mode-spec (cadr all-arg-types))
(canoner (cdr expr-mode-spec)))
;; Ignore the result of the canoner, we just
;; want the error checking.
(canoner new-expr-mode #f this-expr 1
cstate env depth))
(vector-set! operands 1 new-expr-mode)))))
;; The expression's mode might still be DFLT.
;; If it is, fetch the mode of the MATCHEXPR operand,
;; or MATCHSEQ operand, or containing expression.
;; If it's still DFLT, flag an error.
(if (eq? (vector-ref operands 1) 'DFLT)
(cond ((rtx-matchexpr-index rtx-obj)
=> (lambda (matchexpr-index)
(set-mode-from-arg! matchexpr-index)))
((eq? func 'sequence)
(set-mode-from-arg! (- nr-operands 1)))
(else
(if /rtx-canon-debug?
(begin
(display (spaces (* 4 depth)))
(display "Computing expr mode from containing expression.")
(newline)))
(if (or (eq? requested-mode-name 'DFLT)
(rtx-result-mode rtx-obj))
(/rtx-canon-error cstate
"unable to determine mode of expression, please specify a mode"
this-expr parent-expr #f)
(vector-set! operands 1 requested-mode-name)))))
(vector->list operands))
(/rtx-canon-error cstate "missing operands"
this-expr parent-expr #f)))
((null? arg-types)
(/rtx-canon-error cstate "too many operands"
this-expr parent-expr #f))
(else
(let ((type (if varargs? arg-types (car arg-types)))
(mode (let ((mode-spec (if varargs?
arg-modes
(car arg-modes))))
;; We don't necessarily have enough information
;; at this point. Just propagate what we do know,
;; and leave it for final processing to fix up what
;; we missed.
;; This is small enough that case is fast enough,
;; and the number of entries should be stable.
(case mode-spec
((ANY) 'DFLT)
((ANYINT) 'DFLT) ;; FIXME
((NA) #f)
((MATCHEXPR) expr-mode)
((MATCHSEQ)
(if (= (+ op-num 1) nr-operands) ;; last one?
expr-mode
'VOID))
((MATCH2)
;; This is complicated by the fact that some
;; rtx have a different result mode than what
;; is specified in the rtl (e.g. set, eq).
;; ??? Make these rtx specify both modes?
(let* ((op2 (vector-ref operands 2))
(op2-obj (rtx-lookup (rtx-name op2))))
(or (rtx-result-mode op2-obj)
(rtx-mode op2))))
((MATCH3)
;; This is complicated by the fact that some
;; rtx have a different result mode than what
;; is specified in the rtl (e.g. set, eq).
;; ??? Make these rtx specify both modes?
(let* ((op2 (vector-ref operands 3))
(op2-obj (rtx-lookup (rtx-name op2))))
(or (rtx-result-mode op2-obj)
(rtx-mode op2))))
;; Otherwise mode-spec is the mode to use.
(else mode-spec))))
(val (vector-ref operands op-num))
)
;; Look up the canoner for this operand and perform it.
;; FIXME: This would benefit from returning multiple values.
(let ((canoner (cdr type)))
(let ((canon-val (canoner val mode this-expr op-num
cstate env depth)))
(if canon-val
(begin
(set! val (car canon-val))
(set! env (cdr canon-val))))))
(vector-set! operands op-num val)
;; Done with this operand, proceed to the next.
(loop env
(+ op-num 1)
(if varargs? arg-types (cdr arg-types))
(if varargs? arg-modes (cdr arg-modes)))))))))
)
(define (/rtx-canon-rtx-enum rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(if (!= (length args) 3)
(/rtx-canon-error cstate "wrong number of operands to enum, expecting 3"
(cons func args) parent-expr #f))
(let ((mode-name (cadr args))
(enum-name (caddr args)))
(let ((mode-obj (mode:lookup mode-name))
(enum-val-and-obj (enum-lookup-val enum-name)))
(if (not enum-val-and-obj)
(/rtx-canon-error cstate "unknown enum value"
enum-name parent-expr #f))
(let ((expr-mode-or-errmsg (/rtx-pick-mode3 requested-mode-name mode-name INT)))
(if (symbol? expr-mode-or-errmsg)
(list (car args) expr-mode-or-errmsg enum-name)
(/rtx-canon-error cstate expr-mode-or-errmsg
enum-name parent-expr #f)))))
)
(define (/rtx-canon-rtx-ifield rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(if (!= (length args) 3)
(/rtx-canon-error cstate "wrong number of operands to ifield, expecting 3"
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(ifld-name (caddr args)))
(let ((ifld-obj (current-ifld-lookup ifld-name)))
(if ifld-obj
(let ((mode-or-errmsg (/rtx-pick-mode3 requested-mode-name
expr-mode-name
(ifld-mode ifld-obj))))
(if (symbol? mode-or-errmsg)
(list (car args) mode-or-errmsg ifld-name)
(/rtx-canon-error cstate mode-or-errmsg expr-mode-name
parent-expr parent-op-num)))
(/rtx-canon-error cstate "unknown ifield"
ifld-name parent-expr #f))))
)
(define (/rtx-canon-rtx-operand rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(if (!= (length args) 3)
(/rtx-canon-error cstate "wrong number of operands to operand, expecting 3"
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(op-name (caddr args)))
(let ((op-obj (current-op-lookup op-name (/cstate-isas cstate))))
(if op-obj
(let ((mode (/rtx-pick-op-mode cstate requested-mode-name
expr-mode-name op-obj parent-expr)))
(list (car args) mode op-name))
(/rtx-canon-error cstate "unknown operand"
op-name parent-expr #f))))
)
(define (/rtx-canon-rtx-xop rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(if (!= (length args) 3)
(/rtx-canon-error cstate "wrong number of operands to xop, expecting 3"
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(xop-obj (caddr args)))
(if (operand? xop-obj)
(let ((mode-or-errmsg (/rtx-pick-mode3 requested-mode-name
expr-mode-name
(op:mode xop-obj))))
(if (symbol? mode-or-errmsg)
(list (car args) mode-or-errmsg xop-obj)
(/rtx-canon-error cstate mode-or-errmsg expr-mode-name
parent-expr parent-op-num)))
(/rtx-canon-error cstate "xop operand #2 not an operand"
(obj:name xop-obj) parent-expr #f)))
)
(define (/rtx-canon-rtx-local rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(if (!= (length args) 3)
(/rtx-canon-error cstate "wrong number of operands to local, expecting 3"
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(local-name (caddr args)))
(let ((local-obj (rtx-temp-lookup env local-name)))
(if local-obj
(let ((mode-or-errmsg (/rtx-pick-mode3 requested-mode-name
expr-mode-name
(rtx-temp-mode local-obj))))
(if (symbol? mode-or-errmsg)
(list (car args) mode-or-errmsg local-name)
(/rtx-canon-error cstate mode-or-errmsg expr-mode-name
parent-expr parent-op-num)))
(/rtx-canon-error cstate "unknown local"
local-name parent-expr #f))))
)
(define (/rtx-canon-rtx-ref rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(if (!= (length args) 3)
(/rtx-canon-error cstate "wrong number of operands to ref, expecting 3"
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(ref-name (caddr args)))
;; FIXME: Will current-op-lookup find named operands?
(let ((op-obj (current-op-lookup ref-name (/cstate-isas cstate))))
(if op-obj
;; The result of "ref" is canonically an INT.
(let ((mode-or-errmsg (/rtx-pick-mode3 requested-mode-name
expr-mode-name
INT)))
(if (symbol? mode-or-errmsg)
(list (car args) mode-or-errmsg ref-name)
(/rtx-canon-error cstate mode-or-errmsg expr-mode-name
parent-expr parent-op-num)))
(/rtx-canon-error cstate "unknown operand"
ref-name parent-expr #f))))
)
(define (/rtx-canon-rtx-reg rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(let ((len (length args)))
(if (or (< len 3) (> len 5))
(/rtx-canon-error cstate
;; TODO: be more firm on expected number of args
(string-append
"wrong number of operands to "
(symbol->string func)
", expecting 3 (or possibly 4,5)")
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(hw-name (caddr args))
(this-expr (cons func args)))
(let* ((hw (/rtx-lookup-hw cstate hw-name parent-expr
(lambda (hw)
(if (not (register? hw))
(/rtx-canon-error cstate "not a register" hw-name
parent-expr parent-op-num))
*UNSPECIFIED*)))
(hw-mode-obj (hw-mode hw)))
(let ((mode-or-errmsg (/rtx-pick-mode3 requested-mode-name
expr-mode-name
hw-mode-obj)))
(if (symbol? mode-or-errmsg)
;; Canonicalizing optional index/selector.
(let ((index (if (>= len 4)
(let ((canon (/rtx-canon-rtx
(list-ref args 3) 'INT
this-expr 3 cstate env depth)))
(car canon)) ;; discard env
#f))
(sel (if (= len 5)
(let ((canon (/rtx-canon-rtx
(list-ref args 4) 'INT
this-expr 4 cstate env depth)))
(car canon)) ;; discard env
#f)))
(if sel
(begin
(assert index)
(list (car args) mode-or-errmsg hw-name index sel))
(if index
(list (car args) mode-or-errmsg hw-name index)
(list (car args) mode-or-errmsg hw-name))))
(/rtx-canon-error cstate mode-or-errmsg expr-mode-name
parent-expr parent-op-num))))))
)
(define (/rtx-canon-rtx-mem rtx-obj requested-mode-name
func args parent-expr parent-op-num
cstate env depth)
(let ((len (length args)))
(if (or (< len 3) (> len 4))
(/rtx-canon-error cstate
"wrong number of operands to mem, expecting 3 (or possibly 4)"
(cons func args) parent-expr #f))
(let ((expr-mode-name (cadr args))
(addr-expr (caddr args))
(this-expr (cons func args)))