OSDN Git Service

remove unnecessary comment in generated code
[pf3gnuchains/pf3gnuchains4x.git] / cgen / utils-cgen.scm
1 ; CGEN Utilities.
2 ; Copyright (C) 2000, 2002, 2003, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
5 ;
6 ; This file contains utilities specific to cgen.
7 ; Generic utilities should go in utils.scm.
8
9 ; True if text of sanitize markers are to be emitted.
10 ; This is a debugging tool only, though it could have use in sanitized trees.
11 (define include-sanitize-marker? #t)
12
13 ; Utility to display command line invocation for debugging purposes.
14
15 (define (display-argv argv)
16   (let ((cep (current-error-port)))
17     (display "cgen -s " cep)
18     (for-each (lambda (arg)
19                 ; Output double-quotes if string has a space for better
20                 ; correspondence to how to specify string to shell.
21                 (if (string-index arg #\space)
22                     (write arg cep)
23                     (display arg cep))
24                 (display " " cep))
25               argv)
26     (newline cep))
27 )
28 \f
29 ; COS utilities.
30 ; Perhaps these should be provided with cos (cgen-object-system), but for
31 ; now they live here.
32
33 ; Define the getter for a list of elements of a class.
34
35 (defmacro define-getters (class class-prefix elm-names)
36   (cons 'begin
37         (map (lambda (elm-name)
38                (if (pair? elm-name)
39                    `(define ,(symbol-append class-prefix '- (cdr elm-name))
40                       (elm-make-getter ,class (quote ,(car elm-name))))
41                    `(define ,(symbol-append class-prefix '- elm-name)
42                       (elm-make-getter ,class (quote ,elm-name)))))
43              elm-names))
44 )
45
46 ; Define the setter for a list of elements of a class.
47
48 (defmacro define-setters (class class-prefix elm-names)
49   (cons 'begin
50         (map (lambda (elm-name)
51                (if (pair? elm-name)
52                    `(define ,(symbol-append class-prefix '-set- (cdr elm-name) '!)
53                       (elm-make-setter ,class (quote ,(car elm-name))))
54                    `(define ,(symbol-append class-prefix '-set- elm-name '!)
55                       (elm-make-setter ,class (quote ,elm-name)))))
56              elm-names))
57 )
58
59 ; Make an object, specifying values for particular elements.
60 ; ??? Eventually move to cos.scm/cos.c.
61
62 (define (vmake class . args)
63   (let ((obj (new class)))
64     (let ((unrecognized (send obj 'vmake! args)))
65       (if (null? unrecognized)
66           obj
67           (error "vmake: unknown options:" unrecognized))))
68 )
69 \f
70 ;;; Source locations are recorded as a stack, with (ideally) one extra level
71 ;;; for each macro invocation.
72
73 (define <location> (class-make '<location>
74                                nil
75                                '(
76                                  ;; A list of "single-location" objects,
77                                  ;; sorted by most recent location first.
78                                  list
79                                  )
80                                nil))
81
82 (define-getters <location> location (list))
83 (define-setters <location> location (list))
84
85 ;;; A single source location.
86 ;;; This is recorded as a vector for simplicity.
87 ;;; END? is true if the location marks the end of the expression.
88 ;;; NOTE: LINE and COLUMN are origin-0 (the first line is line 0).
89
90 (define (make-single-location file line column end?)
91   (vector file line column end?)
92 )
93
94 (define (single-location-file sloc) (vector-ref sloc 0))
95 (define (single-location-line sloc) (vector-ref sloc 1))
96 (define (single-location-column sloc) (vector-ref sloc 2))
97 (define (single-location-end? sloc) (vector-ref sloc 3))
98
99 ;;; Return a single-location in a readable form.
100
101 (define (single-location->string sloc)
102   ;; +1: numbers are recorded origin-0
103   (string-append (single-location-file sloc)
104                  ":"
105                  (number->string (+ (single-location-line sloc) 1))
106                  ":"
107                  (number->string (+ (single-location-column sloc) 1))
108                  (if (single-location-end? sloc) "(end)" ""))
109 )
110
111 ;;; Same as single-location->string, except omit any directory info in
112 ;;; the file name.
113
114 (define (single-location->simple-string sloc)
115   ;; +1: numbers are recorded origin-0
116   (string-append (basename (single-location-file sloc))
117                  ":"
118                  (number->string (+ (single-location-line sloc) 1))
119                  ":"
120                  (number->string (+ (single-location-column sloc) 1))
121                  (if (single-location-end? sloc) "(end)" ""))
122 )
123
124 ;;; Return a location in a readable form.
125
126 (define (location->string loc)
127   (let ((ref-from " referenced from:"))
128     (string-drop
129      (- 0 (string-length ref-from) 1)
130      (string-drop1
131       (apply string-append
132              (map (lambda (sloc)
133                     (string-append "\n"
134                                    (single-location->string sloc)
135                                    ":"
136                                    ref-from))
137                   (location-list loc))))))
138 )
139
140 ;;; Return the location information in Guile's source-properties
141 ;;; in a readable form.
142
143 (define (source-properties-location->string src-props)
144   (let ((file (assq-ref src-props 'filename))
145         (line (assq-ref src-props 'line))
146         (column (assq-ref src-props 'column)))
147     (string-append file
148                    ":"
149                    (number->string (+ line 1))
150                    ":"
151                    (number->string (+ column 1))))
152 )
153
154 ;;; Return the top location on LOC's stack.
155
156 (define (location-top loc)
157   (car (location-list loc))
158 )
159
160 ;;; Return a new <location> with FILE, LINE pushed onto the stack.
161
162 (define (location-push-single loc file line column end?)
163   (make <location> (cons (make-single-location file line column end?)
164                          (location-list loc)))
165 )
166
167 ;;; Return a new <location> with NEW-LOC preappended to LOC.
168
169 (define (location-push loc new-loc)
170   (make <location> (append (location-list new-loc)
171                            (location-list loc)))
172 )
173
174 ;;; Return an unspecified <location>.
175 ;;; This is mainly for use in debugging utilities.
176 ;;; Ideally for .cpu-file related stuff we always have a location,
177 ;;; but that's not always true.
178
179 (define (unspecified-location)
180   (make <location> (list (make-single-location "unspecified" 0 0 #f)))
181 )
182
183 ;;; Return a location denoting a builtin object.
184
185 (define (builtin-location)
186   (make <location> (list (make-single-location "builtin" 0 0 #f)))
187 )
188
189 ;;; Return a <location> object for the current input port.
190 ;;; END? is true if the location marks the end of the expression.
191
192 (define (current-input-location end?)
193   (let ((cip (current-input-port)))
194     (make <location> (list (make-single-location (port-filename cip)
195                                                  (port-line cip)
196                                                  (port-column cip)
197                                                  end?))))
198 )
199
200 ;;; An object property for tracking source locations during macro expansion.
201
202 (define location-property (make-object-property))
203
204 ;;; Set FORM's location to LOC.
205
206 (define (location-property-set! form loc)
207   (set! (location-property form) loc)
208   *UNSPECIFIED*
209 )
210 \f
211 ; Each named entry in the description file typically has these three members:
212 ; name, comment attrs.
213
214 (define <ident> (class-make '<ident> '() '(name comment attrs) '()))
215
216 (method-make! <ident> 'get-name (lambda (self) (elm-get self 'name)))
217 (method-make! <ident> 'get-comment (lambda (self) (elm-get self 'comment)))
218 (method-make! <ident> 'get-atlist (lambda (self) (elm-get self 'attrs)))
219
220 (method-make! <ident> 'set-name!
221               (lambda (self newval) (elm-set! self 'name newval)))
222 (method-make! <ident> 'set-comment!
223               (lambda (self newval) (elm-set! self 'comment newval)))
224 (method-make! <ident> 'set-atlist!
225               (lambda (self newval) (elm-set! self 'attrs newval)))
226
227 ; All objects defined in the .cpu file have these elements.
228 ; Where in the class hierarchy they're recorded depends on the object.
229 ; Additionally most objects have `name', `comment' and `attrs' elements.
230
231 (define (obj:name obj) (send obj 'get-name))
232 (define (obj-set-name! obj name) (send obj 'set-name! name))
233 (define (obj:comment obj) (send obj 'get-comment))
234
235 ; Utility to return the name as a string.
236
237 (define (obj:str-name obj) (symbol->string (obj:name obj)))
238
239 ;; Given a list of named objects, return a string of comma-separated names.
240
241 (define (obj-csv-names obj-list)
242   (string-drop1
243    (string-map (lambda (o)
244                  (string-append ","
245                                 (obj:str-name o)))
246                obj-list))
247 )
248
249 ; Subclass of <ident> for use by description file objects.
250 ;
251 ; Records the source location of the object.
252 ;
253 ; We also record an internally generated entry, ordinal, to record the
254 ; relative position within the description file.  It's generally more efficient
255 ; to record some kinds of objects (e.g. insns) in a hash table.  But we also
256 ; want to emit these objects in file order.  Recording the object's relative
257 ; position lets us generate an ordered list when we need to.
258 ; We can't just use the line number because we want an ordering over multiple
259 ; input files.
260
261 (define <source-ident>
262   (class-make '<source-ident> '(<ident>)
263               '(
264                 ;; A <location> object.
265                 (location . #f)
266                 ;; #f for ordinal means "unassigned"
267                 (ordinal . #f)
268                 )
269               '()))
270
271 (method-make! <source-ident> 'get-location
272               (lambda (self) (elm-get self 'location)))
273 (method-make! <source-ident> 'set-location!
274               (lambda (self newval) (elm-set! self 'location newval)))
275 (define (obj-location obj) (send obj 'get-location))
276 (define (obj-set-location! obj location) (send obj 'set-location! location))
277
278 (method-make! <source-ident> 'get-ordinal
279               (lambda (self) (elm-get self 'ordinal)))
280 (method-make! <source-ident> 'set-ordinal!
281               (lambda (self newval) (elm-set! self 'ordinal newval)))
282 (define (obj-ordinal obj) (send obj 'get-ordinal))
283 (define (obj-set-ordinal! obj ordinal) (send obj 'set-ordinal! ordinal))
284
285 ; Return a boolean indicating if X is a <source-ident>.
286
287 (define (source-ident? x) (class-instance? <source-ident> x))
288 \f
289 ; Parsing utilities
290
291 ;;; A parsing/processing context, used to give better error messages.
292 ;;; LOCATION must be an object created with make-location.
293
294 (define <context>
295   (class-make '<context> nil
296               '(
297                 ;; Location of the object being processed,
298                 ;; or #f if unknown (or there is none).
299                 (location . #f)
300                 ;; Error message prefix or #f if there is none.
301                 (prefix . #f)
302                 )
303               nil)
304 )
305
306 ; Accessors.
307
308 (define-getters <context> context (location prefix))
309
310 ; Create a <context> object that is just a prefix.
311
312 (define (make-prefix-context prefix)
313   (make <context> #f prefix)
314 )
315
316 ; Create a <context> object that (current-reader-location) with PREFIX.
317
318 (define (make-current-context prefix)
319   (make <context> (current-reader-location) prefix)
320 )
321
322 ; Create a <context> object from <source-ident> object OBJ.
323
324 (define (make-obj-context obj prefix)
325   (make <context> (obj-location obj) prefix)
326 )
327
328 ; Create a new context from CONTEXT with TEXT appended to the prefix.
329
330 (define (context-append context text)
331   (make <context> (context-location context)
332         (string-append (context-prefix context) text))
333 )
334
335 ; Create a new context from CONTEXT with NAME appended to the prefix.
336
337 (define (context-append-name context name)
338   (context-append context (stringsym-append ":" name))
339 )
340
341 ; Call this to issue an error message when all you have is a context.
342 ; CONTEXT is a <context> object or #f if there is none.
343 ; INTRO is a general introduction to what cgen was doing.
344 ; ERRMSG is, yes, you guessed it, the error message.
345 ; EXPR is the value that had the error if there is one.
346
347 (define (context-error context intro errmsg . expr)
348   (apply context-owner-error
349          (cons context
350                (cons #f
351                      (cons intro
352                            (cons errmsg expr)))))
353 )
354
355 ; Call this to issue an error message when you have a context and an
356 ; <ident> or <source-ident> object (we call the "owner").
357 ; CONTEXT is a <context> object or #f if there is none.
358 ; OWNER is an <ident> or <source-ident> object or #f if there is none.
359 ; INTRO is a general introduction to what cgen was doing.
360 ;   If OWNER is non-#f, the text " of <object-name>" is appended.
361 ; ERRMSG is, yes, you guessed it, the error message.
362 ; EXPR is the value that had the error if there is one.
363
364 (define (context-owner-error context owner intro errmsg . expr)
365   ;; If we don't have a context, look at the owner to try to find one.
366   ;; We want to include the source location in the error if we can.
367   (if (and (not context)
368            owner
369            (source-ident? owner))
370       (set! context (make-obj-context owner #f)))
371   (if (not context)
372       (set! context (make-prefix-context #f)))
373
374   (let* ((loc (context-location context))
375          (top-sloc (and loc (location-top loc)))
376          (intro (string-append intro
377                                (if owner
378                                    (string-append " of "
379                                                   (obj:str-name owner))
380                                    "")))
381          (prefix (or (context-prefix context) "Error"))
382          (text (string-append prefix ": " errmsg)))
383
384     (if loc
385
386         (apply error
387                (cons
388                 (simple-format
389                  #f
390                  "\n~A:\n@ ~A:\n\n~A: ~A:"
391                  intro
392                  (location->string loc)
393                  (single-location->simple-string top-sloc)
394                  text)
395                 expr))
396
397         (apply error
398                (cons
399                 (simple-format
400                  #f
401                  "\n~A:\n~A:"
402                  intro
403                  text)
404                 expr))))
405 )
406
407 ; Parse an object name.
408 ; NAME is either a symbol or a list of symbols which are concatenated
409 ; together.  Each element can in turn be a list of symbols, and so on.
410 ; This supports symbol concatenation in the description file without having
411 ; to using string-append or some such.
412
413 (define (parse-name context name)
414   (string->symbol
415    (let parse ((name name))
416      (cond
417       ((symbol? name) (symbol->string name))
418       ((string? name) name)
419       ((number? name) (number->string name))
420       ((list? name) (string-map parse name))
421       (else (parse-error context "improper name" name)))))
422 )
423
424 ; Parse an object comment.
425 ; COMMENT is either a string or a list of strings, each element of which may
426 ; in turn be a list of strings.
427
428 (define (parse-comment context comment)
429   (cond ((string? comment) comment)
430         ((symbol? comment) (symbol->string comment))
431         ((number? comment) (number->string comment))
432         ((list? comment)
433          (string-map (lambda (elm) (parse-comment context elm)) comment))
434         (else (parse-error context "improper comment" comment)))
435 )
436
437 ; Parse a symbol.
438
439 (define (parse-symbol context value)
440   (if (and (not (symbol? value)) (not (string? value)))
441       (parse-error context "not a symbol or string" value))
442   (->symbol value)
443 )
444
445 ; Parse a string.
446
447 (define (parse-string context value)
448   (if (and (not (symbol? value)) (not (string? value)))
449       (parse-error context "not a string or symbol" value))
450   (->string value)
451 )
452
453 ; Parse a number.
454 ; VALID-VALUES is a list of numbers and (min . max) pairs.
455
456 (define (parse-number context value . valid-values)
457   (if (not (number? value))
458       (parse-error context "not a number" value))
459   (if (any-true? (map (lambda (test)
460                         (if (pair? test)
461                             (and (>= value (car test))
462                                  (<= value (cdr test)))
463                             (= value test)))
464                       valid-values))
465       value
466       (parse-error context "invalid number" value valid-values))
467 )
468
469 ; Parse a boolean value
470
471 (define (parse-boolean context value)
472   (if (boolean? value)
473       value
474       (parse-error context "not a boolean (#f/#t)" value))
475 )
476
477 ; Parse a list of handlers.
478 ; Each entry is (symbol "string").
479 ; These map function to a handler for it.
480 ; The meaning is up to the application but generally the handler is a
481 ; C/C++ function name.
482 ; ALLOWED is a list valid values for the symbol or #f if anything is allowed.
483 ; The result is handlers unchanged.
484
485 (define (parse-handlers context allowed handlers)
486   (if (not (list? handlers))
487       (parse-error context "bad handler spec" handlers))
488   (for-each (lambda (arg)
489               (if (not (list-elements-ok? arg (list symbol? string?)))
490                   (parse-error context "bad handler spec" arg))
491               (if (and allowed (not (memq (car arg) allowed)))
492                   (parse-error context "unknown handler type" (car arg))))
493             handlers)
494   handlers
495 )
496
497 ; Return a boolean indicating if X is a keyword.
498 ; This also handles symbols named :foo because Guile doesn't stablely support
499 ; :keywords (how does one enable :keywords? read-options doesn't appear to
500 ; work).
501
502 (define (keyword-list? x)
503   (and (list? x)
504        (not (null? x))
505        (or (keyword? (car x))
506            (and (symbol? (car x))
507                 (char=? (string-ref (symbol->string (car x)) 0) #\:))))
508 )
509
510 ; Convert a list like (#:key1 val1 #:key2 val2 ...) to
511 ; ((#:key1 val1) (#:key2 val2) ...).
512 ; Missing values are specified with an empty list.
513 ; This also supports (:sym1 val1 ...) because Guile doesn't stablely support
514 ; :keywords (#:keywords work, but #:foo shouldn't appear in the description
515 ; language).
516
517 (define (keyword-list->arg-list kl)
518   ; Scan KL backwards, building up each element as we go.
519   (let loop ((result nil) (current nil) (rkl (reverse kl)))
520     (cond ((null? rkl)
521            result)
522           ((keyword? (car rkl))
523            (loop (acons (keyword->symbol (car rkl)) current result)
524                  nil
525                  (cdr rkl)))
526           ((and (symbol? (car rkl))
527                 (char=? (string-ref (symbol->string (car rkl)) 0) #\:))
528            (loop (acons (string->symbol
529                          (substring (car rkl) 1 (string-length (car rkl))))
530                         current result)
531                  nil
532                  (cdr rkl)))
533           (else
534            (loop result
535                  (cons (car rkl) current)
536                  (cdr rkl)))))
537 )
538
539 ; Signal an error if the argument name is not a symbol.
540 ; This is done by each of the argument validation routines so the caller
541 ; doesn't need to make two calls.
542
543 (define (arg-list-validate-name context arg-spec)
544   (if (null? arg-spec)
545       (parse-error context "empty argument spec" arg-spec))
546   (if (not (symbol? (car arg-spec)))
547       (parse-error context "argument name not a symbol" arg-spec))
548   *UNSPECIFIED*
549 )
550
551 ; Signal a parse error if an argument was specified with a value.
552 ; ARG-SPEC is (name value).
553
554 (define (arg-list-check-no-args context arg-spec)
555   (arg-list-validate-name context arg-spec)
556   (if (not (null? (cdr arg-spec)))
557       (parse-error context (string-append (car arg-spec)
558                                           " takes zero arguments")))
559   *UNSPECIFIED*
560 )
561
562 ; Validate and return a symbol argument.
563 ; ARG-SPEC is (name value).
564
565 (define (arg-list-symbol-arg context arg-spec)
566   (arg-list-validate-name context arg-spec)
567   (if (or (!= (length (cdr arg-spec)) 1)
568           (not (symbol? (cadr arg-spec))))
569       (parse-error context (string-append (car arg-spec)
570                                           ": argument not a symbol")))
571   (cadr arg-spec)
572 )
573 \f
574 ; Sanitization
575
576 ; Sanitization is handled via attributes.  Anything that must be sanitized
577 ; has a `sanitize' attribute with the value being the keyword to sanitize on.
578 ; Ideally most, if not all, of the guts of the generated sanitization is here.
579
580 ; Utility to simplify expression in .cpu file.
581 ; Usage: (sanitize isa-name-list keyword entry-type entry-name1 [entry-name2 ...])
582 ; Enum attribute `(sanitize keyword)' is added to the entry.
583
584 (define (sanitize isa-name-list keyword entry-type . entry-names)
585   (for-each (lambda (entry-name)
586               (let ((entry #f))
587                 (case entry-type
588                   ((attr) (set! entry (current-attr-lookup entry-name)))
589                   ((enum) (set! entry (current-enum-lookup entry-name)))
590                   ((isa) (set! entry (current-isa-lookup entry-name)))
591                   ((cpu) (set! entry (current-cpu-lookup entry-name)))
592                   ((mach) (set! entry (current-mach-lookup entry-name)))
593                   ((model) (set! entry (current-model-lookup entry-name)))
594                   ((ifield) (set! entry (current-ifld-lookup entry-name isa-name-list)))
595                   ((hardware) (set! entry (current-hw-lookup entry-name)))
596                   ((operand) (set! entry (current-op-lookup entry-name isa-name-list)))
597                   ((insn) (set! entry (current-insn-lookup entry-name isa-name-list)))
598                   ((macro-insn) (set! entry (current-minsn-lookup entry-name isa-name-list)))
599                   (else (parse-error (make-prefix-context "sanitize")
600                                      "unknown entry type" entry-type)))
601
602                 ; ENTRY is #f in the case where the element was discarded
603                 ; because its mach wasn't selected.  But in the case where
604                 ; we're keeping everything, ensure ENTRY is not #f to
605                 ; catch spelling errors.
606
607                 (if entry
608
609                     (begin
610                       (obj-cons-attr! entry (enum-attr-make 'sanitize keyword))
611                       ; Propagate the sanitize attribute to class members
612                       ; as necessary.
613                       (case entry-type
614                         ((hardware)
615                          (if (hw-indices entry)
616                              (obj-cons-attr! (hw-indices entry)
617                                              (enum-attr-make 'sanitize
618                                                              keyword)))
619                          (if (hw-values entry)
620                              (obj-cons-attr! (hw-values entry)
621                                              (enum-attr-make 'sanitize
622                                                              keyword))))
623                         ))
624
625                     (if (and (eq? APPLICATION 'OPCODES) (keep-all?))
626                         (parse-error (make-prefix-context "sanitize")
627                                      (string-append "unknown " entry-type)
628                                      entry-name)))))
629             entry-names)
630
631   #f ; caller eval's our result, so return a no-op
632 )
633
634 ; Return TEXT sanitized with KEYWORD.
635 ; TEXT must exist on a line (or lines) by itself.
636 ; i.e. it is assumed that it begins at column 1 and ends with a newline.
637 ; If KEYWORD is #f, no sanitization is generated.
638
639 (define (gen-sanitize keyword text)
640   (cond ((null? text) "")
641         ((pair? text) ; pair? -> cheap list?
642          (if (and keyword include-sanitize-marker?)
643              (string-list
644               ; split string to avoid removal
645               "/* start-"
646               "sanitize-" keyword " */\n"
647               text
648               "/* end-"
649               "sanitize-" keyword " */\n")
650              text))
651         (else
652          (if (= (string-length text) 0)
653              ""
654              (if (and keyword include-sanitize-marker?)
655                  (string-append
656                   ; split string to avoid removal
657                   "/* start-"
658                   "sanitize-" keyword " */\n"
659                   text
660                   "/* end-"
661                   "sanitize-" keyword " */\n")
662                  text))))
663 )
664
665 ; Return TEXT sanitized with OBJ's sanitization, if it has any.
666 ; OBJ may be #f.
667
668 (define (gen-obj-sanitize obj text)
669   (if obj
670       (let ((san (obj-attr-value obj 'sanitize)))
671         (gen-sanitize (if (or (not san) (eq? san 'none)) #f san)
672                       text))
673       (gen-sanitize #f text))
674 )
675 \f
676 ; Cover procs to handle generation of object declarations and definitions.
677 ; All object output should be routed through gen-decl and gen-defn.
678
679 ; Send the gen-decl message to OBJ, and sanitize the output if necessary.
680
681 (define (gen-decl obj)
682   (logit 3 "Generating decl for "
683          (cond ((method-present? obj 'get-name) (send obj 'get-name))
684                ((elm-present? obj 'name) (elm-get obj 'name))
685                (else "unknown"))
686          " ...\n")
687   (cond ((and (method-present? obj 'gen-decl) (not (has-attr? obj 'META)))
688          (gen-obj-sanitize obj (send obj 'gen-decl)))
689         (else ""))
690 )
691
692 ; Send the gen-defn message to OBJ, and sanitize the output if necessary.
693
694 (define (gen-defn obj)
695   (logit 3 "Generating defn for "
696          (cond ((method-present? obj 'get-name) (send obj 'get-name))
697                ((elm-present? obj 'name) (elm-xget obj 'name))
698                (else "unknown"))
699          " ...\n")
700   (cond ((and (method-present? obj 'gen-defn) (not (has-attr? obj 'META)))
701          (gen-obj-sanitize obj (send obj 'gen-defn)))
702         (else ""))
703 )
704 \f
705 ; Attributes
706
707 ; Return the C/C++ type to use to hold a value for attribute ATTR.
708
709 (define (gen-attr-type attr)
710   (if (string=? (string-downcase (gen-sym attr)) "isa")
711       "CGEN_BITSET"
712       (case (attr-kind attr)
713         ((boolean) "int")
714         ((bitset)  "unsigned int")
715         ((integer) "int")
716         ((enum)    (string-append "enum " (string-downcase (gen-sym attr)) "_attr"))
717         ))
718 )
719
720 ; Return C macros for accessing an object's attributes ATTRS.
721 ; PREFIX is one of "cgen_ifld", "cgen_hw", "cgen_operand", "cgen_insn".
722 ; ATTRS is an alist of attribute values.  The value is unimportant except that
723 ; it is used to determine bool/non-bool.
724 ; Non-bools need to be separated from bools as they're each recorded
725 ; differently.  Non-bools are recorded in an int for each.  All bools are
726 ; combined into one int to save space.
727 ; ??? We assume there is at least one bool.
728
729 (define (gen-attr-accessors prefix attrs)
730   (string-append
731    "/* " prefix " attribute accessor macros.  */\n"
732    (string-map (lambda (attr)
733                  (string-append
734                   "#define CGEN_ATTR_"
735                   (string-upcase prefix)
736                   "_"
737                   (string-upcase (gen-sym attr))
738                   "_VALUE(attrs) "
739                   (if (bool-attr? attr)
740                       (string-append
741                        "(((attrs)->bool & (1 << "
742                        (string-upcase prefix)
743                        "_"
744                        (string-upcase (gen-sym attr))
745                        ")) != 0)")
746                       (string-append
747                        "((attrs)->nonbool["
748                        (string-upcase prefix)
749                        "_"
750                        (string-upcase (gen-sym attr))
751                        "-"
752                        (string-upcase prefix)
753                        "_START_NBOOLS-1]."
754                        (case (attr-kind attr)
755                          ((bitset)
756                           (if (string=? (string-downcase (gen-sym attr)) "isa")
757                               ""
758                               "non"))
759                          (else "non"))
760                        "bitset)"))
761                   "\n"))
762                attrs)
763    "\n")
764 )
765 ; Return C code to declare an enum of attributes ATTRS.
766 ; PREFIX is one of "cgen_ifld", "cgen_hw", "cgen_operand", "cgen_insn".
767 ; ATTRS is an alist of attribute values.  The value is unimportant except that
768 ; it is used to determine bool/non-bool.
769 ; Non-bools need to be separated from bools as they're each recorded
770 ; differently.  Non-bools are recorded in an int for each.  All bools are
771 ; combined into one int to save space.
772 ; ??? We assume there is at least one bool.
773
774 (define (gen-attr-enum-decl prefix attrs)
775   (string-append
776    (gen-enum-decl (string-append prefix "_attr")
777                   (string-append prefix " attrs")
778                   (string-append prefix "_")
779                   (attr-list-enum-list attrs))
780    "/* Number of non-boolean elements in " prefix "_attr.  */\n"
781    "#define " (string-upcase prefix) "_NBOOL_ATTRS "
782    "(" (string-upcase prefix) "_END_NBOOLS - "
783    (string-upcase prefix) "_START_NBOOLS - 1)\n"
784    "\n")
785 )
786
787 ; Return name of symbol ATTR-NAME.
788 ; PREFIX is the prefix arg to gen-attr-enum-decl.
789
790 (define (gen-attr-name prefix attr-name)
791   (string-upcase (gen-c-symbol (string-append prefix "_"
792                                               (symbol->string attr-name))))
793 )
794
795 ; Normal gen-mask argument to gen-bool-attrs.
796 ; Returns "(1<< PREFIX_NAME)" where PREFIX is from atlist-prefix and
797 ; NAME is the name of the attribute.
798 ; ??? This used to return PREFIX_NAME-CGEN_ATTR_BOOL_OFFSET.
799 ; The tradeoff is simplicity vs perceived maximum number of boolean attributes
800 ; needed.  In the end the maximum number needn't be fixed, and the simplicity
801 ; of the current way is good.
802
803 (define (gen-attr-mask prefix name)
804   (string-append "(1<<" (gen-attr-name prefix name) ")")
805 )
806
807 ; Return C expression of bitmasks of boolean attributes in ATTRS.
808 ; ATTRS is an <attr-list> object, it need not be pre-sorted.
809 ; GEN-MASK is a procedure that returns the C code of the mask.
810
811 (define (gen-bool-attrs attrs gen-mask)
812   (let loop ((result "0")
813              (alist (attr-remove-meta-attrs-alist
814                      (attr-nub (atlist-attrs attrs)))))
815     (cond ((null? alist) result)
816           ((and (boolean? (cdar alist)) (cdar alist))
817            (loop (string-append result
818                                 ; `|' is used here instead of `+' so we don't
819                                 ; have to care about duplicates.
820                                 "|" (gen-mask (atlist-prefix attrs)
821                                               (caar alist)))
822                  (cdr alist)))
823           (else (loop result (cdr alist)))))
824 )
825
826 ; Return the C definition of OBJ's attributes.
827 ; TYPE is one of 'ifld, 'hw, 'operand, 'insn.
828 ; [Other objects have attributes but these are the only ones we currently
829 ; emit definitions for.]
830 ; OBJ is any object that supports the 'get-atlist message.
831 ; ALL-ATTRS is an ordered alist of all attributes.
832 ; "ordered" means all the non-boolean attributes are at the front and
833 ; duplicate entries have been removed.
834 ; GEN-MASK is the gen-mask arg to gen-bool-attrs.
835
836 (define (gen-obj-attr-defn type obj all-attrs num-non-bools gen-mask)
837   (let* ((attrs (obj-atlist obj))
838          (non-bools (attr-non-bool-attrs (atlist-attrs attrs)))
839          (all-non-bools (list-take num-non-bools all-attrs)))
840   (string-append
841    "{ "
842    (gen-bool-attrs attrs gen-mask)
843    ", {"
844    ; For the boolean case, we can (currently) get away with only specifying
845    ; the attributes that are used since they all fit in one int and the
846    ; default is currently always #f (and won't be changed without good
847    ; reason).  In the non-boolean case order is important since each value
848    ; has a specific spot in an array, all of them must be specified.
849    (if (null? all-non-bools)
850        " 0"
851        (string-drop1 ; drop the leading ","
852         (string-map (lambda (attr)
853                       (let ((val (or (assq-ref non-bools (obj:name attr))
854                                      (attr-default attr))))
855                         ; FIXME: Are we missing attr-prefix here?
856                         (string-append ", "
857                                        (send attr 'gen-value-for-defn val))))
858                     all-non-bools)))
859    " } }"
860    ))
861 )
862
863 ; Return the C definition of the terminating entry of an object's attributes.
864 ; ALL-ATTRS is an ordered alist of all attributes.
865 ; "ordered" means all the non-boolean attributes are at the front and
866 ; duplicate entries have been removed.
867
868 (define (gen-obj-attr-end-defn all-attrs num-non-bools)
869   (let ((all-non-bools (list-take num-non-bools all-attrs)))
870     (string-append
871      "{ 0, {"
872      (if (null? all-non-bools)
873          " { 0, 0 }"
874          (string-drop1 ; drop the leading ","
875           (string-map (lambda (attr)
876                         (let ((val (attr-default attr)))
877                                         ; FIXME: Are we missing attr-prefix here?
878                           (string-append ", "
879                                          (send attr 'gen-value-for-defn val))))
880                       all-non-bools)))
881      " } }"
882      ))
883 )
884
885 ; Return a boolean indicating if ATLIST indicates a CTI insn.
886
887 (define (atlist-cti? atlist)
888   (or (atlist-has-attr? atlist 'UNCOND-CTI)
889       (atlist-has-attr? atlist 'COND-CTI))
890 )
891 \f
892 ; Misc. gen-* procs
893
894 ; Return name of obj as a C symbol.
895
896 (define (gen-sym obj) (gen-c-symbol (obj:name obj)))
897
898 ; Return the name of the selected cpu family.
899 ; An error is signalled if more than one has been selected.
900
901 (define (gen-cpu-name)
902   ; FIXME: error checking
903   (gen-sym (current-cpu))
904 )
905
906 ; Return HAVE_CPU_<CPU>.
907
908 (define (gen-have-cpu cpu)
909   (string-append "HAVE_CPU_"
910                  (string-upcase (gen-sym cpu)))
911 )
912
913 ; Return the bfd mach name for MACH.
914
915 (define (gen-mach-bfd-name mach)
916   (string-append "bfd_mach_" (gen-c-symbol (mach-bfd-name mach)))
917 )
918
919 ;; Return definition of C macro to get the value of SYM.
920 ;; INDEX-ARGS, EXPR must not have any newlines.
921
922 (define (gen-get-macro sym index-args expr)
923   (string-append
924    "#define GET_" (string-upcase sym) "(" index-args ") " expr "\n")
925 )
926
927 ;; Return definition of C macro to get the value of SYM, version 2.
928 ;; EXPR is a C expression *without* proper \newline handling,
929 ;; we prepend \ to each line.
930 ;; INDEX-ARGS, EXPR must not have any newlines.
931
932 (define (gen-get-macro2 sym index-args expr)
933   (string-append
934    "#define GET_" (string-upcase sym) "(" index-args ") "
935    (backslash "\n" expr)
936    "\n")
937 )
938
939 ;; Return definition of C macro to set the value of SYM.
940 ;; INDEX-ARGS, EXPR, LVALUE must not have any newlines.
941
942 (define (gen-set-macro sym index-args lvalue)
943   (string-append
944    "#define SET_" (string-upcase sym)
945    "(" index-args
946    (if (equal? index-args "") "" ", ")
947    "x) (" lvalue " = (x))\n")
948 )
949
950 ;; Return definition of C macro to set the value of SYM, version 2.
951 ;; EXPR is one or more C statements *without* proper \newline handling,
952 ;; we prepend \ to each line.
953 ;; INDEX-ARGS, NEWVAL-ARG must not have any newlines.
954
955 (define (gen-set-macro2 sym index-args newval-arg expr)
956   (string-append
957    "#define SET_" (string-upcase sym)
958    "(" index-args
959    (if (equal? index-args "") "" ", ")
960    newval-arg ") \\\n"
961    "do { \\\n"
962    (backslash "\n" expr)
963    ";} while (0)\n")
964 )
965 \f
966 ;; Misc. object utilities.
967
968 ;; Return the nub of a list of objects.
969
970 (define (obj-list-nub obj-list)
971   (nub obj-list obj:name)
972 )
973
974 ;; Sort a list of objects with get-name methods alphabetically.
975
976 (define (alpha-sort-obj-list l)
977   (sort l
978         (lambda (o1 o2)
979           (symbol<? (obj:name o1) (obj:name o2))))
980 )
981 \f
982 ; Called before loading the .cpu file to initialize.
983
984 (define (utils-init!)
985   (reader-add-command! 'sanitize
986                        "\
987 Mark an entry as being sanitized.
988 "
989                        nil '(keyword entry-type . entry-names) sanitize)
990
991   *UNSPECIFIED*
992 )
993
994 ; Return a pair of definitions for a C macro that concatenates its
995 ; argument symbols.  The definitions are conditional on ANSI C
996 ; semantics: one contains ANSI concat operators (##), and the other
997 ; uses the empty-comment trick (/**/).  We must do this, rather than
998 ; use CONCATn(...) as defined in include/symcat.h, in order to avoid
999 ; spuriously expanding our macro's args.
1000
1001 (define (gen-define-with-symcat head . args)
1002   (string-append
1003    "\
1004 #if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
1005 #define "
1006    head (string-map (lambda (elm) (string-append "##" elm)) args)
1007    "
1008 #else
1009 #define "
1010    head (string-map (lambda (elm) (string-append "/**/" elm)) args)
1011    "
1012 #endif
1013 "
1014    )
1015 )