diff options
Diffstat (limited to 'cgen/rtl-c.scm')
-rw-r--r-- | cgen/rtl-c.scm | 1662 |
1 files changed, 1662 insertions, 0 deletions
diff --git a/cgen/rtl-c.scm b/cgen/rtl-c.scm new file mode 100644 index 00000000000..0469c9be6d6 --- /dev/null +++ b/cgen/rtl-c.scm @@ -0,0 +1,1662 @@ +; RTL->C translation support. +; Copyright (C) 2000 Red Hat, Inc. +; This file is part of CGEN. +; See file COPYING.CGEN for details. + +; Generating C from RTL +; --------------------- +; The main way to generate C code from an RTL expression is: +; +; (rtl-c mode '(func mode ...) nil) +; +; E.g. +; (rtl-c DFLT '(add SI (const SI 1) (const SI 2)) nil) +; --> +; "ADDSI (1, 2)" +; Mode `DFLT' (DEFAULTmode) means "use the default/natural mode". +; +; The expression is in source form or may be already compiled (with +; rtx-compile). +; +; The `set' rtx needs to be handled a little carefully. +; Both the dest and src are processed first, and then code to perform the +; assignment is computed. However, the dest may require more than a simple +; C assignment. Therefore set dests are converted to the specified object +; (e.g. a hardware operand) and then a message is sent to this object to +; perform the actual code generation. +; +; All interesting operands (e.g. regs, mem) are `operand' objects. +; The following messages must be supported by operand objects. +; - get-mode - return mode of operand +; - cxmake-get - return <c-expr> object containing operand's value +; - gen-set-quiet - return string of C code to set operand's value (no tracing) +; - gen-set-trace - return string of C code to set operand's value +; +; Instruction fields are refered to by name. +; (estate-owner estate) must be an instruction that has the field. +; Instruction ifields must have these methods: +; - get-mode +; - cxmake-get +; +; Conventions used in this file: +; - see rtl.scm + +; The <c-expr> object. +; This is a fully translated expression (i.e. C code). + +(define <c-expr> + (class-make '<c-expr> nil + '( + ; The mode of C-CODE. + mode + ; The translated C code. + c-code + ; The source expression, for debugging. + expr + ; Attributes of the expression. + atlist + ; List of temporaries required to compute the expression. + ; ??? wip. These would be combined as the expression is + ; built up. Then in sets and other statements, the temporaries + ; would be declared. + ;(tmps . nil) + ) + nil) +) + +(method-make! + <c-expr> 'make! + (lambda (self mode c-code atlist) + ; FIXME: Extend COS to allow specifying member predicates. + (assert (mode? mode)) + (assert (string? c-code)) + ;(assert (atlist? atlist)) ; FIXME: What should this be? + (elm-set! self 'mode mode) + (elm-set! self 'c-code c-code) + (elm-set! self 'atlist atlist) + self) +) + +; Accessor fns + +(define cx:mode (elm-make-getter <c-expr> 'mode)) +(define cx:c-code (elm-make-getter <c-expr> 'c-code)) +(define cx:expr (elm-make-getter <c-expr> 'expr)) +(define cx:atlist (elm-make-getter <c-expr> 'atlist)) +;(define cx:tmps (elm-make-getter <c-expr> 'tmps)) + +; Any object with attributes requires the get-atlist method. + +(method-make! <c-expr> 'get-atlist (lambda (self) (elm-get self 'atlist))) + +; Respond to 'get-mode messages. + +(method-make! <c-expr> 'get-mode (lambda (self) (elm-get self 'mode))) + +; Respond to 'get-name messages for rtx-dump. + +(method-make! + <c-expr> 'get-name + (lambda (self) + (string-append "(" (obj:name (elm-get self 'mode)) ") " + (cx:c self))) +) + +; Return C code to perform an assignment. +; NEWVAL is a <c-expr> object of the value to be assigned to SELF. + +(method-make! <c-expr> 'gen-set-quiet + (lambda (self estate mode indx selector newval) + (string-append " " (cx:c self) " = " (cx:c newval) ";\n")) +) + +(method-make! <c-expr> 'gen-set-trace + (lambda (self estate mode indx selector newval) + (string-append " " (cx:c self) " = " (cx:c newval) ";\n")) +) + +; Return the C code of CX. +; ??? This used to handle lazy evaluation of the expression. +; Maybe it will again, so it's left in, as a cover fn to cx:c-code. + +(define (cx:c cx) + (cx:c-code cx) +) + +; Main routine to create a <c-expr> node object. +; MODE is either the mode's symbol (e.g. 'QI) or a mode object. +; CODE is a string of C code. + +(define (cx:make mode code) + (make <c-expr> (mode:lookup mode) code nil) +) + +; Make copy of CX in new mode MODE. +; MODE must be a <mode> object. + +(define (cx-new-mode mode cx) + (make <c-expr> mode (cx:c cx) (cx:atlist cx)) +) + +; Same as cx:make except with attributes. + +(define (cx:make-with-atlist mode code atlist) + (make <c-expr> (mode:lookup mode) code atlist) +) + +; Return a boolean indicated if X is a <c-expr> object. + +(define (c-expr? x) (class-instance? <c-expr> x)) + +; RTX environment support. + +(method-make! + <rtx-temp> 'cxmake-get + (lambda (self estate mode indx selector) + (cx:make mode (rtx-temp-value self))) +) + +(method-make! + <rtx-temp> 'gen-set-quiet + (lambda (self estate mode indx selector src) + (string-append " " (rtx-temp-value self) " = " (cx:c src) ";\n")) +) + +(method-make! + <rtx-temp> 'gen-set-trace + (lambda (self estate mode indx selector src) + (string-append " " (rtx-temp-value self) " = " (cx:c src) ";\n")) +) + +(define (gen-temp-defs estate env) + (string-map (lambda (temp) + (let ((temp-obj (cdr temp))) + (string-append " " (mode:c-type (rtx-temp-mode temp-obj)) + " " (rtx-temp-value temp-obj) ";\n"))) + env) +) + +; Top level routines to handle rtl->c translation. + +; rtl->c configuration parameters + +; #t -> emit calls to rtl cover fns, otherwise emit plain C where possible. +(define -rtl-c-rtl-cover-fns? #f) + +; Called before emitting code to configure the generator. +; ??? I think this can go away now (since cover-fn specification is also +; done at each call to rtl-c). + +(define (rtl-c-config! . args) + (set! -rtl-c-rtl-cover-fns? #f) + (let loop ((args args)) + (if (null? args) + #f ; done + (begin + (case (car args) + ((#:rtl-cover-fns?) + (set! -rtl-c-rtl-cover-fns? (cadr args))) + (else (error "rtl-c-config: unknown option:" (car args)))) + (loop (cddr args))))) + *UNSPECIFIED* +) + +; Subclass of <eval-state> to record additional things needed for rtl->c. + +(define <rtl-c-eval-state> + (class-make '<rtl-c-eval-state> '(<eval-state>) + '( + ; #t -> emit calls to rtl cover fns. + (rtl-cover-fns? . #f) + + ; name of output language, "c" or "c++" + (output-language . "c") + + ; #t if generating code for a macro. + ; Each newline is then preceeded with '\\'. + (macro? . #f) + + ; #f -> reference ifield values using FLD macro. + ; #t -> use C variables. + ; ??? This is only needed to get correct ifield references + ; in opcodes, decoder, and semantics. Maybe a better way to + ; go would be to specify the caller's name so there'd be just + ; one of these, rather than an increasing number. However, + ; for now either way is the same. + ; An alternative is to specify a callback to try first. + (ifield-var? . #f) + ) + nil) +) + +; FIXME: involves upcasting. +(define-getters <rtl-c-eval-state> estate + (rtl-cover-fns? output-language macro? ifield-var?) +) + +; Return booleans indicating if output language is C/C++. + +(define (estate-output-language-c? estate) + (string=? (estate-output-language estate) "c") +) +(define (estate-output-language-c++? estate) + (string=? (estate-output-language estate) "c++") +) + +(method-make! + <rtl-c-eval-state> 'vmake! + (lambda (self args) + ; Initialize parent class first. + (let loop ((args (send-next self 'vmake! args)) (unrecognized nil)) + (if (null? args) + (reverse! unrecognized) ; ??? Could invoke method to initialize here. + (begin + (case (car args) + ((#:rtl-cover-fns?) + (elm-set! self 'rtl-cover-fns? (cadr args))) + ((#:output-language) + (elm-set! self 'output-language (cadr args))) + ((#:macro?) + (elm-set! self 'macro? (cadr args))) + ((#:ifield-var?) + (elm-set! self 'ifield-var? (cadr args))) + (else + ; Build in reverse order, as we reverse it back when we're done. + (set! unrecognized + (cons (cadr args) (cons (car args) unrecognized))))) + (loop (cddr args) unrecognized))))) +) + +; Build an estate for use in generating C. +; CONTEXT is a <context> object or #f if there is none. +; OWNER is the owner of the expression or #f if there is none. +; EXTRA-VARS-ALIST is an association list of (symbol <mode> value) +; elements to be used during value lookup. +; OVERRIDES is a #:keyword/value list of parameters to apply last. + +(define (estate-make-for-rtl-c context owner extra-vars-alist + rtl-cover-fns? macro? overrides) + (apply vmake + (append! + (list + <rtl-c-eval-state> + #:context context + #:owner owner + #:expr-fn (lambda (rtx-obj expr mode estate) + (rtl-c-generator rtx-obj)) + #:env (rtx-env-init-stack1 extra-vars-alist) + #:rtl-cover-fns? rtl-cover-fns? + #:macro? macro?) + overrides)) +) + +(define (estate-make-for-normal-rtl-c extra-vars-alist overrides) + (estate-make-for-rtl-c + #f ; FIXME: context + #f ; FIXME: owner + extra-vars-alist + -rtl-c-rtl-cover-fns? + #f ; macro? + overrides) +) + +; Translate RTL expression EXPR to C. +; ESTATE is the current rtx evaluation state. + +(define (rtl-c-with-estate estate mode expr) + (cx:c (rtl-c-get estate mode (rtx-eval-with-estate expr mode estate))) +) + +; Translate parsed RTL expression X to a string of C code. +; X must have already been fed through rtx-parse/rtx-compile. +; MODE is the desired mode of the value or DFLT for "natural mode". +; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value) +; elements to be used during value lookup. +; OVERRIDES is a #:keyword/value list of arguments to build the eval state +; with. +; ??? Maybe EXTRA-VARS-ALIST should be handled this way. + +(define (rtl-c-parsed mode x extra-vars-alist . overrides) + (let ((estate (estate-make-for-normal-rtl-c extra-vars-alist overrides))) + (rtl-c-with-estate estate mode x)) +) + +; Same as rtl-c-parsed but X is unparsed. + +(define (rtl-c mode x extra-vars-alist . overrides) + ; ??? rtx-compile could return a closure, then we wouldn't have to + ; pass EXTRA-VARS-ALIST to two routines here. + (let ((estate (estate-make-for-normal-rtl-c extra-vars-alist overrides))) + (rtl-c-with-estate estate mode (rtx-compile #f x extra-vars-alist))) +) + +; C++ versions of rtl-c routines. + +; Build an estate for use in generating C++. +; EXTRA-VARS-ALIST is an association list of (symbol <mode> value) +; elements to be used during value lookup. +; OVERRIDES is a #:keyword/value list of parameters to apply last. + +(define (estate-make-for-normal-rtl-c++ extra-vars-alist overrides) + (estate-make-for-rtl-c + #f ; FIXME: context + #f ; FIXME: owner + extra-vars-alist + -rtl-c-rtl-cover-fns? + #f ; macro? + (cons #:output-language (cons "c++" overrides))) +) + +; Translate parsed RTL expression X to a string of C++ code. +; X must have already been fed through rtx-parse/rtx-compile. +; MODE is the desired mode of the value or DFLT for "natural mode". +; EXTRA-VARS-ALIST is an association list of extra (symbol <mode> value) +; elements to be used during value lookup. +; OVERRIDES is a #:keyword/value list of arguments to build the eval state +; with. +; ??? Maybe EXTRA-VARS-ALIST should be handled this way. + +(define (rtl-c++-parsed mode x extra-vars-alist . overrides) + (let ((estate (estate-make-for-normal-rtl-c++ extra-vars-alist overrides))) + (rtl-c-with-estate estate mode x)) +) + +; Same as rtl-c-parsed but X is unparsed. + +(define (rtl-c++ mode x extra-vars-alist . overrides) + ; ??? rtx-compile could return a closure, then we wouldn't have to + ; pass EXTRA-VARS-ALIST to two routines here. + (let ((estate (estate-make-for-normal-rtl-c++ extra-vars-alist overrides))) + (rtl-c-with-estate estate mode (rtx-compile #f x extra-vars-alist))) +) + +; Top level routines for getting/setting values. + +; Return a <c-expr> node to get the value of SRC in mode MODE. +; ESTATE is the current rtl evaluation state. +; SRC is one of: +; - <c-expr> node +; - rtl expression (e.g. '(add WI dr sr)) +; - sequence's local variable name +; - sequence's local variable object +; - operand name +; - operand object +; - a string of C code +; FIXME: Reduce acceptable values of SRC. +; The result has mode MODE, unless MODE is the "default mode indicator" +; (DFLT) in which case the mode of the result is derived from SRC. +; If SRC is a string, MODE can't be VOID or DFLT. +; +; ??? mode compatibility checks are wip + +(define (rtl-c-get estate mode src) + (logit 4 "(rtl-c-get " (mode-real-name mode) " " (rtx-strdump src) ")\n") + + (let ((mode (mode:lookup mode))) + + (cond ((c-expr? src) + (cond ((or (mode:eq? 'VOID mode) + (mode:eq? 'DFLT mode) + (mode:eq? (cx:mode src) mode)) + src) + ((-rtx-mode-compatible? mode (cx:mode src)) + (cx-new-mode mode src)) + (else + (error (string-append "incompatible mode for " + "(" (obj:name (cx:mode src)) ") " + "\"" (cx:c src) "\"" + ": ") + (obj:name mode))))) + + ; The recursive call to rtl-c-get is in case the result of rtx-eval + ; is a hardware object, rtx-func object, or another rtl expression. + ((rtx? src) + (let ((evald-src (rtx-eval-with-estate src mode estate))) + ; There must have been some change, otherwise we'll loop forever. + (assert (not (eq? src evald-src))) + (rtl-c-get estate mode evald-src))) + + ((or (and (symbol? src) (current-op-lookup src)) + (operand? src)) + (begin + (if (symbol? src) + (set! src (current-op-lookup src))) + (cond ((mode:eq? 'DFLT mode) + ; FIXME: If we fetch the mode here, operands can assume + ; they never get called with "default mode". + (send src 'cxmake-get estate mode #f #f)) + ((-rtx-mode-compatible? mode (op:mode src)) + (let ((mode (-rtx-lazy-sem-mode mode))) + (send src 'cxmake-get estate mode #f #f))) + (else + (error (string-append "operand " (obj:name src) + " referenced in incompatible mode: ") + (obj:name mode)))))) + + ((or (and (symbol? src) (rtx-temp-lookup (estate-env estate) src)) + (rtx-temp? src)) + (begin + (if (symbol? src) + (set! src (rtx-temp-lookup (estate-env estate) src))) + (cond ((mode:eq? 'DFLT mode) + (send src 'cxmake-get estate (rtx-temp-mode src) #f #f)) + ((-rtx-mode-compatible? mode (rtx-temp-mode src)) + (let ((mode (-rtx-lazy-sem-mode mode))) + (send src 'cxmake-get estate mode #f #f))) + (else (error (string-append "sequence temp " (rtx-temp-name src) + " referenced in incompatible mode: ") + (obj:name mode)))))) + + ((integer? src) + ; Default mode of string argument is INT. + (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode)) + (cx:make INT (number->string src)) + (cx:make mode (number->string src)))) + + ((string? src) + ; Default mode of string argument is INT. + (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode)) + (cx:make INT src) + (cx:make mode src))) + + (else (error "rtl-c-get: invalid argument:" src)))) +) + +; Return a <c-expr> object to set the value of DEST to SRC. +; ESTATE is the current rtl evaluation state. +; DEST is one of: +; - <c-expr> node +; - rtl expression (e.g. '(mem QI dr)) +; SRC is a <c-expr> object. +; The mode of the result is always VOID (void). + +(define (rtl-c-set-quiet estate mode dest src) + ;(display (list 'rtl-c-set-quiet mode dest src)) (newline) + (let ((xdest (cond ((c-expr? dest) + dest) + ((rtx? dest) + (rtx-eval-with-estate dest mode estate)) + (else + (error "rtl-c-set-quiet: invalid dest:" dest))))) + (if (not (object? xdest)) + (error "rtl-c-set-quiet: invalid dest:" dest)) + (let ((mode (if (mode:eq? 'DFLT mode) + (-rtx-obj-mode xdest) + (-rtx-lazy-sem-mode mode)))) + (assert (mode? mode)) + (cx:make VOID (send xdest 'gen-set-quiet + estate mode #f #f + (rtl-c-get estate mode src))))) +) + +; Same as rtl-c-set-quiet except also print TRACE_RESULT message. +; ??? One possible change is to defer the (rtl-c-get src) call to dest's +; set handler. Such sources would be marked accordingly and rtl-c-get +; would recognize them. This would allow, for example, passing the address +; of the result to the computation. + +(define (rtl-c-set-trace estate mode dest src) + ;(display (list 'rtl-c-set-trace mode dest src)) (newline) + (let ((xdest (cond ((c-expr? dest) + dest) + ((rtx? dest) + (rtx-eval-with-estate dest mode estate)) + (else + (error "rtl-c-set-trace: invalid dest:" dest))))) + (if (not (object? xdest)) + (error "rtl-c-set-trace: invalid dest:" dest)) + (let ((mode (if (mode:eq? 'DFLT mode) + (-rtx-obj-mode xdest) ; FIXME: internal routines + (-rtx-lazy-sem-mode mode)))) + (assert (mode? mode)) + (cx:make VOID (send xdest 'gen-set-trace + estate mode #f #f + (rtl-c-get estate mode src))))) +) + +; Emit C code for each rtx function. + +; Table mapping rtx function to C generator. + +(define -rtl-c-gen-table #f) + +; Return the C generator for <rtx-func> F. + +(define (rtl-c-generator f) + (vector-ref -rtl-c-gen-table (rtx-num f)) +) + +; Support for explicit C/C++ code. +; ??? Actually, "support for explicit foreign language code". +; s-c-call needs a better name but "unspec" seems like obfuscation. +; ??? Need to distinguish owner of call (cpu, ???). + +(define (s-c-call estate mode name . args) + (cx:make mode + (string-append + (if (estate-output-language-c++? estate) + (string-append "current_cpu->" name " (") + ; FIXME: Prepend @cpu@_ to name here, and delete @cpu@_ from + ; description file. + (string-append name " (current_cpu")) + (let ((c-args + (string-map (lambda (arg) + (string-append + ", " + (cx:c (rtl-c-get estate DFLT arg)))) + args))) + (if (estate-output-language-c++? estate) + (string-drop 2 c-args) + c-args)) + ; If the mode is VOID, this is a statement. + ; Otherwise it's an expression. + (if (or (mode:eq? 'DFLT mode) + (mode:eq? 'VOID mode)) + ");\n" + ")") + )) +) + +; Same as c-call except there is no particular owner of the call. +; In general this means making a call to a non-member function, +; whereas c-call makes calls to member functions (in C++ parlance). + +(define (s-c-raw-call estate mode name . args) + (cx:make mode + (string-append + name " (" + (string-drop 2 + (string-map (lambda (elm) + (string-append + ", " (cx:c (rtl-c-get estate DFLT elm)))) + args)) + ; If the mode is VOID, this is a statement. + ; Otherwise it's an expression. + (if (or (mode:eq? 'DFLT mode) + (mode:eq? 'VOID mode)) + ");\n" + ")") + )) +) + +; Standard arithmetic operations. + +; Return a boolean indicating if a cover function/macro should be emitted +; to perform an operation. +; C-OP is a string containing the C operation or #f if there is none. +; MODE is the mode of the operation. + +(define (-rtx-use-sem-fn? estate c-op mode) + ; If no C operation has been provided, use a macro, or + ; if this is the simulator and MODE is not a host mode, use a macro. +; (or (not c-op) +; (and (estate-rtl-cover-fns? estate) +; (not (mode:host? mode)))) + ; FIXME: The current definition is a temporary hack while host/target-ness + ; of INT/UINT is unresolved. + (and (not (obj-has-attr? mode 'FORCE-C)) + (or (not c-op) + (and (estate-rtl-cover-fns? estate) + (or (insn? (estate-owner estate)) + (not (mode:host? mode)))))) +) + +; One operand referenced, result is in same mode. + +(define (s-unop estate name c-op mode src) + (let* ((val (rtl-c-get estate mode src)) + ; Refetch mode in case it was DFLT and ensure unsigned->signed. + (mode (cx:mode val)) + (sem-mode (-rtx-sem-mode mode))) + ; FIXME: Argument checking. + + (if (-rtx-use-sem-fn? estate c-op mode) + (if (mode-float? mode) + (cx:make sem-mode + (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->" + (string-downcase name) + (string-downcase (obj:name sem-mode)) + ") (CGEN_CPU_FPU (current_cpu), " + (cx:c val) ")")) + (cx:make sem-mode + (string-append name (obj:name sem-mode) + " (" (cx:c val) ")"))) + (cx:make mode ; not sem-mode on purpose + (string-append "(" c-op " (" + (cx:c val) "))")))) +) + +; Two operands referenced in the same mode producing a result in the same mode. +; If MODE is DFLT, use the mode of SRC1. +; +; ??? Will eventually want to handle floating point modes specially. Since +; bigger modes may get clumsily passed (there is no pass by reference in C) and +; since we want to eventually handle lazy transformation, FP values could be +; passed by reference. This is easy in C++. C requires more work and is +; defered until it's warranted. +; Implementing this should probably be via a new cxmake-get-ref method, +; rather then complicating cxmake-get. Ditto for rtl-c-get-ref/rtl-c-get. + +(define (s-binop estate name c-op mode src1 src2) + (let* ((val1 (rtl-c-get estate mode src1)) + ; Refetch mode in case it was DFLT and ensure unsigned->signed. + (mode (cx:mode val1)) + (sem-mode (-rtx-sem-mode mode)) + (val2 (rtl-c-get estate mode src2))) + ; FIXME: Argument checking. + + (if (-rtx-use-sem-fn? estate c-op mode) + (if (mode-float? mode) + (cx:make sem-mode + (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->" + (string-downcase name) + (string-downcase (obj:name sem-mode)) + ") (CGEN_CPU_FPU (current_cpu), " + (cx:c val1) ", " + (cx:c val2) ")")) + (cx:make sem-mode + (string-append name (obj:name sem-mode) + " (" (cx:c val1) ", " + (cx:c val2) ")"))) + (cx:make mode ; not sem-mode on purpose + (string-append "((" + (cx:c val1) + ") " c-op " (" + (cx:c val2) + "))")))) +) + +; Same as s-binop except there's a third argument which is always one bit. + +(define (s-binop-with-bit estate name mode src1 src2 src3) + (let* ((val1 (rtl-c-get estate mode src1)) + ; Refetch mode in case it was DFLT and ensure unsigned->signed. + (mode (-rtx-sem-mode (cx:mode val1))) + (val2 (rtl-c-get estate mode src2)) + (val3 (rtl-c-get estate 'BI src3))) + ; FIXME: Argument checking. + (cx:make mode + (string-append name (obj:name mode) + " (" + (cx:c val1) ", " + (cx:c val2) ", " + (cx:c val3) + ")"))) +) + +; Shift operations are slightly different than binary operations: +; the mode of src2 is any integral mode. +; ??? Note that some cpus have a signed shift left that is semantically +; different from a logical one. May need to create `sla' some day. Later. + +(define (s-shop estate name c-op mode src1 src2) + (let* ((val1 (rtl-c-get estate mode src1)) + ; Refetch mode in case it was DFLT and ensure unsigned->signed + ; [sign of operation is determined from operation name, not mode]. + (mode (cx:mode val1)) + (sem-mode (-rtx-sem-mode mode)) + (val2 (rtl-c-get estate mode src2))) + ; FIXME: Argument checking. + + (if (-rtx-use-sem-fn? estate c-op mode) + (cx:make sem-mode + (string-append name (obj:name sem-mode) + " (" (cx:c val1) ", " + (cx:c val2) ")")) + (cx:make mode ; not sem-mode on purpose + (string-append "(" + ; Ensure correct sign of shift. + (cond ((equal? name "SRL") + (string-append "(" + (if (eq? (mode:class mode) 'UINT) + "" + "unsigned ") + (mode:non-mode-c-type mode) + ") ")) + ((equal? name "SRA") + (string-append "(" + (mode:non-mode-c-type mode) + ") ")) + (else "")) + "(" (cx:c val1) ") " + c-op + " (" (cx:c val2) "))")))) +) + +; Process andif, orif. +; SRC1 and SRC2 have any arithmetic mode. +; The result has mode BI. +; ??? May want to use INT as BI may introduce some slowness +; in the generated code. + +(define (s-boolifop estate name c-op src1 src2) + (let* ((val1 (rtl-c-get estate DFLT src1)) + (val2 (rtl-c-get estate DFLT src2))) + ; FIXME: Argument checking. + ; If this is the simulator and MODE is not a host mode, use a macro. + ; ??? MODE here being the mode of SRC1. Maybe later. + (if (estate-rtl-cover-fns? estate) + (cx:make (mode:lookup 'BI) + (string-append name ; "BI", leave off mode, no need for it + " (" (cx:c val1) ", " + (cx:c val2) ")")) + (cx:make (mode:lookup 'BI) + (string-append "((" + (cx:c val1) + ") " c-op " (" + (cx:c val2) + "))")))) +) + +; Mode conversions. + +(define (s-convop estate name mode s1) + ; Get S1 in its normal mode, then convert. + (let ((s (rtl-c-get estate DFLT s1)) + (mode (mode:lookup mode))) + (if (and (not (estate-rtl-cover-fns? estate)) + (mode:host? (cx:mode s))) + (cx:make mode + (string-append "((" (obj:name mode) ")" + " (" (obj:name (cx:mode s)) ")" + " (" (cx:c s) "))")) + (if (or (mode-float? mode) + (mode-float? (cx:mode s))) + (cx:make mode + (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->" + (string-downcase name) + (string-downcase (obj:name (-rtx-sem-mode (cx:mode s)))) + (string-downcase (obj:name (-rtx-sem-mode mode))) + ") (CGEN_CPU_FPU (current_cpu), " + (cx:c s) ")")) + (cx:make mode + (string-append name + (obj:name (-rtx-sem-mode (cx:mode s))) + (obj:name (-rtx-sem-mode mode)) + " (" (cx:c s) ")"))))) +) + +; Compare SRC1 and SRC2 in mode MODE. The result has mode BI. +; NAME is one of eq,ne,lt,le,gt,ge,ltu,leu,gtu,geu. +; ??? May want a host int mode result as BI may introduce some slowness +; in the generated code. + +(define (s-cmpop estate name c-op mode src1 src2) + (let* ((val1 (rtl-c-get estate mode src1)) + ; Refetch mode in case it was DFLT. + (mode (cx:mode val1)) + (val2 (rtl-c-get estate mode src2))) + ; FIXME: Argument checking. + + ; If no C operation has been provided, use a macro, or + ; if this is the simulator and MODE is not a host mode, use a macro. + (if (-rtx-use-sem-fn? estate c-op mode) + (if (mode-float? mode) + (cx:make (mode:lookup 'BI) + (string-append "(* CGEN_CPU_FPU (current_cpu)->ops->" + (string-downcase name) + (string-downcase (obj:name (-rtx-sem-mode mode))) + ") (CGEN_CPU_FPU (current_cpu), " + (cx:c val1) ", " + (cx:c val2) ")")) + (cx:make (mode:lookup 'BI) + (string-append (string-upcase name) + (if (memq name '(eq ne)) + (obj:name (-rtx-sem-mode mode)) + (obj:name mode)) + " (" (cx:c val1) ", " + (cx:c val2) ")"))) + (cx:make (mode:lookup 'BI) + (string-append "((" + (cx:c val1) + ") " c-op " (" + (cx:c val2) + "))")))) +) + +; Conditional execution. + +; `if' in RTL has a result, like ?: in C. +; We support both: one with a result (non VOID mode), and one without (VOID mode). +; The non-VOID case must have an else part. +; MODE is the mode of the result, not the comparison. +; The comparison is expected to return a zero/non-zero value. +; ??? Perhaps this should be a syntax-expr. Later. + +(define (s-if estate mode cond then . else) + (if (> (length else) 1) + (error "if: too many elements in `else' part" else)) + (let () + (if (or (mode:eq? 'DFLT mode) + (mode:eq? 'VOID mode)) + (cx:make mode + (string-append "if (" (cx:c (rtl-c-get estate DFLT cond)) ")" + " {\n" (cx:c (rtl-c-get estate mode then)) "}" + (if (not (null? else)) + (string-append " else {\n" + (cx:c (rtl-c-get estate mode (car else))) + "}\n") + "\n") + )) + (if (= (length else) 1) + (cx:make mode + (string-append "((" + (cx:c (rtl-c-get estate DFLT cond)) + ") ? (" + (cx:c (rtl-c-get estate mode then)) + ") : (" + (cx:c (rtl-c-get estate mode (car else))) + "))")) + (error "non-VoidMode `if' must have `else' part")))) +) + +; A multiway `if'. +; If MODE is VOID emit a series of if/else's. +; If MODE is not VOID, emit a series of ?:'s. +; COND-CODE-LIST is a list of lists, each sublist is a list of two elements: +; condition, code. The condition part must return a zero/non-zero value, and +; the code part is treated as a `sequence'. +; This defer argument evaluation, the syntax +; ((... condition ...) ... action ...) +; needs special parsing. +; FIXME: Need more error checking of arguments. + +(define (s-cond estate mode . cond-code-list) + (let ((vm? (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode)))) + (if (null? cond-code-list) + (error "empty `cond'")) + (let ((if-part (if vm? "if (" "(")) + (then-part (if vm? ") " ") ? ")) + (elseif-part (if vm? " else if (" " : (")) + (else-part (if vm? " else " " : ")) + (fi-part (if vm? "" ")"))) + (let loop ((result + (string-append + if-part + (cx:c (rtl-c-get estate DFLT (caar cond-code-list))) + then-part + (cx:c (apply s-sequence + (cons estate + (cons mode + (cons nil + (cdar cond-code-list)))))))) + (ccl (cdr cond-code-list))) + (cond ((null? ccl) (cx:make mode result)) + ((eq? (caar ccl) 'else) + (cx:make mode + (string-append + result + else-part + (cx:c (apply s-sequence + (cons estate + (cons mode + (cons nil + (cdar ccl))))))))) + (else (loop (string-append + result + elseif-part + (cx:c (rtl-c-get estate DFLT (caar ccl))) + then-part + (cx:c (apply s-sequence + (cons estate + (cons mode + (cons nil + (cdar ccl))))))) + (cdr ccl))))))) +) + +; Utility of s-case to print a case prefix (for lack of a better term). + +(define (-gen-case-prefix val) + (string-append " case " + (cond ((number? val) + (number->string val)) + ((symbol? val) + (string-upcase (gen-c-symbol val))) ; yes, upcase + ((string? val) val) + (else + (parse-error "case:" "bad case" val))) + " : ") +) + +; Utility of s-case to handle a void result. + +(define (s-case-vm estate test case-list) + (cx:make + VOID + (string-append + " switch (" + (cx:c (rtl-c-get estate DFLT test)) + ")\n" + " {\n" + (string-map (lambda (case-entry) + (let ((caseval (car case-entry)) + (code (cdr case-entry))) + (string-append + (cond ((list? caseval) + (string-map -gen-case-prefix caseval)) + ((eq? 'else caseval) + (string-append " default : ")) + (else + (-gen-case-prefix caseval))) + (cx:c (apply s-sequence + (cons estate (cons VOID (cons nil code))))) + " break;\n"))) + case-list) + " }\n")) +) + +; Utility of s-case-non-vm to generate code to perform the test. + +(define (-gen-non-vm-case-test estate mode test cases) + (assert (not (null? cases))) + (let loop ((result "") (cases cases)) + (if (null? cases) + result + (let ((case (cond ((number? (car cases)) + (car cases)) + ((symbol? (car cases)) + (if (enum-lookup-val (car cases)) + (rtx-make 'enum mode (car cases)) + (context-error (estate-context estate) + "symbol not an enum" + (car cases)))) + (else (error "invalid case" (car cases)))))) + (loop (string-append + result + (if (= (string-length result) 0) + "" + " || ") + (cx:c (rtl-c-get estate mode test)) + " == " + (cx:c (rtl-c-get estate mode case))) + (cdr cases))))) +) + +; Utility of s-case to handle a non-void result. +; This is expanded as a series of ?:'s. + +(define (s-case-non-vm estate mode test case-list) + (let ((if-part "(") + (then-part ") ? ") + (elseif-part " : (") + (else-part " : ") + (fi-part ")")) + (let loop ((result + (string-append + if-part + (-gen-non-vm-case-test estate mode test (caar case-list)) + then-part + (cx:c (apply s-sequence + (cons estate + (cons mode + (cons nil + (cdar case-list)))))))) + (cl (cdr case-list))) + (cond ((null? cl) (cx:make mode result)) + ((eq? (caar cl) 'else) + (cx:make mode + (string-append + result + else-part + (cx:c (apply s-sequence + (cons estate + (cons mode + (cons nil + (cdar cl))))))))) + (else (loop (string-append + result + elseif-part + (-gen-non-vm-case-test estate mode test (caar cl)) + then-part + (cx:c (apply s-sequence + (cons estate + (cons mode + (cons nil + (cdar cl))))))) + (cdr cl)))))) +) + +; C switch statement +; To follow convention, MODE is the first arg. +; FIXME: What to allow for case choices is wip. + +(define (s-case estate mode test . case-list) + (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode)) + (s-case-vm estate test case-list) + (s-case-non-vm estate mode test case-list)) +) + +; Parallels and Sequences + +; Temps for `parallel' are recorded differently than for `sequence'. +; ??? I believe this is because there was an interaction between the two. + +(define -par-temp-list nil) + +; Record a temporary needed for a parallel in mode MODE. +; We just need to record the mode with a unique name so we use a <c-expr> +; object where the "expression" is the variable's name. + +(define (-par-new-temp! mode) + (set! -par-temp-list + (cons (cx:make mode (string-append "temp" + (number->string + (length -par-temp-list)))) + -par-temp-list)) + (car -par-temp-list) +) + +; Return the next temp from the list, and leave the list pointing to the +; next one. + +(define (-par-next-temp!) + (let ((result (car -par-temp-list))) + (set! -par-temp-list (cdr -par-temp-list)) + result) +) + +(define (-gen-par-temp-defns temp-list) + ;(display temp-list) (newline) + (string-append + " " + ; ??? mode:c-type + (string-map (lambda (temp) (string-append (obj:name (cx:mode temp)) " " (cx:c temp) ";")) + temp-list) + "\n") +) + +; Parallels are handled by converting them into two sequences. The first has +; all set destinations replaced with temps, and the second has all set sources +; replaced with those temps. +; ??? Revisit later to see if (if ...) and (set pc ...) is ok. +; How about disallowing if's and jump's inside parallels? +; One can still put a parallel inside an `if' however. + +(define (-par-replace-set-dests estate exprs) + (let ((sets (list 'set 'set-quiet + (rtx-lookup 'set) (rtx-lookup 'set-quiet)))) + (letrec ((replace + (lambda (expr) + (let ((name (car expr)) + (options (rtx-options expr)) + (mode (rtx-mode expr))) + (if (memq name sets) + (list name + options + mode + (-par-new-temp! ; replace dest with temp + (if (mode:eq? 'DFLT mode) + (rtx-lvalue-mode-name estate (rtx-set-dest expr)) + mode)) + (rtx-set-src expr)) + (cons name + (cons options + (cons mode (replace (rtx-args expr))))))))) + ) + (map replace exprs))) +) + +; This must process expressions in the same order as -par-replace-set-dests! + +(define (-par-replace-set-srcs estate exprs) + (let ((sets (list 'set 'set-quiet + (rtx-lookup 'set) (rtx-lookup 'set-quiet)))) + (letrec ((replace + (lambda (expr) + (let ((name (car expr)) + (options (rtx-options expr)) + (mode (rtx-mode expr))) + (if (memq name sets) + (list name + options + mode + (rtx-set-dest expr) + (-par-next-temp!)) ; the source's temp + (cons name + (cons options + (cons mode (replace (cddr expr))))))))) + ) + (map replace exprs))) +) + +; Return a <c-expr> node for a `parallel'. + +(define (s-parallel estate . exprs) + (begin + ; Initialize -par-temp-list for -par-replace-set-dests. + (set! -par-temp-list nil) + (let* ((set-dests (string-map (lambda (e) + (rtl-c-with-estate estate VOID e)) + (-par-replace-set-dests estate exprs))) + (temps (reverse! -par-temp-list))) + ; Initialize -par-temp-list for -par-replace-set-srcs. + (set! -par-temp-list temps) + (cx:make VOID + (string-append + ; FIXME: do {} while (0); doesn't get "optimized out" + ; internally by gcc, meaning two labels and a loop are + ; created for it to have to process. We can generate pretty + ; big files and can cause gcc to require *lots* of memory. + ; So let's try just {} ... + "{\n" + (-gen-par-temp-defns temps) + set-dests + (string-map (lambda (e) + (rtl-c-with-estate estate VOID e)) + (-par-replace-set-srcs estate exprs)) + "}\n") + ))) +) + +; Return a <c-expr> node for a `sequence'. + +(define (s-sequence estate mode env . exprs) + (let* ((env (rtx-env-make-locals env)) ; compile env + (estate (estate-push-env estate env))) + (if (or (mode:eq? 'DFLT mode) + (mode:eq? 'VOID mode)) + (cx:make mode + (string-append + ; FIXME: do {} while (0); doesn't get "optimized out" + ; internally by gcc, meaning two labels and a loop are + ; created for it to have to process. We can generate pretty + ; big files and can cause gcc to require *lots* of memory. + ; So let's try just {} ... + "{\n" + (gen-temp-defs estate env) + (string-map (lambda (e) + (rtl-c-with-estate estate DFLT e)) + exprs) + "}\n")) + (cx:make mode + (string-append + ; Don't use GCC extension unless necessary. + (if (rtx-env-empty? env) "(" "({ ") + (gen-temp-defs estate env) + (string-drop 2 + (string-map + (lambda (e) + (string-append + ", " + (rtl-c-with-estate estate DFLT e))) + exprs)) + (if (rtx-env-empty? env) ")" "; })"))))) +) + +; ***************************************************************************** +; +; RTL->C generators for each rtx function. + +; Return code to set FN as the generator for RTX. + +(defmacro define-fn (rtx args expr . rest) + `(begin + (assert (rtx-lookup (quote ,rtx))) + (vector-set! table (rtx-num (rtx-lookup (quote ,rtx))) + (lambda ,args ,@(cons expr rest)))) +) + +(define (rtl-c-init!) + (set! -rtl-c-gen-table (rtl-c-build-table)) + *UNSPECIFIED* +) + +; The rest of this file is one big function to return the rtl->c lookup table. + +(define (rtl-c-build-table) + (let ((table (make-vector (rtx-max-num) #f))) + +; Error generation + +(define-fn error (estate options mode message) + (let ((c-call (s-c-call estate mode "cgen_rtx_error" + (string-append "\"" + (backslash "\"" message) + "\"")))) + (if (or (mode:eq? 'DFLT mode) (mode:eq? 'VOID mode)) + c-call + (cx:make mode (string-append "(" (cx:c c-call) ", 0)")))) +) + +; Enum support + +(define-fn enum (estate options mode name) + (cx:make mode (string-upcase (gen-c-symbol name))) +) + +; Instruction field support. +; ??? This should build an operand object like -build-ifield-operand! does +; in semantics.scm. +; ??? Mode support is wip. + +(define-fn ifield (estate options mode ifld-name) + (if (estate-ifield-var? estate) + (cx:make 'UINT (gen-c-symbol ifld-name)) + (cx:make 'UINT (string-append "FLD (" (gen-c-symbol ifld-name) ")"))) +; (let ((f (current-ifld-lookup ifld-name))) +; (make <operand> ifld-name ifld-name +; (atlist-cons (bool-attr-make 'SEM-ONLY #t) +; (obj-atlist f)) +; (obj:name (ifld-hw-type f)) +; (obj:name (ifld-mode f)) +; (make <hw-index> 'anonymous +; 'ifield (ifld-mode f) f) +; nil #f #f)) +) + +; Operand support + +(define-fn operand (estate options mode object-or-name) + (cond ((operand? object-or-name) + object-or-name) + ((symbol? object-or-name) + (let ((object (current-op-lookup object-or-name))) + (if (not object) + (context-error (estate-context estate) + "undefined operand" object-or-name)) + object)) + (else + (context-error (estate-context estate) + "bad arg to `operand'" object-or-name))) +) + +(define-fn xop (estate options mode object) object) + +(define-fn local (estate options mode object-or-name) + (cond ((rtx-temp? object-or-name) + object-or-name) + ((symbol? object-or-name) + (let ((object (rtx-temp-lookup (estate-env estate) object-or-name))) + (if (not object) + (context-error (estate-context estate) + "undefined local" object-or-name)) + object)) + (else + (context-error (estate-context estate) + "bad arg to `local'" object-or-name))) +) + +(define-fn reg (estate options mode hw-elm . indx-sel) + (let ((indx (or (list-maybe-ref indx-sel 0) 0)) + (sel (or (list-maybe-ref indx-sel 1) hw-selector-default))) + (s-hw estate mode hw-elm indx sel)) +) + +(define-fn raw-reg (estate options mode hw-elm . indx-sel) + (let ((indx (or (list-maybe-ref indx-sel 0) 0)) + (sel (or (list-maybe-ref indx-sel 1) hw-selector-default))) + (let ((result (s-hw estate mode hw-elm indx sel))) + (obj-cons-attr! result (bool-attr-make 'RAW #t)) + result)) +) + +(define-fn mem (estate options mode addr . sel) + (s-hw estate mode 'h-memory addr + (if (pair? sel) (car sel) hw-selector-default)) +) + +(define-fn pc (estate options mode) + s-pc +) + +(define-fn ref (estate options mode name) + (if (not (insn? (estate-owner estate))) + (error "ref: not processing an insn")) + (cx:make 'UINT + (string-append + "(referenced & (1 << " + (number->string + (op:num (insn-lookup-op (estate-owner estate) name))) + "))")) +) + +; ??? Maybe this should return an operand object. +(define-fn index-of (estate options mode op) + (send (op:index (rtx-eval-with-estate op 'DFLT estate)) 'cxmake-get estate 'DFLT) +) + +(define-fn clobber (estate options mode object) + (cx:make VOID "; /*clobber*/\n") +) + +(define-fn delay (estate options mode n rtx) + (s-sequence (estate-with-modifiers estate '((#:delay))) VOID '() rtx) ; wip! +) + +; Gets expanded as a macro. +;(define-fn annul (estate yes?) +; (s-c-call estate 'VOID "SEM_ANNUL_INSN" "pc" yes?) +;) + +(define-fn skip (estate options mode yes?) + (send pc 'cxmake-skip estate yes?) + ;(s-c-call estate 'VOID "SEM_SKIP_INSN" "pc" yes?) +) + +(define-fn eq-attr (estate options mode obj attr-name value) + (cx:make 'INT + (string-append "(GET_ATTR (" + (gen-c-symbol attr-name) + ") == " + (gen-c-symbol value) + ")")) +) + +(define-fn attr (estate options mode owner attr-name) + (cond ((equal? owner '(current-insn () DFLT)) + (s-c-raw-call estate 'INT "GET_ATTR" + (string-upcase (gen-c-symbol attr-name)))) + (else (error "attr: unsupported object type:" owner))) +) + +(define-fn const (estate options mode c) + (assert (not (mode:eq? 'VOID mode))) + (if (mode:eq? 'DFLT mode) + (set! mode 'INT)) + (let ((mode (mode:lookup mode))) + (cx:make mode + (cond ((or (mode:eq? 'DI mode) + (mode:eq? 'UDI mode)) + (string-append "MAKEDI (" + (gen-integer (high-part c)) ", " + (gen-integer (low-part c)) + ")")) + ((and (<= #x-80000000 c) (> #x80000000 c)) + (number->string c)) + ((and (<= #x80000000 c) (>= #xffffffff c)) + ; ??? GCC complains if not affixed with "U" but that's not k&r. + ;(string-append (number->string val) "U")) + (string-append "0x" (number->string c 16))) + ; Else punt. + (else (number->string c))))) +) + +(define-fn join (estate options out-mode in-mode arg1 . arg-rest) + ; FIXME: Endianness issues undecided. + ; FIXME: Ensure correct number of args for in/out modes. + ; Ensure compatible modes. + (apply s-c-raw-call (cons estate + (cons out-mode + (cons (string-append "JOIN" + in-mode + out-mode) + (cons arg1 arg-rest))))) +) + +(define-fn subword (estate options mode value word-num) + (let* ((mode (mode:lookup mode)) + (val (rtl-c-get estate DFLT value)) + ; Refetch mode in case it was DFLT. + (val-mode (cx:mode val))) + (cx:make mode + (string-append "SUBWORD" (obj:name val-mode) (obj:name mode) + " (" (cx:c val) + (if (mode-bigger? val-mode mode) + (string-append + ", " + (if (number? word-num) + (number->string word-num) + (cx:c (rtl-c-get estate DFLT word-num)))) + "") + ")"))) +) + +(define-fn c-code (estate options mode text) + (cx:make mode text) +) + +(define-fn c-call (estate options mode name . args) + (apply s-c-call (cons estate (cons mode (cons name args)))) +) + +(define-fn c-raw-call (estate options mode name . args) + (apply s-c-raw-call (cons estate (cons mode (cons name args)))) +) + +(define-fn nop (estate options mode) + (cx:make VOID "((void) 0); /*nop*/\n") +) + +(define-fn set (estate options mode dst src) + (if (insn? (estate-owner estate)) + (rtl-c-set-trace estate mode dst (rtl-c-get estate mode src)) + (rtl-c-set-quiet estate mode dst (rtl-c-get estate mode src))) +) + +(define-fn set-quiet (estate options mode dst src) + (rtl-c-set-quiet estate mode dst (rtl-c-get estate mode src)) +) + +(define-fn neg (estate options mode s1) + (s-unop estate "NEG" "-" mode s1) +) + +(define-fn abs (estate options mode s1) + (s-unop estate "ABS" #f mode s1) +) + +(define-fn inv (estate options mode s1) + (s-unop estate "INV" "~" mode s1) +) + +(define-fn not (estate options mode s1) + (s-unop estate "NOT" "!" mode s1) +) + +(define-fn add (estate options mode s1 s2) + (s-binop estate "ADD" "+" mode s1 s2) +) +(define-fn sub (estate options mode s1 s2) + (s-binop estate "SUB" "-" mode s1 s2) +) + +(define-fn addc (estate options mode s1 s2 s3) + (s-binop-with-bit estate "ADDC" mode s1 s2 s3) +) +(define-fn add-cflag (estate options mode s1 s2 s3) + (s-binop-with-bit estate "ADDCF" mode s1 s2 s3) +) +(define-fn add-oflag (estate options mode s1 s2 s3) + (s-binop-with-bit estate "ADDOF" mode s1 s2 s3) +) +(define-fn subc (estate options mode s1 s2 s3) + (s-binop-with-bit estate "SUBC" mode s1 s2 s3) +) +(define-fn sub-cflag (estate options mode s1 s2 s3) + (s-binop-with-bit estate "SUBCF" mode s1 s2 s3) +) +(define-fn sub-oflag (estate options mode s1 s2 s3) + (s-binop-with-bit estate "SUBOF" mode s1 s2 s3) +) + +;(define-fn zflag (estate options mode value) +; (list 'eq mode value (list 'const mode 0)) +;) + +;(define-fn nflag (estate options mode value) +; (list 'lt mode value (list 'const mode 0)) +;) + +(define-fn mul (estate options mode s1 s2) + (s-binop estate "MUL" "*" mode s1 s2) +) +(define-fn div (estate options mode s1 s2) + (s-binop estate "DIV" "/" mode s1 s2) +) +(define-fn udiv (estate options mode s1 s2) + (s-binop estate "UDIV" "/" mode s1 s2) +) +(define-fn mod (estate options mode s1 s2) + (s-binop estate "MOD" "%" mode s1 s2) +) +(define-fn umod (estate options mode s1 s2) + (s-binop estate "UMOD" "%" mode s1 s2) +) + +(define-fn sqrt (estate options mode s1) + (s-unop estate "SQRT" #f mode s1) +) +(define-fn cos (estate options mode s1) + (s-unop estate "COS" #f mode s1) +) +(define-fn sin (estate options mode s1) + (s-unop estate "SIN" #f mode s1) +) + +(define-fn min (estate options mode s1 s2) + (s-binop estate "MIN" #f mode s1 s2) +) +(define-fn max (estate options mode s1 s2) + (s-binop estate "MAX" #f mode s1 s2) +) +(define-fn umin (estate options mode s1 s2) + (s-binop estate "UMIN" #f mode s1 s2) +) +(define-fn umax (estate options mode s1 s2) + (s-binop estate "UMAX" #f mode s1 s2) +) + +(define-fn and (estate options mode s1 s2) + (s-binop estate "AND" "&" mode s1 s2) +) +(define-fn or (estate options mode s1 s2) + (s-binop estate "OR" "|" mode s1 s2) +) +(define-fn xor (estate options mode s1 s2) + (s-binop estate "XOR" "^" mode s1 s2) +) + +(define-fn sll (estate options mode s1 s2) + (s-shop estate "SLL" "<<" mode s1 s2) +) +(define-fn srl (estate options mode s1 s2) + (s-shop estate "SRL" ">>" mode s1 s2) +) +(define-fn sra (estate options mode s1 s2) + (s-shop estate "SRA" ">>" mode s1 s2) +) +(define-fn ror (estate options mode s1 s2) + (s-shop estate "ROR" #f mode s1 s2) +) +(define-fn rol (estate options mode s1 s2) + (s-shop estate "ROL" #f mode s1 s2) +) + +(define-fn andif (estate options mode s1 s2) + (s-boolifop estate "ANDIF" "&&" s1 s2) +) +(define-fn orif (estate options mode s1 s2) + (s-boolifop estate "ORIF" "||" s1 s2) +) + +(define-fn ext (estate options mode s1) + (s-convop estate "EXT" mode s1) +) +(define-fn zext (estate options mode s1) + (s-convop estate "ZEXT" mode s1) +) +(define-fn trunc (estate options mode s1) + (s-convop estate "TRUNC" mode s1) +) +(define-fn fext (estate options mode s1) + (s-convop estate "FEXT" mode s1) +) +(define-fn ftrunc (estate options mode s1) + (s-convop estate "FTRUNC" mode s1) +) +(define-fn float (estate options mode s1) + (s-convop estate "FLOAT" mode s1) +) +(define-fn ufloat (estate options mode s1) + (s-convop estate "UFLOAT" mode s1) +) +(define-fn fix (estate options mode s1) + (s-convop estate "FIX" mode s1) +) +(define-fn ufix (estate options mode s1) + (s-convop estate "UFIX" mode s1) +) + +(define-fn eq (estate options mode s1 s2) + (s-cmpop estate 'eq "==" mode s1 s2) +) +(define-fn ne (estate options mode s1 s2) + (s-cmpop estate 'ne "!=" mode s1 s2) +) + +(define-fn lt (estate options mode s1 s2) + (s-cmpop estate 'lt "<" mode s1 s2) +) +(define-fn le (estate options mode s1 s2) + (s-cmpop estate 'le "<=" mode s1 s2) +) +(define-fn gt (estate options mode s1 s2) + (s-cmpop estate 'gt ">" mode s1 s2) +) +(define-fn ge (estate options mode s1 s2) + (s-cmpop estate 'ge ">=" mode s1 s2) +) + +(define-fn ltu (estate options mode s1 s2) + (s-cmpop estate 'ltu "<" mode s1 s2) +) +(define-fn leu (estate options mode s1 s2) + (s-cmpop estate 'leu "<=" mode s1 s2) +) +(define-fn gtu (estate options mode s1 s2) + (s-cmpop estate 'gtu ">" mode s1 s2) +) +(define-fn geu (estate options mode s1 s2) + (s-cmpop estate 'geu ">=" mode s1 s2) +) + +(define-fn member (estate options mode value set) + ; FIXME: Multiple evalutions of VALUE. + (let ((c-value (rtl-c-get estate 'DFLT value)) + (set (rtx-number-list-values set))) + (let loop ((set (cdr set)) + (code (string-append "(" (cx:c c-value) + " == " + (gen-integer (car set)) + ")"))) + (if (null? set) + (cx:make (mode:lookup 'BI) (string-append "(" code ")")) + (loop (cdr set) + (string-append code + " || (" + (cx:c c-value) + " == " + (gen-integer (car set)) + ")"))))) +) + +(define-fn if (estate options mode cond then . else) + (apply s-if (append! (list estate mode cond then) else)) +) + +(define-fn cond (estate options mode . cond-code-list) + (apply s-cond (cons estate (cons mode cond-code-list))) +) + +(define-fn case (estate options mode test . case-list) + (apply s-case (cons estate (cons mode (cons test case-list)))) +) + +(define-fn parallel (estate options mode ignore expr . exprs) + (apply s-parallel (cons estate (cons expr exprs))) +) + +(define-fn sequence (estate options mode locals expr . exprs) + (apply s-sequence + (cons estate (cons mode (cons locals (cons expr exprs))))) +) + +(define-fn closure (estate options mode expr env) + ; ??? estate-push-env? + (rtl-c-with-estate (estate-new-env estate env) DFLT expr) +) + +; The result is the rtl->c generator table. +table +)) ; End of rtl-c-build-table |