2 ; Copyright (C) 2000, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
6 ; FIXME: Later allow target to add new modes.
12 ; One of RANDOM, INT, UINT, FLOAT.
21 ; NON-MODE-C-TYPE is the C type to use in situations where
22 ; modes aren't available. A somewhat dubious feature, but at
23 ; the moment the opcodes tables use it. It is either the C
24 ; type as a string (e.g. "int") or #f for non-portable modes
25 ; (??? could use other typedefs for #f, e.g. int64 for DI).
26 ; Use of GCC can't be assumed though.
29 ; PRINTF-TYPE is the %<letter> arg to printf-like functions,
30 ; however we define our own extensions for non-portable modes.
31 ; Values not understood by printf aren't intended to be used
36 ; %D - DI mode (8 bytes)
37 ; %T - TI mode (16 bytes)
38 ; %O - OI mode (32 bytes)
43 ; SEM-MODE is the mode to use for semantic operations.
44 ; Unsigned modes are not part of the semantic language proper,
45 ; but they can be used in hardware descriptions. This maps
46 ; unusable -> usable modes. It is #f if the mode is usable by
47 ; itself. This prevents circular data structures and makes it
48 ; easy to define since the object doesn't exist before it's
50 ; ??? May wish to later remove SEM-MODE (e.g. mips signed add
51 ; is different than mips unsigned add). However for now it keeps
52 ; things simpler, and prevents being wildly dissimilar from
53 ; GCC-RTL. And the mips case needn't be handled with different
57 ; PTR-TO, if non-#f, is the mode being pointed to.
60 ; HOST? is non-#f if the mode is a portable int for hosts,
61 ; or other host-related value.
62 ; This is used for things like register numbers and small
63 ; odd-sized immediates and registers.
64 ; ??? Not my favorite word choice here, but it's close.
72 (define mode:class (elm-make-getter <mode> 'class))
73 (define mode:bits (elm-make-getter <mode> 'bits))
74 (define mode:bytes (elm-make-getter <mode> 'bytes))
75 (define mode:non-mode-c-type (elm-make-getter <mode> 'non-mode-c-type))
76 (define mode:printf-type (elm-make-getter <mode> 'printf-type))
77 (define mode:sem-mode (elm-make-getter <mode> 'sem-mode))
78 ; ptr-to is currently private so there is no accessor.
79 (define mode:host? (elm-make-getter <mode> 'host?))
81 ;; Utility to set the parameters of WI/UWI/AI/IAI modes.
83 (define (/mode-set-word-params! dst src)
86 (object-assign! dst src)
90 ; Return string C type to use for values of mode M.
92 (define (mode:c-type m)
93 (let ((ptr-to (elm-xget m 'ptr-to)))
95 (string-append (mode:c-type ptr-to) " *")
99 ; CM is short for "concat mode". It is a list of modes of the elements
101 ; ??? Experiment. Not currently used.
103 (define <concat-mode>
104 (class-make '<concat-mode> '(<mode>)
106 ; List of element modes
114 (define cmode-elm-modes (elm-make-getter <concat-mode> 'elm-modes))
116 ;; Table of all modes.
117 (define /mode-table nil)
119 ;; This exists to simplify mode-find.
120 (define /mode-class-table nil)
122 ; Return list of real mode objects (no aliases).
124 (define (mode-list-non-alias-values)
125 (hash-fold (lambda (key value prior)
126 (if (eq? key (obj:name value))
133 ; Return a boolean indicating if X is a <mode> object.
135 (define (mode? x) (class-instance? <mode> x))
137 ; Return enum cgen_mode_types value for M.
139 (define (mode:enum m)
140 (gen-c-symbol (string-append "MODE_" (string-upcase (obj:str-name m))))
143 ; Return a boolean indicating if MODE1 is equal to MODE2
144 ; Either may be the name of a mode or a <mode> object.
145 ; Aliases are handled by refering to their real name.
146 ; ??? Might be useful to restrict this to <mode> objects only.
148 (define (mode:eq? mode1 mode2)
149 (let ((mode1-name (mode-real-name (mode-maybe-lookup mode1)))
150 (mode2-name (mode-real-name (mode-maybe-lookup mode2))))
151 (eq? mode1-name mode2-name))
154 ; Return a boolean indicating if CLASS is one of INT/UINT.
156 (define (mode-class-integral? class) (memq class '(INT UINT)))
157 (define (mode-class-signed? class) (eq? class 'INT))
158 (define (mode-class-unsigned? class) (eq? class 'UINT))
160 ; Return a boolean indicating if CLASS is floating point.
162 (define (mode-class-float? class) (memq class '(FLOAT)))
164 ; Return a boolean indicating if CLASS is numeric.
166 (define (mode-class-numeric? class) (memq class '(INT UINT FLOAT)))
168 ; Return a boolean indicating if <mode> MODE has an integral mode class.
169 ; Similarily for signed/unsigned.
171 (define (mode-integral? mode) (mode-class-integral? (mode:class mode)))
172 (define (mode-signed? mode) (mode-class-signed? (mode:class mode)))
173 (define (mode-unsigned? mode) (mode-class-unsigned? (mode:class mode)))
175 ; Return a boolean indicating if <mode> MODE has a floating point mode class.
177 (define (mode-float? mode) (mode-class-float? (mode:class mode)))
179 ; Return a boolean indicating if <mode> MODE has a numeric mode class.
181 (define (mode-numeric? mode) (mode-class-numeric? (mode:class mode)))
183 ;; Return a boolean indicating if <mode> MODE is VOID.
185 (define (mode-void? mode)
189 ; Return a boolean indicating if MODE1 is compatible with MODE2.
190 ; MODE[12] are either names or <mode> objects.
191 ; HOW is a symbol indicating how the test is performed:
192 ; strict: modes must have same name
193 ; samesize: modes must be both float, or both integer (int or uint),
194 ; or both VOID and have same size
195 ; sameclass: modes must be both float, or both integer (int or uint),
197 ; numeric: modes must be both numeric
199 (define (mode-compatible? how mode1 mode2)
200 (let ((m1 (mode-maybe-lookup mode1))
201 (m2 (mode-maybe-lookup mode2)))
204 (eq? (obj:name m1) (obj:name m2)))
206 (cond ((mode-integral? m1)
207 (and (mode-integral? m2)
208 (= (mode:bits m1) (mode:bits m2))))
210 (and (mode-float? m2)
211 (= (mode:bits m1) (mode:bits m2))))
216 (cond ((mode-integral? m1) (mode-integral? m2))
217 ((mode-float? m1) (mode-float? m2))
218 ((mode-void? m1) (mode-void? m2))
221 (and (mode-numeric? m1) (mode-numeric? m2)))
222 (else (error "bad `how' arg to mode-compatible?" how))))
225 ; Add MODE named NAME to the table of recognized modes.
226 ; If NAME is already present, replace it with MODE.
227 ; MODE is a mode object.
228 ; NAME exists to allow aliases of modes [e.g. WI, UWI, AI, IAI].
230 ; No attempt to preserve any particular order of entries is done here.
231 ; That is up to the caller.
233 (define (mode:add! name mode)
234 (hashq-set! /mode-table name mode)
236 ;; Add the mode to its mode class.
237 ;; There's no point in building this list in any particular order,
238 ;; if the user adds some they could be of any size.
239 ;; So build the list the simple way (in reverse).
240 ;; The list is sorted in mode-finish!.
241 (let ((class (mode:class mode)))
242 (hashq-set! /mode-class-table class
243 (cons mode (hashq-ref /mode-class-table class))))
249 ; This is the main routine for building a mode object.
250 ; All arguments are in raw (non-evaluated) form.
252 (define (/mode-parse context name comment attrs class bits bytes
253 non-mode-c-type printf-type sem-mode ptr-to host?)
254 (logit 2 "Processing mode " name " ...\n")
256 ;; Pick out name first to augment the error context.
257 (let* ((name (parse-name context name))
258 (context (context-append-name context name)))
262 (parse-comment context comment)
263 (atlist-parse context attrs "mode")
264 class bits bytes non-mode-c-type printf-type
265 sem-mode ptr-to host?))
268 ; ??? At present there is no define-mode that takes an associative list
271 ; Define a mode object, all arguments specified.
273 (define (define-full-mode name comment attrs class bits bytes
274 non-mode-c-type printf-type sem-mode ptr-to host?)
275 (let ((m (/mode-parse (make-current-context "define-full-mode")
278 non-mode-c-type printf-type sem-mode ptr-to host?)))
279 ; Add it to the list of insn modes.
284 ; Lookup the mode named X.
285 ; Return the found object or #f.
286 ; If X is already a mode object, return that.
288 (define (mode:lookup mode-name)
291 ; (let ((result (assq x mode-list)))
295 (hashq-ref /mode-table mode-name)
298 ;; Same as mode:lookup except MODE is either the mode name or a <mode> object.
300 (define (mode-maybe-lookup mode)
302 (hashq-ref /mode-table mode)
306 ; Return a boolean indicating if X is a valid mode name.
308 (define (mode-name? x)
310 (->bool (mode:lookup x)))
313 ; Return the name of the real mode of MODE, a <mode> object.
314 ; This is a no-op unless M is an alias in which case we return the
315 ; real mode of the alias.
317 (define (mode-real-name mode)
321 ; Return the real mode of MODE, a <mode> object.
322 ; This is a no-op unless M is an alias in which case we return the
323 ; real mode of the alias.
325 (define (mode-real-mode mode)
326 ;; Lookups of aliases return its real mode, so this function is a no-op.
327 ;; But that's an implementation detail, so I'm not ready to delete this
332 ; Return the version of MODE to use in semantic expressions.
333 ; MODE is a <mode> object.
334 ; This (essentially) converts aliases to their real value and then uses
335 ; mode:sem-mode. The implementation is the opposite but the effect is the
337 ; ??? Less efficient than it should be. One improvement would be to
338 ; disallow unsigned modes from being aliased and set sem-mode for aliased
341 (define (mode-sem-mode mode)
342 (let ((sm (mode:sem-mode mode)))
345 (mode-real-mode mode)))
348 ; Return #t if mode M1 is bigger than mode M2.
349 ; Both are <mode> objects.
351 (define (mode-bigger? m1 m2)
356 ; Return a mode in mode class CLASS wide enough to hold BITS.
357 ; This ignores "host" modes (e.g. INT,UINT).
359 (define (mode-find bits class)
360 (let* ((class-modes (hashq-ref /mode-class-table class))
361 (modes (find (lambda (mode) (not (mode:host? mode)))
362 (or class-modes nil))))
364 (error "invalid mode class" class))
365 (let loop ((modes modes))
366 (cond ((null? modes) (error "no modes for bits" bits))
367 ((<= bits (mode:bits (car modes))) (car modes))
368 (else (loop (cdr modes))))))
371 ; Parse MODE-NAME and return the mode object.
372 ; CONTEXT is a <context> object for error messages.
373 ; An error is signalled if MODE isn't valid.
375 (define (parse-mode-name context mode-name)
376 (let ((m (mode:lookup mode-name)))
378 (parse-error context "not a valid mode" mode-name))
382 ; Make a new INT/UINT mode.
383 ; These have a variable number of bits (1-64).
385 (define (mode-make-int bits)
386 (if (or (<= bits 0) (> bits 64))
387 (error "unsupported number of bits" bits))
388 (let ((result (object-copy-top INT)))
389 (elm-xset! result 'bits bits)
390 (elm-xset! result 'bytes (bits->bytes bits))
394 (define (mode-make-uint bits)
395 (if (or (<= bits 0) (> bits 64))
396 (error "unsupported number of bits" bits))
397 (let ((result (object-copy-top UINT)))
398 (elm-xset! result 'bits bits)
399 (elm-xset! result 'bytes (bits->bytes bits))
403 ; WI/UWI/AI/IAI modes
404 ; These are aliases for other modes, e.g. SI,DI.
405 ; Final values are defered until all cpu family definitions have been
406 ; read in so that we know the word size, etc.
408 ; NOTE: We currently assume WI/AI/IAI all have the same size: cpu:word-bitsize.
409 ; If we ever add an architecture that needs different modes for WI/AI/IAI,
410 ; we can add the support then.
412 ; This is defined by the target in define-cpu:word-bitsize.
416 ; An "address int". This is recorded in addition to a "word int" because it
417 ; is believed that some target will need it. It also stays consistent with
418 ; what BFD does. It also allows one to write rtl without having to care
419 ; what the real mode actually is.
420 ; ??? These are currently set from define-cpu:word-bitsize but that's just
421 ; laziness. If an architecture comes along that has different values,
422 ; add the support then.
426 ; Kind of word size handling wanted.
427 ; BIGGEST: pick the largest word size
428 ; IDENTICAL: all word sizes must be identical
429 (define /mode-word-sizes-kind #f)
431 ;; Set to true if mode-set-word-modes! has been called.
432 (define /mode-word-sizes-defined? #f)
434 ; Called when a cpu-family is read in to set the word sizes.
436 (define (mode-set-word-modes! bitsize)
437 (let ((current-word-bitsize (mode:bits WI))
438 (word-mode (mode-find bitsize 'INT))
439 (uword-mode (mode-find bitsize 'UINT))
442 ; Ensure we found a precise match.
443 (if (!= bitsize (mode:bits word-mode))
444 (error "unable to find precise mode to match cpu word-bitsize" bitsize))
446 ; Enforce word size kind.
447 (if /mode-word-sizes-defined?
448 (case /mode-word-sizes-kind
450 (if (!= current-word-bitsize (mode:bits word-mode))
451 (error "app requires all selected cpu families to have same word size"))
454 (if (>= current-word-bitsize (mode:bits word-mode))
460 (/mode-set-word-params! WI word-mode)
461 (/mode-set-word-params! UWI uword-mode)
462 (/mode-set-word-params! AI uword-mode)
463 (/mode-set-word-params! IAI uword-mode)
467 (set! /mode-word-sizes-defined? #t)
470 ; Called by apps to indicate cpu:word-bitsize always has one value.
471 ; It is an error to call this if the selected cpu families have
472 ; different word sizes.
473 ; Must be called before loading .cpu files.
475 (define (mode-set-identical-word-bitsizes!)
476 (set! /mode-word-sizes-kind 'IDENTICAL)
479 ; Called by apps to indicate using the biggest cpu:word-bitsize of all
480 ; selected cpu families.
481 ; Must be called before loading .cpu files.
483 (define (mode-set-biggest-word-bitsizes!)
484 (set! /mode-word-sizes-kind 'BIGGEST)
487 ; Ensure word sizes have been defined.
488 ; This must be called after all cpu families have been defined
489 ; and before any ifields, hardware, operand or insns have been read.
490 ; FIXME: sparc.cpu breaks this
492 (define (mode-ensure-word-sizes-defined)
493 (if (not /mode-word-sizes-defined?)
494 (error "word sizes must be defined"))
499 ; Some modes are refered to by the Scheme code.
500 ; These have global bindings, but we try not to make this the general rule.
501 ; [Actually I don't think this is all that bad, but it seems reasonable to
502 ; not create global bindings that we don't have to.]
507 ; Variable sized portable ints.
511 ;; Sort the modes for each class.
513 (define (/sort-mode-classes!)
514 (for-each (lambda (class-name)
515 (hashq-set! /mode-class-table class-name
516 (sort (hashq-ref /mode-class-table class-name)
520 '(RANDOM INT UINT FLOAT))
526 (set! /mode-word-sizes-kind 'IDENTICAL)
527 (set! /mode-word-sizes-defined? #f)
529 (reader-add-command! 'define-full-mode
531 Define a mode, all arguments specified.
533 nil '(name commment attrs class bits bytes
534 non-c-mode-type printf-type sem-mode ptr-to host?)
540 ; Called before a . cpu file is read in to install any builtins.
542 (define (mode-builtin!)
543 ; FN-SUPPORT: In sem-ops.h file, include prototypes as well as macros.
544 ; Elsewhere, functions are defined to perform the operation.
545 (define-attr '(for mode) '(type boolean) '(name FN-SUPPORT))
547 (set! /mode-class-table (make-hash-table 7))
548 (hashq-set! /mode-class-table 'RANDOM '())
549 (hashq-set! /mode-class-table 'INT '())
550 (hashq-set! /mode-class-table 'UINT '())
551 (hashq-set! /mode-class-table 'FLOAT '())
553 (set! /mode-table (make-hash-table 41))
555 (let ((dfm define-full-mode))
556 ; This list must be defined in order of increasing size among each type.
559 (dfm 'VOID "void" '() 'RANDOM 0 0 "void" "" #f #f #f) ; VOIDmode
561 ; Special marker to indicate "use the default mode".
562 (dfm 'DFLT "default mode" '() 'RANDOM 0 0 "" "" #f #f #f)
564 ; Mode used in `symbol' rtxs.
565 (dfm 'SYM "symbol" '() 'RANDOM 0 0 "" "" #f #f #f)
567 ; Mode used in `current-insn' rtxs.
568 (dfm 'INSN "insn" '() 'RANDOM 0 0 "" "" #f #f #f)
570 ; Mode used in `current-mach' rtxs.
571 (dfm 'MACH "mach" '() 'RANDOM 0 0 "" "" #f #f #f)
573 ; Not UINT on purpose.
574 (dfm 'BI "one bit (0,1 not 0,-1)" '() 'INT 1 1 "int" "'x'" #f #f #f)
576 (dfm 'QI "8 bit byte" '() 'INT 8 1 "int" "'x'" #f #f #f)
577 (dfm 'HI "16 bit int" '() 'INT 16 2 "int" "'x'" #f #f #f)
578 (dfm 'SI "32 bit int" '() 'INT 32 4 "int" "'x'" #f #f #f)
579 (dfm 'DI "64 bit int" '(FN-SUPPORT) 'INT 64 8 "" "'D'" #f #f #f)
581 ; No unsigned versions on purpose for now.
582 (dfm 'TI "128 bit int" '(FN-SUPPORT) 'INT 128 16 "" "'T'" #f #f #f)
583 (dfm 'OI "256 bit int" '(FN-SUPPORT) 'INT 256 32 "" "'O'" #f #f #f)
585 (dfm 'UQI "8 bit unsigned byte" '() 'UINT
586 8 1 "unsigned int" "'x'" (mode:lookup 'QI) #f #f)
587 (dfm 'UHI "16 bit unsigned int" '() 'UINT
588 16 2 "unsigned int" "'x'" (mode:lookup 'HI) #f #f)
589 (dfm 'USI "32 bit unsigned int" '() 'UINT
590 32 4 "unsigned int" "'x'" (mode:lookup 'SI) #f #f)
591 (dfm 'UDI "64 bit unsigned int" '(FN-SUPPORT) 'UINT
592 64 8 "" "'D'" (mode:lookup 'DI) #f #f)
594 ; Floating point values.
595 (dfm 'SF "32 bit float" '(FN-SUPPORT) 'FLOAT
596 32 4 "" "'f'" #f #f #f)
597 (dfm 'DF "64 bit float" '(FN-SUPPORT) 'FLOAT
598 64 8 "" "'f'" #f #f #f)
599 (dfm 'XF "80/96 bit float" '(FN-SUPPORT) 'FLOAT
600 96 12 "" "'F'" #f #f #f)
601 (dfm 'TF "128 bit float" '(FN-SUPPORT) 'FLOAT
602 128 16 "" "'F'" #f #f #f)
604 ; These are useful modes that represent host values.
605 ; For INT/UINT the sizes indicate maximum portable values.
606 ; These are also used for random width hardware elements (e.g. immediates
608 ; FIXME: Can't be used to represent both host and target values.
609 ; Either remove the distinction or add new modes with the distinction.
610 (dfm 'INT "portable int" '() 'INT 32 4 "int" "'x'"
611 (mode:lookup 'SI) #f #t)
612 (dfm 'UINT "portable unsigned int" '() 'UINT 32 4 "unsigned int" "'x'"
613 (mode:lookup 'SI) #f #t)
616 (dfm 'PTR "host pointer" '() 'RANDOM 0 0 "PTR" "'x'"
617 #f (mode:lookup 'VOID) #t)
620 (set! VOID (mode:lookup 'VOID))
621 (set! DFLT (mode:lookup 'DFLT))
623 (set! INT (mode:lookup 'INT))
624 (set! UINT (mode:lookup 'UINT))
626 ;; While setting the real values of WI/UWI/AI/IAI is defered to
627 ;; mode-set-word-modes!, create usable entries in the table.
628 ;; The entries must be usable as h/w elements may be defined that use them.
629 (set! WI (object-copy-top (mode:lookup 'SI)))
630 (set! UWI (object-copy-top (mode:lookup 'USI)))
631 (set! AI (object-copy-top (mode:lookup 'USI)))
632 (set! IAI (object-copy-top (mode:lookup 'USI)))
638 ;; Need to have usable mode classes at this point as define-cpu
639 ;; calls mode-set-word-modes!.
640 (/sort-mode-classes!)
645 (define (mode-finish!)
646 ;; FIXME: mode:add! should keep the class sorted.
647 ;; It's a cleaner way to handle modes from the .cpu file.
648 (/sort-mode-classes!)