From 145787f5bde62a3b2a986f10f568cf27ec9f2db8 Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Sun, 22 Apr 2012 20:03:52 +0200 Subject: [PATCH 1/1] Initial commit: 0.4.3.0 from hackage --- COPYING | 340 +++ Harpy.hs | 22 + Harpy/Call.hs | 35 + Harpy/CodeGenMonad.hs | 588 ++++ Harpy/X86Assembler.hs | 4168 +++++++++++++++++++++++++++++ Harpy/X86CGCombinators.hs | 266 ++ Harpy/X86CodeGen.hs | 2184 +++++++++++++++ Harpy/X86Disassembler.hs | 32 + Makefile | 24 + NEWS | 93 + README | 65 + Setup.hs | 2 + doc/Makefile | 18 + doc/larger-tutorial.lhs | 312 +++ doc/tutorial.lhs | 199 ++ examples/evaluator/ArithParser.hs | 73 + examples/evaluator/ArithTypes.hs | 22 + examples/evaluator/Evaluator.hs | 118 + harpy.cabal | 67 + 19 files changed, 8628 insertions(+) create mode 100644 COPYING create mode 100644 Harpy.hs create mode 100644 Harpy/Call.hs create mode 100644 Harpy/CodeGenMonad.hs create mode 100644 Harpy/X86Assembler.hs create mode 100644 Harpy/X86CGCombinators.hs create mode 100644 Harpy/X86CodeGen.hs create mode 100644 Harpy/X86Disassembler.hs create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100644 Setup.hs create mode 100644 doc/Makefile create mode 100644 doc/larger-tutorial.lhs create mode 100644 doc/tutorial.lhs create mode 100644 examples/evaluator/ArithParser.hs create mode 100644 examples/evaluator/ArithTypes.hs create mode 100644 examples/evaluator/Evaluator.hs create mode 100644 harpy.cabal diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Harpy.hs b/Harpy.hs new file mode 100644 index 0000000..89e58cd --- /dev/null +++ b/Harpy.hs @@ -0,0 +1,22 @@ +-------------------------------------------------------------------------- +-- | +-- Module: Harpy +-- Copyright: (c) 2006-2007 Martin Grabmueller and Dirk Kleeblatt +-- License: GPL +-- +-- Maintainer: {magr,klee}@cs.tu-berlin.de +-- Stability: provisional +-- Portability: portable +-- +-- Harpy is a library for run-time code generation of x86 machine code. +-- +-- This is a convenience module which re-exports the modules which are +-- essential for using Harpy. +---------------------------------------------------------------------------- +module Harpy(module Harpy.CodeGenMonad, + module Harpy.Call, + module Harpy.X86Assembler) where + +import Harpy.CodeGenMonad +import Harpy.Call +import Harpy.X86Assembler diff --git a/Harpy/Call.hs b/Harpy/Call.hs new file mode 100644 index 0000000..76d4af5 --- /dev/null +++ b/Harpy/Call.hs @@ -0,0 +1,35 @@ +{-# OPTIONS -cpp #-} + +-------------------------------------------------------------------------- +-- | +-- Module : Harpy.Call +-- Copyright : (c) 2006-2007 Martin Grabmueller and Dirk Kleeblatt +-- License : GPL +-- +-- Maintainer : {magr,klee}@cs.tu-berlin.de +-- Stability : provisional +-- Portability : non-portable +-- +-- Predefined call stubs for run-time generated code. +-------------------------------------------------------------------------- + +module Harpy.Call where + +import Harpy.CodeGenMonad + +import Data.Word +import Foreign.Ptr + +#ifndef __HADDOCK__ + +$(callDecl "callAsVoid" [t|()|]) +$(callDecl "callAsWord32ToWord32" [t|Word32 -> Word32|]) +$(callDecl "callAs7PtrToVoid" [t|forall a b c d e f g . Ptr a -> Ptr b -> Ptr c -> Ptr d -> Ptr e -> Ptr f -> Ptr g -> () |]) + +#else + +callAsVoid :: CodeGen e s () +callAsWord32ToWord32 :: Word32 -> CodeGen e s Word32 +callAs7PtrToVoid :: forall a b c d e f g e' s'. Ptr a -> Ptr b -> Ptr c -> Ptr d -> Ptr e -> Ptr f -> Ptr g -> CodeGen e' s' () + +#endif diff --git a/Harpy/CodeGenMonad.hs b/Harpy/CodeGenMonad.hs new file mode 100644 index 0000000..20e81dd --- /dev/null +++ b/Harpy/CodeGenMonad.hs @@ -0,0 +1,588 @@ +{-# OPTIONS -cpp #-} + +-------------------------------------------------------------------------- +-- | +-- Module: Harpy.CodeGenMonad +-- Copyright: (c) 2006-2007 Martin Grabmueller and Dirk Kleeblatt +-- License: GPL +-- +-- Maintainer: {magr,klee}@cs.tu-berlin.de +-- Stability: provisional +-- Portability: portable (but generated code non-portable) +-- +-- Monad for generating x86 machine code at runtime. +-- +-- This is a combined reader-state-exception monad which handles all +-- the details of handling code buffers, emitting binary data, +-- relocation etc. +-- +-- All the code generation functions in module "Harpy.X86CodeGen" live +-- in this monad and use its error reporting facilities as well as the +-- internal state maintained by the monad. +-- +-- The library user can pass a user environment and user state through +-- the monad. This state is independent from the internal state and +-- may be used by higher-level code generation libraries to maintain +-- their own state across code generation operations. +-- -------------------------------------------------------------------------- + +module Harpy.CodeGenMonad( + -- * Types + CodeGen, + ErrMsg, + RelocKind(..), + Reloc, + Label, + FixupKind(..), + CodeGenConfig(..), + defaultCodeGenConfig, + -- * Functions + -- ** General code generator monad operations + failCodeGen, + -- ** Accessing code generation internals + getEntryPoint, + getCodeOffset, + getBasePtr, + getCodeBufferList, + -- ** Access to user state and environment + setState, + getState, + getEnv, + withEnv, + -- ** Label management + newLabel, + newNamedLabel, + setLabel, + defineLabel, + (@@), + emitFixup, + labelAddress, + emitRelocInfo, + -- ** Code emission + emit8, + emit8At, + peek8At, + emit32, + emit32At, + checkBufferSize, + ensureBufferSize, + -- ** Executing code generation + runCodeGen, + runCodeGenWithConfig, + -- ** Calling generated functions + callDecl, + -- ** Interface to disassembler + disassemble + ) where + +import qualified Harpy.X86Disassembler as Dis + +import Control.Monad + +import Text.PrettyPrint.HughesPJ + +import Numeric + +import Data.List +import qualified Data.Map as Map +import Foreign +import System.IO + +import Control.Monad.Trans + +import Language.Haskell.TH.Syntax + + +-- | An error message produced by a code generation operation. +type ErrMsg = Doc + +-- | The code generation monad, a combined reader-state-exception +-- monad. +newtype CodeGen e s a = CodeGen ((e, CodeGenEnv) -> (s, CodeGenState) -> IO ((s, CodeGenState), Either ErrMsg a)) + +-- | Configuration of the code generator. There are currently two +-- configuration options. The first is the number fo bytes to use for +-- allocating code buffers (the first as well as additional buffers +-- created in calls to 'ensureBufferSize'. The second allows to pass +-- in a pre-allocated code buffer and its size. When this option is +-- used, Harpy does not perform any code buffer resizing (calls to +-- 'ensureBufferSize' will be equivalent to calls to +-- 'checkBufferSize'). +data CodeGenConfig = CodeGenConfig { + codeBufferSize :: Int, -- ^ Size of individual code buffer blocks. + customCodeBuffer :: Maybe (Ptr Word8, Int) -- ^ Code buffer passed in. + } + +-- | Internal state of the code generator +data CodeGenState = CodeGenState { + buffer :: Ptr Word8, -- ^ Pointer to current code buffer. + bufferList :: [(Ptr Word8, Int)], -- ^ List of all other code buffers. + firstBuffer :: Ptr Word8, -- ^ Pointer to first buffer. + bufferOfs :: Int, -- ^ Current offset into buffer where next instruction will be stored. + bufferSize :: Int, -- ^ Size of current buffer. + relocEntries :: [Reloc], -- ^ List of all emitted relocation entries. + nextLabel :: Int, -- ^ Counter for generating labels. + definedLabels :: Map.Map Int (Ptr Word8, Int, String), -- ^ Map of already defined labels. + pendingFixups :: Map.Map Int [FixupEntry], -- ^ Map of labels which have been referenced, but not defined. + config :: CodeGenConfig -- ^ Configuration record. + } + +data FixupEntry = FixupEntry { + fueBuffer :: Ptr Word8, + fueOfs :: Int, + fueKind :: FixupKind + } + +-- | Kind of a fixup entry. When a label is emitted with +-- 'defineLabel', all prior references to this label must be fixed +-- up. This data type tells how to perform the fixup operation. +data FixupKind = Fixup8 -- ^ 8-bit relative reference + | Fixup16 -- ^ 16-bit relative reference + | Fixup32 -- ^ 32-bit relative reference + | Fixup32Absolute -- ^ 32-bit absolute reference + deriving (Show) + +data CodeGenEnv = CodeGenEnv { tailContext :: Bool } + deriving (Show) + +-- | Kind of relocation, for example PC-relative +data RelocKind = RelocPCRel -- ^ PC-relative relocation + | RelocAbsolute -- ^ Absolute address + deriving (Show) + +-- | Relocation entry +data Reloc = Reloc { offset :: Int, + -- ^ offset in code block which needs relocation + kind :: RelocKind, + -- ^ kind of relocation + address :: FunPtr () + -- ^ target address + } + deriving (Show) + +-- | Label +data Label = Label Int String + deriving (Eq, Ord) + +unCg :: CodeGen e s a -> ((e, CodeGenEnv) -> (s, CodeGenState) -> IO ((s, CodeGenState), Either ErrMsg a)) +unCg (CodeGen a) = a + +instance Monad (CodeGen e s) where + return x = cgReturn x + fail err = cgFail err + m >>= k = cgBind m k + +cgReturn :: a -> CodeGen e s a +cgReturn x = CodeGen (\_env state -> return (state, Right x)) + +cgFail :: String -> CodeGen e s a +cgFail err = CodeGen (\_env state -> return (state, Left (text err))) + +cgBind :: CodeGen e s a -> (a -> CodeGen e s a1) -> CodeGen e s a1 +cgBind m k = CodeGen (\env state -> + do r1 <- unCg m env state + case r1 of + (state', Left err) -> return (state', Left err) + (state', Right v) -> unCg (k v) env state') + +-- | Abort code generation with the given error message. +failCodeGen :: Doc -> CodeGen e s a +failCodeGen d = CodeGen (\_env state -> return (state, Left d)) + +instance MonadIO (CodeGen e s) where + liftIO st = CodeGen (\_env state -> do { r <- st; return (state, Right r) }) + +emptyCodeGenState :: CodeGenState +emptyCodeGenState = CodeGenState { buffer = undefined, + bufferList = [], + firstBuffer = undefined, + bufferOfs = 0, + bufferSize = 0, + relocEntries = [], + nextLabel = 0, + definedLabels = Map.empty, + pendingFixups = Map.empty, + config = defaultCodeGenConfig} + +-- | Default code generation configuration. The code buffer size is +-- set to 4KB, and code buffer management is automatic. This value is +-- intended to be used with record update syntax, for example: +-- +-- > runCodeGenWithConfig ... defaultCodeGenConfig{codeBufferSize = 128} ... +defaultCodeGenConfig :: CodeGenConfig +defaultCodeGenConfig = CodeGenConfig { codeBufferSize = defaultCodeBufferSize, + customCodeBuffer = Nothing } + +defaultCodeBufferSize :: Int +defaultCodeBufferSize = 4096 + +-- | Execute code generation, given a user environment and state. The +-- result is a tuple of the resulting user state and either an error +-- message (when code generation failed) or the result of the code +-- generation. This function runs 'runCodeGenWithConfig' with a +-- sensible default configuration. +runCodeGen :: CodeGen e s a -> e -> s -> IO (s, Either ErrMsg a) +runCodeGen cg uenv ustate = + runCodeGenWithConfig cg uenv ustate defaultCodeGenConfig + +-- | Like 'runCodeGen', but allows more control over the code +-- generation process. In addition to a code generator and a user +-- environment and state, a code generation configuration must be +-- provided. A code generation configuration allows control over the +-- allocation of code buffers, for example. +runCodeGenWithConfig :: CodeGen e s a -> e -> s -> CodeGenConfig -> IO (s, Either ErrMsg a) +runCodeGenWithConfig (CodeGen cg) uenv ustate conf = + do (buf, sze) <- case customCodeBuffer conf of + Nothing -> do let initSize = codeBufferSize conf + arr <- mallocBytes initSize + return (arr, initSize) + Just (buf, sze) -> return (buf, sze) + let env = CodeGenEnv {tailContext = True} + let state = emptyCodeGenState{buffer = buf, + bufferList = [], + firstBuffer = buf, + bufferSize = sze, + config = conf} + ((ustate', _), res) <- cg (uenv, env) (ustate, state) + return (ustate', res) + +-- | Check whether the code buffer has room for at least the given +-- number of bytes. This should be called by code generators +-- whenever it cannot be guaranteed that the code buffer is large +-- enough to hold all the generated code. Lets the code generation +-- monad fail when the buffer overflows. +-- +-- /Note:/ Starting with version 0.4, Harpy automatically checks for +-- buffer overflow, so you do not need to call this function anymore. +checkBufferSize :: Int -> CodeGen e s () +checkBufferSize needed = + do state <- getInternalState + unless (bufferOfs state + needed <= bufferSize state) + (failCodeGen (text "code generation buffer overflow: needed additional" <+> + int needed <+> text "bytes (offset =" <+> + int (bufferOfs state) <> + text ", buffer size =" <+> + int (bufferSize state) <> text ")")) + +-- | Make sure that the code buffer has room for at least the given +-- number of bytes. This should be called by code generators whenever +-- it cannot be guaranteed that the code buffer is large enough to +-- hold all the generated code. Creates a new buffer and places a +-- jump to the new buffer when there is not sufficient space +-- available. When code generation was invoked with a pre-defined +-- code buffer, code generation is aborted on overflow. +-- +-- /Note:/ Starting with version 0.4, Harpy automatically checks for +-- buffer overflow, so you do not need to call this function anymore. +ensureBufferSize :: Int -> CodeGen e s () +ensureBufferSize needed = + do state <- getInternalState + case (customCodeBuffer (config state)) of + Nothing -> + unless (bufferOfs state + needed + 5 <= bufferSize state) + (do let incrSize = max (needed + 16) (codeBufferSize (config state)) + arr <- liftIO $ mallocBytes incrSize + ofs <- getCodeOffset + let buf = buffer state + disp :: Int + disp = arr `minusPtr` (buf `plusPtr` ofs) - 5 + emit8 0xe9 -- FIXME: Machine dependent! + emit32 (fromIntegral disp) + st <- getInternalState + setInternalState st{buffer = arr, bufferList = bufferList st ++ [(buffer st, bufferOfs st)], bufferOfs = 0}) + Just (_, _) -> checkBufferSize needed + +-- | Return a pointer to the beginning of the first code buffer, which +-- is normally the entry point to the generated code. +getEntryPoint :: CodeGen e s (Ptr Word8) +getEntryPoint = + CodeGen (\ _ (ustate, state) -> + return $ ((ustate, state), Right (firstBuffer state))) + +-- | Return the current offset in the code buffer, e.g. the offset +-- at which the next instruction will be emitted. +getCodeOffset :: CodeGen e s Int +getCodeOffset = + CodeGen (\ _ (ustate, state) -> + return $ ((ustate, state), Right (bufferOfs state))) + +-- | Set the user state to the given value. +setState :: s -> CodeGen e s () +setState st = + CodeGen (\ _ (_, state) -> + return $ ((st, state), Right ())) + +-- | Return the current user state. +getState :: CodeGen e s s +getState = + CodeGen (\ _ (ustate, state) -> + return $ ((ustate, state), Right (ustate))) + +-- | Return the current user environment. +getEnv :: CodeGen e s e +getEnv = + CodeGen (\ (uenv, _) state -> + return $ (state, Right uenv)) + +-- | Set the environment to the given value and execute the given +-- code generation in this environment. +withEnv :: e -> CodeGen e s r -> CodeGen e s r +withEnv e (CodeGen cg) = + CodeGen (\ (_, env) state -> + cg (e, env) state) + +-- | Set the user state to the given value. +setInternalState :: CodeGenState -> CodeGen e s () +setInternalState st = + CodeGen (\ _ (ustate, _) -> + return $ ((ustate, st), Right ())) + +-- | Return the current user state. +getInternalState :: CodeGen e s CodeGenState +getInternalState = + CodeGen (\ _ (ustate, state) -> + return $ ((ustate, state), Right (state))) + +-- | Return the pointer to the start of the code buffer. +getBasePtr :: CodeGen e s (Ptr Word8) +getBasePtr = + CodeGen (\ _ (ustate, state) -> + return $ ((ustate, state), Right (buffer state))) + +-- | Return a list of all code buffers and their respective size +-- (i.e., actually used space for code, not allocated size). +getCodeBufferList :: CodeGen e s [(Ptr Word8, Int)] +getCodeBufferList = do st <- getInternalState + return $ bufferList st ++ [(buffer st, bufferOfs st)] + +-- | Generate a new label to be used with the label operations +-- 'emitFixup' and 'defineLabel'. +newLabel :: CodeGen e s Label +newLabel = + do state <- getInternalState + let lab = nextLabel state + setInternalState state{nextLabel = lab + 1} + return (Label lab "") + +-- | Generate a new label to be used with the label operations +-- 'emitFixup' and 'defineLabel'. The given name is used for +-- diagnostic purposes, and will appear in the disassembly. +newNamedLabel :: String -> CodeGen e s Label +newNamedLabel name = + do state <- getInternalState + let lab = nextLabel state + setInternalState state{nextLabel = lab + 1} + return (Label lab name) + +-- | Generate a new label and define it at once +setLabel :: CodeGen e s Label +setLabel = + do l <- newLabel + defineLabel l + return l + +-- | Emit a relocation entry for the given offset, relocation kind +-- and target address. +emitRelocInfo :: Int -> RelocKind -> FunPtr a -> CodeGen e s () +emitRelocInfo ofs knd addr = + do state <- getInternalState + setInternalState state{relocEntries = + Reloc{offset = ofs, + kind = knd, + address = castFunPtr addr} : + (relocEntries state)} + +-- | Emit a byte value to the code buffer. +emit8 :: Word8 -> CodeGen e s () +emit8 op = + CodeGen (\ _ (ustate, state) -> + do let buf = buffer state + ptr = bufferOfs state + pokeByteOff buf ptr op + return $ ((ustate, state{bufferOfs = ptr + 1}), Right ())) + +-- | Store a byte value at the given offset into the code buffer. +emit8At :: Int -> Word8 -> CodeGen e s () +emit8At pos op = + CodeGen (\ _ (ustate, state) -> + do let buf = buffer state + pokeByteOff buf pos op + return $ ((ustate, state), Right ())) + +-- | Return the byte value at the given offset in the code buffer. +peek8At :: Int -> CodeGen e s Word8 +peek8At pos = + CodeGen (\ _ (ustate, state) -> + do let buf = buffer state + b <- peekByteOff buf pos + return $ ((ustate, state), Right b)) + +-- | Like 'emit8', but for a 32-bit value. +emit32 :: Word32 -> CodeGen e s () +emit32 op = + CodeGen (\ _ (ustate, state) -> + do let buf = buffer state + ptr = bufferOfs state + pokeByteOff buf ptr op + return $ ((ustate, state{bufferOfs = ptr + 4}), Right ())) + +-- | Like 'emit8At', but for a 32-bit value. +emit32At :: Int -> Word32 -> CodeGen e s () +emit32At pos op = + CodeGen (\ _ (ustate, state) -> + do let buf = buffer state + pokeByteOff buf pos op + return $ ((ustate, state), Right ())) + +-- | Emit a label at the current offset in the code buffer. All +-- references to the label will be relocated to this offset. +defineLabel :: Label -> CodeGen e s () +defineLabel (Label lab name) = + do state <- getInternalState + case Map.lookup lab (definedLabels state) of + Just _ -> failCodeGen $ text "duplicate definition of label" <+> + int lab + _ -> return () + case Map.lookup lab (pendingFixups state) of + Just fixups -> do mapM_ (performFixup (buffer state) (bufferOfs state)) fixups + setInternalState state{pendingFixups = Map.delete lab (pendingFixups state)} + Nothing -> return () + state1 <- getInternalState + setInternalState state1{definedLabels = Map.insert lab (buffer state1, bufferOfs state1, name) (definedLabels state1)} + +performFixup :: Ptr Word8 -> Int -> FixupEntry -> CodeGen e s () +performFixup labBuf labOfs (FixupEntry{fueBuffer = buf, fueOfs = ofs, fueKind = knd}) = + do let diff = (labBuf `plusPtr` labOfs) `minusPtr` (buf `plusPtr` ofs) + liftIO $ case knd of + Fixup8 -> pokeByteOff buf ofs (fromIntegral diff - 1 :: Word8) + Fixup16 -> pokeByteOff buf ofs (fromIntegral diff - 2 :: Word16) + Fixup32 -> pokeByteOff buf ofs (fromIntegral diff - 4 :: Word32) + Fixup32Absolute -> pokeByteOff buf ofs (fromIntegral (ptrToWordPtr (labBuf `plusPtr` labOfs)) :: Word32) + return () + + +-- | This operator gives neat syntax for defining labels. When @l@ is a label, the code +-- +-- > l @@ mov eax ebx +-- +-- associates the label l with the following @mov@ instruction. +(@@) :: Label -> CodeGen e s a -> CodeGen e s a +(@@) lab gen = do defineLabel lab + gen + +-- | Emit a fixup entry for the given label at the current offset in +-- the code buffer (unless the label is already defined). +-- The instruction at this offset will +-- be patched to target the address associated with this label when +-- it is defined later. +emitFixup :: Label -> Int -> FixupKind -> CodeGen e s () +emitFixup (Label lab _) ofs knd = + do state <- getInternalState + let base = buffer state + ptr = bufferOfs state + fue = FixupEntry{fueBuffer = base, + fueOfs = ptr + ofs, + fueKind = knd} + case Map.lookup lab (definedLabels state) of + Just (labBuf, labOfs, _) -> performFixup labBuf labOfs fue + Nothing -> setInternalState state{pendingFixups = Map.insertWith (++) lab [fue] (pendingFixups state)} + +-- | Return the address of a label, fail if the label is not yet defined. +labelAddress :: Label -> CodeGen e s (Ptr a) +labelAddress (Label lab name) = do + state <- getInternalState + case Map.lookup lab (definedLabels state) of + Just (labBuf, labOfs, _) -> return $ plusPtr labBuf labOfs + Nothing -> fail $ "Label " ++ show lab ++ "(" ++ name ++ ") not yet defined" + + +-- | Disassemble all code buffers. The result is a list of +-- disassembled instructions which can be converted to strings using +-- the 'Dis.showIntel' or 'Dis.showAtt' functions from module +-- "Harpy.X86Disassembler". +disassemble :: CodeGen e s [Dis.Instruction] +disassemble = do + s <- getInternalState + let buffers = bufferList s + r <- mapM (\ (buff, len) -> do + r <- liftIO $ Dis.disassembleBlock buff len + case r of + Left err -> cgFail $ show err + Right instr -> return instr + ) $ buffers ++ [(buffer s, bufferOfs s)] + r' <- insertLabels (concat r) + return r' + where insertLabels :: [Dis.Instruction] -> CodeGen e s [Dis.Instruction] + insertLabels = liftM concat . mapM ins + ins :: Dis.Instruction -> CodeGen e s [Dis.Instruction] + ins i@(Dis.BadInstruction{}) = return [i] + ins i@(Dis.PseudoInstruction{}) = return [i] + ins i@(Dis.Instruction{Dis.address = addr}) = + do state <- getInternalState + let allLabs = Map.toList (definedLabels state) + labs = filter (\ (_, (buf, ofs, _)) -> fromIntegral (ptrToWordPtr (buf `plusPtr` ofs)) == addr) allLabs + createLabel (l, (buf, ofs, name)) = Dis.PseudoInstruction addr + (case name of + "" -> + "label " ++ show l ++ + " [" ++ + hex32 (fromIntegral (ptrToWordPtr (buf `plusPtr` ofs))) ++ + "]" + _ -> name ++ ": [" ++ + hex32 (fromIntegral (ptrToWordPtr (buf `plusPtr` ofs))) ++ + "]") + return $ fmap createLabel labs ++ [i] + hex32 :: Int -> String + hex32 i = + let w :: Word32 + w = fromIntegral i + s = showHex w "" + in take (8 - length s) (repeat '0') ++ s + +#ifndef __HADDOCK__ + +callDecl :: String -> Q Type -> Q [Dec] +callDecl ns qt = do + t0 <- qt + let (tvars, cxt, t) = case t0 of + ForallT vs c t' -> (vs, c, t') + _ -> ([], [], t0) + let name = mkName ns + let funptr = AppT (ConT $ mkName "FunPtr") t + let ioresult = addIO t + let ty = AppT (AppT ArrowT funptr) ioresult + dynName <- newName "conv" + let dyn = ForeignD $ ImportF CCall Safe "dynamic" dynName $ ForallT tvars cxt ty + vs <- mkArgs t + cbody <- [| CodeGen (\env (ustate, state) -> + do let code = firstBuffer state + res <- liftIO $ $(do + c <- newName "c" + cast <- [|castPtrToFunPtr|] + let f = AppE (VarE dynName) + (AppE cast + (VarE c)) + return $ LamE [VarP c] $ foldl AppE f $ map VarE vs + ) code + return $ ((ustate, state), Right res))|] + let call = ValD (VarP name) (NormalB $ LamE (map VarP vs) cbody) [] + return [ dyn, call ] + +mkArgs (AppT (AppT ArrowT _from) to) = do + v <- newName "v" + vs <- mkArgs to + return $ v : vs +mkArgs _ = return [] + +addIO (AppT t@(AppT ArrowT _from) to) = AppT t $ addIO to +addIO t = AppT (ConT $ mkName "IO") t + +#else + +-- | Declare a stub function to call the code buffer. Arguments are the name +-- of the generated function, and the type the code buffer is supposed to have. +-- The type argument can be given using the [t| ... |] notation of Template Haskell. +-- Allowed types are the legal types for FFI functions. +callDecl :: String -> Q Type -> Q [Dec] + +#endif diff --git a/Harpy/X86Assembler.hs b/Harpy/X86Assembler.hs new file mode 100644 index 0000000..1933ad5 --- /dev/null +++ b/Harpy/X86Assembler.hs @@ -0,0 +1,4168 @@ +{-# LANGUAGE MultiParamTypeClasses,FlexibleInstances,FunctionalDependencies #-} +-------------------------------------------------------------------------- +-- | +-- Module : Harpy.X86Assembler +-- Copyright : (c) 2006-2007 Martin Grabmueller and Dirk Kleeblatt +-- License : GPL +-- +-- Maintainer : {magr,klee}@cs.tu-berlin.de +-- Stability : provisional +-- Portability : non-portable +-- +-- A type class based layer on top of X86CodeGen +-- which determines the addressing modes from the types of the +-- operands. +-------------------------------------------------------------------------- +module Harpy.X86Assembler ( + module Harpy.X86Assembler, + XMMReg(..), + ) where + +import Harpy.X86CodeGen +import Harpy.CodeGenMonad +import Data.Word +import Foreign.Ptr + +import qualified Text.PrettyPrint.HughesPJ as PP + + +-- address modes used in this module: + +-- Word8/16/32 immediate values +-- Reg8/16/32 register +-- Addr Word32 absolut +-- Ind Reg32 register indirect +-- (Disp, Reg32) register indirect with displacement +-- (Reg32, Reg32, Scale) (base, index, scale), effective address is (base + index * scale) +-- (Disp, Reg32, Scale) (disp, index, scale), effective address is (disp + index * scale) +-- (Disp, Reg32, Reg32, Scale) (base, index, scale) + displacement (only ebp is allowed as base register) +-- Label not-yet-specified label + +onlyEbp = failCodeGen (PP.text "only epb is allowed as base register for disp/base/index/scale addressing") +onlyCl = failCodeGen (PP.text "only cl is allowed as shift count") + + +-- x86 Registers + +newtype Reg8 = Reg8 Word8 +al, cl, dl, bl, ah, ch, dh, bh :: Reg8 + +al = Reg8 0 +cl = Reg8 1 +dl = Reg8 2 +bl = Reg8 3 +ah = Reg8 4 +ch = Reg8 5 +dh = Reg8 6 +bh = Reg8 7 + +newtype Reg16 = Reg16 Word8 +ax, cx, dx, bx, sp, bp, si, di :: Reg16 + +ax = Reg16 0 +cx = Reg16 1 +dx = Reg16 2 +bx = Reg16 3 +sp = Reg16 4 +bp = Reg16 5 +si = Reg16 6 +di = Reg16 7 + +newtype Reg32 = Reg32 Word8 deriving (Eq, Ord) +eax, ecx, edx, ebx, esp, ebp, esi, edi :: Reg32 + +eax = Reg32 0 +ecx = Reg32 1 +edx = Reg32 2 +ebx = Reg32 3 +esp = Reg32 4 +ebp = Reg32 5 +esi = Reg32 6 +edi = Reg32 7 + +{- +newtype XMMReg = XMMReg Word8 + deriving (Eq, Ord) +-} + +xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 :: XMMReg +xmm0 = XMMReg 0 +xmm1 = XMMReg 1 +xmm2 = XMMReg 2 +xmm3 = XMMReg 3 +xmm4 = XMMReg 4 +xmm5 = XMMReg 5 +xmm6 = XMMReg 6 +xmm7 = XMMReg 7 + +instance Show XMMReg where + show (XMMReg i) = "xmm" ++ show i + +-- TODO: instances for other registers + +instance Show Reg32 where + show (Reg32 0) = "eax" + show (Reg32 1) = "ecx" + show (Reg32 2) = "edx" + show (Reg32 3) = "ebx" + show (Reg32 4) = "esp" + show (Reg32 5) = "ebp" + show (Reg32 6) = "esi" + show (Reg32 7) = "edi" + +-- memory addresses + +newtype Addr = Addr Word32 +newtype Ind = Ind Reg32 +newtype Disp = Disp Word32 + +data Scale = S1 | S2 | S4 | S8 + +scaleToShift :: Scale -> Word8 +scaleToShift S1 = 0 +scaleToShift S2 = 1 +scaleToShift S4 = 2 +scaleToShift S8 = 3 + +newtype FPReg = FPReg Word8 + +data FPTopReg = FPTopReg + +fpTop = FPTopReg + +fp0 = FPReg 0 +fp1 = FPReg 1 +fp2 = FPReg 2 +fp3 = FPReg 3 +fp4 = FPReg 4 +fp5 = FPReg 5 +fp6 = FPReg 6 +fp7 = FPReg 7 + +-- int 3 + +breakpoint = ensureBufferSize x86_max_instruction_bytes >> x86_breakpoint + + +-- clear direction flag + +cld = ensureBufferSize x86_max_instruction_bytes >> x86_cld + + +-- store string + +stosb = ensureBufferSize x86_max_instruction_bytes >> x86_stosb +stosl = ensureBufferSize x86_max_instruction_bytes >> x86_stosl +stosd = ensureBufferSize x86_max_instruction_bytes >> x86_stosd + + +-- move string + +movsb = ensureBufferSize x86_max_instruction_bytes >> x86_movsb +movsl = ensureBufferSize x86_max_instruction_bytes >> x86_movsl +--movsd = ensureBufferSize x86_max_instruction_bytes >> x86_movsd + + +-- read time stamp counter + +rdtsc = ensureBufferSize x86_max_instruction_bytes >> x86_rdtsc + + +-- compare and exchange + +class Cmpxchg a b where + cmpxchg :: a -> b -> CodeGen e s () + +instance Cmpxchg Reg32 Reg32 where + cmpxchg (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_reg_reg dest source + +instance Cmpxchg Addr Reg32 where + cmpxchg (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_mem_reg dest source + +instance Cmpxchg (Disp, Reg32) Reg32 where + cmpxchg (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_membase_reg dest disp source + +instance Cmpxchg Ind Reg32 where + cmpxchg (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_membase_reg dest 0 source + + + +-- exchange memory/register with register + +class Xchg a b where + xchg :: a -> b -> CodeGen e s () + +instance Xchg Reg8 Reg8 where + xchg (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_reg_reg dest source 1 + +instance Xchg Reg32 Reg32 where + xchg (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_reg_reg dest source 4 + +instance Xchg Addr Reg8 where + xchg (Addr dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_mem_reg dest source 1 + +instance Xchg Addr Reg32 where + xchg (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_mem_reg dest source 4 + +instance Xchg (Disp, Reg32) Reg8 where + xchg (Disp disp, Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest disp source 1 + +instance Xchg Ind Reg8 where + xchg (Ind (Reg32 dest)) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest 0 source 1 + +instance Xchg (Disp, Reg32) Reg32 where + xchg (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest disp source 4 + +instance Xchg Ind Reg32 where + xchg (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest 0 source 4 + + +-- exchange and add + +class Xadd a b where + xadd :: a -> b -> CodeGen e s () + +instance Xadd Reg8 Reg8 where + xadd (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_reg_reg dest source 1 + +instance Xadd Reg32 Reg32 where + xadd (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_reg_reg dest source 4 + +instance Xadd Addr Reg8 where + xadd (Addr dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_mem_reg dest source 1 + +instance Xadd Addr Reg32 where + xadd (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_mem_reg dest source 4 + +instance Xadd (Disp, Reg32) Reg8 where + xadd (Disp disp, Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest disp source 1 + +instance Xadd Ind Reg8 where + xadd (Ind (Reg32 dest)) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest 0 source 1 + +instance Xadd (Disp, Reg32) Reg32 where + xadd (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest disp source 4 + +instance Xadd Ind Reg32 where + xadd (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest 0 source 4 + + +-- Increment by 1 + +class Inc a where + inc :: a -> CodeGen e s () + +instance Inc Addr where + inc (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_mem dest + +instance Inc (Disp, Reg32) where + inc (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_membase dest disp + +instance Inc Ind where + inc (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_membase dest 0 + +instance Inc Reg32 where + inc (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_reg dest + + +-- Decrement by 1 + +class Dec a where + dec :: a -> CodeGen e s () + +instance Dec Addr where + dec (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_mem dest + +instance Dec (Disp, Reg32) where + dec (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_membase dest disp + +instance Dec Ind where + dec (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_membase dest 0 + +instance Dec Reg32 where + dec (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_reg dest + + +-- One's complement negation + +class Not a where + not :: a -> CodeGen e s () + +instance Not Addr where + not (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_not_mem dest + +instance Not (Disp, Reg32) where + not (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_not_membase dest disp + +instance Not Ind where + not (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_not_membase dest 0 + +instance Not Reg32 where + not (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_not_reg dest + + +-- Two's complement negation + +class Neg a where + neg :: a -> CodeGen e s () + +instance Neg Addr where + neg (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_mem dest + +instance Neg (Disp, Reg32) where + neg (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_membase dest disp + +instance Neg Ind where + neg (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_membase dest 0 + +instance Neg Reg32 where + neg (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_reg dest + + +-- No operation + +nop = ensureBufferSize x86_max_instruction_bytes >> x86_nop + + +-- ALU operations + +-- Calling "x86_alu_reg8_reg8 _ _ _ *False* *False*" is a little bit hackish: the last two +-- arguments are set to True for the "high byte registers" ah, bh, ch and dh. +-- x86_reg8_emit then sets the 3rd bit in the register number. This bit is set in our +-- encoding anyway to the right value, so we simply skip this part. + +class Add a b where + add :: a -> b -> CodeGen e s () + +instance Add Reg32 Word32 where + add (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_add dest (fromIntegral imm) + +instance Add Addr Word32 where + add (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_add dest (fromIntegral imm) + +instance Add (Disp, Reg32) Word32 where + add (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_add dest disp (fromIntegral imm) + +instance Add Ind Word32 where + add (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_add dest 0 (fromIntegral imm) + +instance Add (Disp, Reg32) Word8 where + add (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_add dest disp (fromIntegral imm) + +instance Add Ind Word8 where + add (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_add dest 0 (fromIntegral imm) + +instance Add Addr Reg32 where + add (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_add dest source + +instance Add (Disp, Reg32) Reg32 where + add (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_add dest disp source + +instance Add Ind Reg32 where + add (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_add dest 0 source + +instance Add Reg32 Reg32 where + add (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_add dest source + +instance Add Reg8 Reg8 where + add (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_add dest source False False + +instance Add Reg32 Addr where + add (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_add dest source + +instance Add Reg32 (Disp, Reg32) where + add (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_add dest source disp + +instance Add Reg32 Ind where + add (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_add dest source 0 + + +class Or a b where + or :: a -> b -> CodeGen e s () + +instance Or Reg32 Word32 where + or (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_or dest (fromIntegral imm) + +instance Or Addr Word32 where + or (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_or dest (fromIntegral imm) + +instance Or (Disp, Reg32) Word32 where + or (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_or dest disp (fromIntegral imm) + +instance Or Ind Word32 where + or (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_or dest 0 (fromIntegral imm) + +instance Or (Disp, Reg32) Word8 where + or (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_or dest disp (fromIntegral imm) + +instance Or Ind Word8 where + or (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_or dest 0 (fromIntegral imm) + +instance Or Addr Reg32 where + or (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_or dest source + +instance Or (Disp, Reg32) Reg32 where + or (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_or dest disp source + +instance Or Ind Reg32 where + or (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_or dest 0 source + +instance Or Reg32 Reg32 where + or (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_or dest source + +instance Or Reg8 Reg8 where + or (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_or dest source False False + +instance Or Reg32 Addr where + or (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_or dest source + +instance Or Reg32 (Disp, Reg32) where + or (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_or dest source disp + +instance Or Reg32 Ind where + or (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_or dest source 0 + + +class Adc a b where + adc :: a -> b -> CodeGen e s () + +instance Adc Reg32 Word32 where + adc (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_adc dest (fromIntegral imm) + +instance Adc Addr Word32 where + adc (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_adc dest (fromIntegral imm) + +instance Adc (Disp, Reg32) Word32 where + adc (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_adc dest disp (fromIntegral imm) + +instance Adc Ind Word32 where + adc (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_adc dest 0 (fromIntegral imm) + +instance Adc (Disp, Reg32) Word8 where + adc (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_adc dest disp (fromIntegral imm) + +instance Adc Ind Word8 where + adc (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_adc dest 0 (fromIntegral imm) + +instance Adc Addr Reg32 where + adc (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_adc dest source + +instance Adc (Disp, Reg32) Reg32 where + adc (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_adc dest disp source + +instance Adc Ind Reg32 where + adc (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_adc dest 0 source + +instance Adc Reg32 Reg32 where + adc (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_adc dest source + +instance Adc Reg8 Reg8 where + adc (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_adc dest source False False + +instance Adc Reg32 Addr where + adc (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_adc dest source + +instance Adc Reg32 (Disp, Reg32) where + adc (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_adc dest source disp + +instance Adc Reg32 Ind where + adc (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_adc dest source 0 + + +class Sbb a b where + sbb :: a -> b -> CodeGen e s () + +instance Sbb Reg32 Word32 where + sbb (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_sbb dest (fromIntegral imm) + +instance Sbb Addr Word32 where + sbb (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_sbb dest (fromIntegral imm) + +instance Sbb (Disp, Reg32) Word32 where + sbb (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sbb dest disp (fromIntegral imm) + +instance Sbb Ind Word32 where + sbb (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sbb dest 0 (fromIntegral imm) + +instance Sbb (Disp, Reg32) Word8 where + sbb (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_sbb dest disp (fromIntegral imm) + +instance Sbb Ind Word8 where + sbb (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_sbb dest 0 (fromIntegral imm) + +instance Sbb Addr Reg32 where + sbb (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_sbb dest source + +instance Sbb (Disp, Reg32) Reg32 where + sbb (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_sbb dest disp source + +instance Sbb Ind Reg32 where + sbb (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_sbb dest 0 source + +instance Sbb Reg32 Reg32 where + sbb (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_sbb dest source + +instance Sbb Reg8 Reg8 where + sbb (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_sbb dest source False False + +instance Sbb Reg32 Addr where + sbb (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_sbb dest source + +instance Sbb Reg32 (Disp, Reg32) where + sbb (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_sbb dest source disp + +instance Sbb Reg32 Ind where + sbb (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_sbb dest source 0 + + +class And a b where + and :: a -> b -> CodeGen e s () + +instance And Reg32 Word32 where + and (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_and dest (fromIntegral imm) + +instance And Addr Word32 where + and (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_and dest (fromIntegral imm) + +instance And (Disp, Reg32) Word32 where + and (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_and dest disp (fromIntegral imm) + +instance And Ind Word32 where + and (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_and dest 0 (fromIntegral imm) + +instance And (Disp, Reg32) Word8 where + and (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_and dest disp (fromIntegral imm) + +instance And Ind Word8 where + and (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_and dest 0 (fromIntegral imm) + +instance And Addr Reg32 where + and (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_and dest source + +instance And (Disp, Reg32) Reg32 where + and (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_and dest disp source + +instance And Ind Reg32 where + and (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_and dest 0 source + +instance And Reg32 Reg32 where + and (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_and dest source + +instance And Reg8 Reg8 where + and (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_and dest source False False + +instance And Reg32 Addr where + and (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_and dest source + +instance And Reg32 (Disp, Reg32) where + and (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_and dest source disp + +instance And Reg32 Ind where + and (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_and dest source 0 + + +class Sub a b where + sub :: a -> b -> CodeGen e s () + +instance Sub Reg32 Word32 where + sub (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_sub dest (fromIntegral imm) + +instance Sub Addr Word32 where + sub (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_sub dest (fromIntegral imm) + +instance Sub (Disp, Reg32) Word32 where + sub (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sub dest disp (fromIntegral imm) + +instance Sub Ind Word32 where + sub (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sub dest 0 (fromIntegral imm) + +instance Sub (Disp, Reg32) Word8 where + sub (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_sub dest disp (fromIntegral imm) + +instance Sub Ind Word8 where + sub (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_sub dest 0 (fromIntegral imm) + +instance Sub Addr Reg32 where + sub (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_sub dest source + +instance Sub (Disp, Reg32) Reg32 where + sub (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_sub dest disp source + +instance Sub Ind Reg32 where + sub (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_sub dest 0 source + +instance Sub Reg32 Reg32 where + sub (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_sub dest source + +instance Sub Reg8 Reg8 where + sub (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_sub dest source False False + +instance Sub Reg32 Addr where + sub (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_sub dest source + +instance Sub Reg32 (Disp, Reg32) where + sub (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_sub dest source disp + +instance Sub Reg32 Ind where + sub (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_sub dest source 0 + + +class Xor a b where + xor :: a -> b -> CodeGen e s () + +instance Xor Reg32 Word32 where + xor (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_xor dest (fromIntegral imm) + +instance Xor Addr Word32 where + xor (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_xor dest (fromIntegral imm) + +instance Xor (Disp, Reg32) Word32 where + xor (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_xor dest disp (fromIntegral imm) + +instance Xor Ind Word32 where + xor (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_xor dest 0 (fromIntegral imm) + +instance Xor (Disp, Reg32) Word8 where + xor (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_xor dest disp (fromIntegral imm) + +instance Xor Ind Word8 where + xor (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_xor dest 0 (fromIntegral imm) + +instance Xor Addr Reg32 where + xor (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_xor dest source + +instance Xor (Disp, Reg32) Reg32 where + xor (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_xor dest disp source + +instance Xor Ind Reg32 where + xor (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_xor dest 0 source + +instance Xor Reg32 Reg32 where + xor (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_xor dest source + +instance Xor Reg8 Reg8 where + xor (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_xor dest source False False + +instance Xor Reg32 Addr where + xor (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_xor dest source + +instance Xor Reg32 (Disp, Reg32) where + xor (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_xor dest source disp + +instance Xor Reg32 Ind where + xor (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_xor dest source 0 + + +class Cmp a b where + cmp :: a -> b -> CodeGen e s () + +instance Cmp Reg32 Word32 where + cmp (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_cmp dest (fromIntegral imm) + +instance Cmp Reg32 (Ptr a) where + cmp (Reg32 dest) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_cmp dest (ptrToInt ptr) + +instance Cmp Reg32 Label where + cmp (Reg32 dest) lab = do + ensureBufferSize x86_max_instruction_bytes + x86_alu_reg_imm x86_cmp dest 0xf0f0f0f0 + emitFixup lab (-4) Fixup32Absolute + +instance Cmp Addr Word32 where + cmp (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_cmp dest (fromIntegral imm) + +instance Cmp Addr (Ptr a) where + cmp (Addr dest) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_cmp dest (ptrToWord32 ptr) + +instance Cmp Addr Label where + cmp (Addr dest) lab = do + ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_cmp dest 0xf0f0f0f0 + emitFixup lab (-4) Fixup32Absolute + +instance Cmp (Disp, Reg32) Word32 where + cmp (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_cmp dest disp (fromIntegral imm) + +instance Cmp (Disp, Reg32) (Ptr a) where + cmp (Disp disp, Reg32 dest) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_cmp dest disp (ptrToWord32 ptr) + +instance Cmp (Disp, Reg32) Label where + cmp (Disp disp, Reg32 dest) lab = do + ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_cmp dest disp 0xf0f0f0f0 + emitFixup lab (-4) Fixup32Absolute + +instance Cmp Ind Word32 where + cmp (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_cmp dest 0 (fromIntegral imm) + +instance Cmp Ind (Ptr a) where + cmp (Ind (Reg32 dest)) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_cmp dest 0 (ptrToWord32 ptr) + +instance Cmp Ind Label where + cmp (Ind (Reg32 dest)) lab = do + ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_cmp dest 0 0xf0f0f0f0 + emitFixup lab (-4) Fixup32Absolute + +instance Cmp (Disp, Reg32) Word8 where + cmp (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_cmp dest disp imm + +instance Cmp Ind Word8 where + cmp (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_cmp dest 0 imm + +instance Cmp Addr Reg32 where + cmp (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_cmp dest source + +instance Cmp (Disp, Reg32) Reg32 where + cmp (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_cmp dest disp source + +instance Cmp Ind Reg32 where + cmp (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_cmp dest 0 source + +instance Cmp Reg32 Reg32 where + cmp (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_cmp dest source + +instance Cmp Reg8 Reg8 where + cmp (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_cmp dest source False False + +instance Cmp Reg32 Addr where + cmp (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_cmp dest source + +instance Cmp Reg32 (Disp, Reg32) where + cmp (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_cmp dest source disp + +instance Cmp Reg32 Ind where + cmp (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_cmp dest source 0 + + +-- logical compare + +class Test a b where + test :: a -> b -> CodeGen e s () + +instance Test Reg32 Word32 where + test (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_test_reg_imm dest imm + +instance Test Addr Word32 where + test (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_test_mem_imm dest imm + +instance Test (Disp, Reg32) Word32 where + test (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_test_membase_imm dest disp imm + +instance Test Ind Word32 where + test (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_test_membase_imm dest 0 imm + +instance Test Reg32 Reg32 where + test (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_test_reg_reg dest source + +instance Test Addr Reg32 where + test (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_test_mem_reg dest source + +instance Test (Disp, Reg32) Reg32 where + test (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_test_membase_reg dest disp source + +instance Test Ind Reg32 where + test (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_test_membase_reg dest 0 source + + +-- shift and rotate + +class Rol a b where + rol :: a -> b -> CodeGen e s () + +instance Rol Reg32 Word8 where + rol (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_rol dest imm + +instance Rol Addr Word8 where + rol (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_rol dest imm + +instance Rol (Disp, Reg32) Word8 where + rol (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_rol dest disp imm + +instance Rol Ind Word8 where + rol (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_rol dest 0 imm + +instance Rol Reg32 Reg8 where + rol (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_rol dest + rol _ _ = onlyCl + +instance Rol Addr Reg8 where + rol (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_rol dest + rol _ _ = onlyCl + +instance Rol (Disp, Reg32) Reg8 where + rol (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_rol dest disp + +instance Rol Ind Reg8 where + rol (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_rol dest 0 + rol _ _ = onlyCl + +class Ror a b where + ror :: a -> b -> CodeGen e s () + +instance Ror Reg32 Word8 where + ror (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_ror dest imm + +instance Ror Addr Word8 where + ror (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_ror dest imm + +instance Ror (Disp, Reg32) Word8 where + ror (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_ror dest disp imm + +instance Ror Ind Word8 where + ror (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_ror dest 0 imm + +instance Ror Reg32 Reg8 where + ror (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_ror dest + ror _ _ = onlyCl + +instance Ror Addr Reg8 where + ror (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_ror dest + ror _ _ = onlyCl + +instance Ror (Disp, Reg32) Reg8 where + ror (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_ror dest disp + +instance Ror Ind Reg8 where + ror (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_ror dest 0 + ror _ _ = onlyCl + +class Rcl a b where + rcl :: a -> b -> CodeGen e s () + +instance Rcl Reg32 Word8 where + rcl (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_rcl dest imm + +instance Rcl Addr Word8 where + rcl (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_rcl dest imm + +instance Rcl (Disp, Reg32) Word8 where + rcl (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_rcl dest disp imm + +instance Rcl Ind Word8 where + rcl (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_rcl dest 0 imm + +instance Rcl Reg32 Reg8 where + rcl (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_rcl dest + rcl _ _ = onlyCl + +instance Rcl Addr Reg8 where + rcl (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_rcl dest + rcl _ _ = onlyCl + +instance Rcl (Disp, Reg32) Reg8 where + rcl (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_rcl dest disp + +instance Rcl Ind Reg8 where + rcl (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_rcl dest 0 + rcl _ _ = onlyCl + +class Rcr a b where + rcr :: a -> b -> CodeGen e s () + +instance Rcr Reg32 Word8 where + rcr (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_rcr dest imm + +instance Rcr Addr Word8 where + rcr (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_rcr dest imm + +instance Rcr (Disp, Reg32) Word8 where + rcr (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_rcr dest disp imm + +instance Rcr Ind Word8 where + rcr (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_rcr dest 0 imm + +instance Rcr Reg32 Reg8 where + rcr (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_rcr dest + rcr _ _ = onlyCl + +instance Rcr Addr Reg8 where + rcr (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_rcr dest + rcr _ _ = onlyCl + +instance Rcr (Disp, Reg32) Reg8 where + rcr (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_rcr dest disp + +instance Rcr Ind Reg8 where + rcr (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_rcr dest 0 + rcr _ _ = onlyCl + +class Shl a b where + shl :: a -> b -> CodeGen e s () + +instance Shl Reg32 Word8 where + shl (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_shl dest imm + +instance Shl Addr Word8 where + shl (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_shl dest imm + +instance Shl (Disp, Reg32) Word8 where + shl (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_shl dest disp imm + +instance Shl Ind Word8 where + shl (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_shl dest 0 imm + +instance Shl Reg32 Reg8 where + shl (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_shl dest + shl _ _ = onlyCl + +instance Shl Addr Reg8 where + shl (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_shl dest + shl _ _ = onlyCl + +instance Shl (Disp, Reg32) Reg8 where + shl (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_shl dest disp + +instance Shl Ind Reg8 where + shl (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_shl dest 0 + shl _ _ = onlyCl + +class Shr a b where + shr :: a -> b -> CodeGen e s () + +instance Shr Reg32 Word8 where + shr (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_shr dest imm + +instance Shr Addr Word8 where + shr (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_shr dest imm + +instance Shr (Disp, Reg32) Word8 where + shr (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_shr dest disp imm + +instance Shr Ind Word8 where + shr (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_shr dest 0 imm + +instance Shr Reg32 Reg8 where + shr (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_shr dest + shr _ _ = onlyCl + +instance Shr Addr Reg8 where + shr (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_shr dest + shr _ _ = onlyCl + +instance Shr (Disp, Reg32) Reg8 where + shr (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_shr dest disp + +instance Shr Ind Reg8 where + shr (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_shr dest 0 + shr _ _ = onlyCl + +class Sar a b where + sar :: a -> b -> CodeGen e s () + +instance Sar Reg32 Word8 where + sar (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_sar dest imm + +instance Sar Addr Word8 where + sar (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_sar dest imm + +instance Sar (Disp, Reg32) Word8 where + sar (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_sar dest disp imm + +instance Sar Ind Word8 where + sar (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_sar dest 0 imm + +instance Sar Reg32 Reg8 where + sar (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_sar dest + sar _ _ = onlyCl + +instance Sar Addr Reg8 where + sar (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_sar dest + sar _ _ = onlyCl + +instance Sar (Disp, Reg32) Reg8 where + sar (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_sar dest disp + +instance Sar Ind Reg8 where + sar (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_sar dest 0 + sar _ _ = onlyCl + +class Sal a b where + sal :: a -> b -> CodeGen e s () + +instance Sal Reg32 Word8 where + sal (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg_imm x86_shl dest imm + +instance Sal Addr Word8 where + sal (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem_imm x86_shl dest imm + +instance Sal (Disp, Reg32) Word8 where + sal (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_shl dest disp imm + +instance Sal Ind Word8 where + sal (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase_imm x86_shl dest 0 imm + +instance Sal Reg32 Reg8 where + sal (Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_reg x86_shl dest + sal _ _ = onlyCl + +instance Sal Addr Reg8 where + sal (Addr dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_mem x86_shl dest + sal _ _ = onlyCl + +instance Sal (Disp, Reg32) Reg8 where + sal (Disp disp, Reg32 dest) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_shl dest disp + +instance Sal Ind Reg8 where + sal (Ind (Reg32 dest)) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shift_membase x86_shl dest 0 + sal _ _ = onlyCl + + +-- double precision shift right + +class Shrd a b c where + shrd :: a -> b -> c -> CodeGen e s () + +instance Shrd Reg32 Reg32 Reg8 where + shrd (Reg32 dest) (Reg32 source) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shrd_reg dest source + shrd _ _ _ = onlyCl + +instance Shrd Reg32 Reg32 Word8 where + shrd (Reg32 dest) (Reg32 source) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shrd_reg_imm dest source imm + + +-- double precision shift left + +class Shld a b c where + shld :: a -> b -> c -> CodeGen e s () + +instance Shld Reg32 Reg32 Reg8 where + shld (Reg32 dest) (Reg32 source) (Reg8 1) = ensureBufferSize x86_max_instruction_bytes >> x86_shld_reg dest source + shld _ _ _ = onlyCl + +instance Shld Reg32 Reg32 Word8 where + shld (Reg32 dest) (Reg32 source) imm = ensureBufferSize x86_max_instruction_bytes >> x86_shld_reg_imm dest source imm + + +-- unsigned multiply + +class Mul a where + mul :: a -> CodeGen e s () + +instance Mul Reg32 where + mul (Reg32 arg) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_reg arg False + +instance Mul Addr where + mul (Addr arg) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_mem arg False + +instance Mul (Disp, Reg32) where + mul (Disp disp, Reg32 arg) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_membase arg disp False + +instance Mul Ind where + mul (Ind (Reg32 arg)) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_membase arg 0 False + + +-- signed multiply + +data InPlace = InPlace + +-- if a == InPlace then +-- b = b * c +-- else +-- a = b * c + +class Imul a b c where + imul :: a -> b -> c -> CodeGen e s () + +instance Imul InPlace Reg32 Reg32 where + imul _ (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_reg dest source + +instance Imul InPlace Reg32 Addr where + imul _ (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_mem dest source + +instance Imul InPlace Reg32 (Disp, Reg32) where + imul _ (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_membase dest source disp + +instance Imul InPlace Reg32 Ind where + imul _ (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_membase dest source 0 + +instance Imul Reg32 Reg32 Word32 where + imul (Reg32 dest) (Reg32 source) imm = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_reg_imm dest source imm + +instance Imul Reg32 Addr Word32 where + imul (Reg32 dest) (Addr source) imm = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_mem_imm dest source imm + +instance Imul Reg32 (Disp, Reg32) Word32 where + imul (Reg32 dest) (Disp disp, Reg32 source) imm = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_membase_imm dest source disp imm + +instance Imul Reg32 Ind Word32 where + imul (Reg32 dest) (Ind (Reg32 source)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_imul_reg_membase_imm dest source 0 imm + + +-- divide EDX:EAX by rm; +-- eax = quotient, edx = remainder + +-- unsigned divide + +class Div a where + div :: a -> CodeGen e s () + +instance Div Reg32 where + div (Reg32 arg) = ensureBufferSize x86_max_instruction_bytes >> x86_div_reg arg False + +instance Div Addr where + div (Addr arg) = ensureBufferSize x86_max_instruction_bytes >> x86_div_mem arg False + +instance Div (Disp, Reg32) where + div (Disp disp, Reg32 arg) = ensureBufferSize x86_max_instruction_bytes >> x86_div_membase arg disp False + +instance Div Ind where + div (Ind (Reg32 arg)) = ensureBufferSize x86_max_instruction_bytes >> x86_div_membase arg 0 False + + +-- signed divide + +class Idiv a where + idiv :: a -> CodeGen e s () + +instance Idiv Reg32 where + idiv (Reg32 arg) = ensureBufferSize x86_max_instruction_bytes >> x86_div_reg arg True + +instance Idiv Addr where + idiv (Addr arg) = ensureBufferSize x86_max_instruction_bytes >> x86_div_mem arg True + +instance Idiv (Disp, Reg32) where + idiv (Disp disp, Reg32 arg) = ensureBufferSize x86_max_instruction_bytes >> x86_div_membase arg disp True + +instance Idiv Ind where + idiv (Ind (Reg32 arg)) = ensureBufferSize x86_max_instruction_bytes >> x86_div_membase arg 0 True + + +-- "mov" instruction for different sources and destinations + +class Mov a b where + mov :: a -> b -> CodeGen e s () + + +instance Mov Reg8 Reg8 where + mov (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_reg dest source 1 + +instance Mov Reg16 Reg16 where + mov (Reg16 dest) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_reg dest source 2 + +instance Mov Reg32 Reg32 where + mov (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_reg dest source 4 + + +instance Mov Reg32 Word32 where + mov (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_imm dest (fromIntegral imm) + +instance Mov Reg32 (Ptr a) where + mov (Reg32 dest) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_imm dest (ptrToWord32 ptr) + +instance Mov Reg32 Label where + mov (Reg32 dest) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_imm dest 0 + emitFixup lab (-4) Fixup32Absolute + +instance Mov Addr Word8 where + mov (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_imm dest (fromIntegral imm) 1 + +instance Mov Addr Word16 where + mov (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_imm dest (fromIntegral imm) 2 + +instance Mov Addr Word32 where + mov (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_imm dest imm 4 + +instance Mov Addr (Ptr a) where + mov (Addr dest) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_imm dest (ptrToWord32 ptr) 4 + +instance Mov Addr Label where + mov (Addr dest) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_imm dest 0 4 + emitFixup lab (-4) Fixup32Absolute + +instance Mov (Disp, Reg32) Word8 where + mov (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest disp (fromIntegral imm) 1 + +instance Mov Ind Word8 where + mov (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest 0 (fromIntegral imm) 1 + +instance Mov (Disp, Reg32) Word16 where + mov (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest disp (fromIntegral imm) 2 + +instance Mov Ind Word16 where + mov (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest 0 (fromIntegral imm) 2 + +instance Mov (Disp, Reg32) Word32 where + mov (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest disp imm 4 + +instance Mov (Disp, Reg32) (Ptr a) where + mov (Disp disp, Reg32 dest) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest disp (ptrToWord32 ptr) 4 + +instance Mov (Disp, Reg32) Label where + mov (Disp disp, Reg32 dest) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest disp 0 4 + emitFixup lab (-4) Fixup32Absolute + +instance Mov Ind Word32 where + mov (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest 0 imm 4 + +instance Mov Ind (Ptr a) where + mov (Ind (Reg32 dest)) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest 0 (ptrToWord32 ptr) 4 + +instance Mov Ind Label where + mov (Ind (Reg32 dest)) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_imm dest 0 0 4 + emitFixup lab (-4) Fixup32Absolute + +instance Mov (Reg32, Reg32, Scale) Word8 where + mov (Reg32 base, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm base 0 index (scaleToShift scale) (fromIntegral imm) 1 + +instance Mov (Reg32, Reg32, Scale) Word16 where + mov (Reg32 base, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm base 0 index (scaleToShift scale) (fromIntegral imm) 2 + +instance Mov (Reg32, Reg32, Scale) Word32 where + mov (Reg32 base, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm base 0 index (scaleToShift scale) imm 4 + +instance Mov (Reg32, Reg32, Scale) (Ptr a) where + mov (Reg32 base, Reg32 index, scale) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm base 0 index (scaleToShift scale) (ptrToWord32 ptr) 4 + +instance Mov (Reg32, Reg32, Scale) Label where + mov (Reg32 base, Reg32 index, scale) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm base 0 index (scaleToShift scale) 0 4 + emitFixup lab (-4) Fixup32Absolute + +instance Mov (Disp, Reg32, Scale) Word8 where + mov (Disp disp, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm x86_nobasereg disp index (scaleToShift scale) (fromIntegral imm) 1 + +instance Mov (Disp, Reg32, Scale) Word16 where + mov (Disp disp, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm x86_nobasereg disp index (scaleToShift scale) (fromIntegral imm) 2 + +instance Mov (Disp, Reg32, Scale) Word32 where + mov (Disp disp, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm x86_nobasereg disp index (scaleToShift scale) imm 4 + +instance Mov (Disp, Reg32, Scale) (Ptr a) where + mov (Disp disp, Reg32 index, scale) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm x86_nobasereg disp index (scaleToShift scale) (ptrToWord32 ptr) 4 + +instance Mov (Disp, Reg32, Scale) Label where + mov (Disp disp, Reg32 index, scale) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm x86_nobasereg disp index (scaleToShift scale) 0 4 + emitFixup lab (-4) Fixup32Absolute + +instance Mov (Disp, Reg32, Reg32, Scale) Word8 where + mov (Disp disp, Reg32 5, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm 5 disp index (scaleToShift scale) (fromIntegral imm) 1 + mov _ _ = onlyEbp + +instance Mov (Disp, Reg32, Reg32, Scale) Word16 where + mov (Disp disp, Reg32 5, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm 5 disp index (scaleToShift scale) (fromIntegral imm) 2 + mov _ _ = onlyEbp + +instance Mov (Disp, Reg32, Reg32, Scale) Word32 where + mov (Disp disp, Reg32 5, Reg32 index, scale) imm = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm 5 disp index (scaleToShift scale) imm 4 + mov _ _ = onlyEbp + +instance Mov (Disp, Reg32, Reg32, Scale) (Ptr a) where + mov (Disp disp, Reg32 5, Reg32 index, scale) ptr = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm 5 disp index (scaleToShift scale) (ptrToWord32 ptr) 4 + mov _ _ = onlyEbp + +instance Mov (Disp, Reg32, Reg32, Scale) Label where + mov (Disp disp, Reg32 5, Reg32 index, scale) lab = do ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_imm 5 disp index (scaleToShift scale) 0 4 + emitFixup lab (-4) Fixup32Absolute + mov _ _ = onlyEbp + +instance Mov Addr Reg8 where + mov (Addr a) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_reg a source 1 + +instance Mov Addr Reg16 where + mov (Addr a) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_reg a source 2 + +instance Mov Addr Reg32 where + mov (Addr a) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_mem_reg a source 4 + +instance Mov Reg8 Addr where + mov (Reg8 dest) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_mem dest a 1 + +instance Mov Reg16 Addr where + mov (Reg16 dest) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_mem dest a 2 + +instance Mov Reg32 Addr where + mov (Reg32 dest) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_mem dest a 4 + + +instance Mov Ind Reg8 where + mov (Ind (Reg32 dest)) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_regp_reg dest source 1 + +instance Mov Ind Reg16 where + mov (Ind (Reg32 dest)) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_regp_reg dest source 2 + +instance Mov Ind Reg32 where + mov (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_regp_reg dest source 4 + +instance Mov Reg8 Ind where + mov (Reg8 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_regp dest source 1 + +instance Mov Reg16 Ind where + mov (Reg16 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_regp dest source 2 + +instance Mov Reg32 Ind where + mov (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_regp dest source 4 + + +instance Mov (Disp, Reg32) Reg8 where + mov (Disp disp, Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_reg dest disp source 1 + +instance Mov (Disp, Reg32) Reg16 where + mov (Disp disp, Reg32 dest) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_reg dest disp source 2 + +instance Mov (Disp, Reg32) Reg32 where + mov (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_membase_reg dest disp source 4 + +instance Mov Reg8 (Disp, Reg32) where + mov (Reg8 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_membase dest source disp 1 + +instance Mov Reg16 (Disp, Reg32) where + mov (Reg16 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_membase dest source disp 2 + +instance Mov Reg32 (Disp, Reg32) where + mov (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_membase dest source disp 4 + + +instance Mov (Reg32, Reg32, Scale) Reg8 where + mov (Reg32 base, Reg32 index, s) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg base 0 index (scaleToShift s) source 1 + +instance Mov (Reg32, Reg32, Scale) Reg16 where + mov (Reg32 base, Reg32 index, s) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg base 0 index (scaleToShift s) source 2 + +instance Mov (Reg32, Reg32, Scale) Reg32 where + mov (Reg32 base, Reg32 index, s) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg base 0 index (scaleToShift s) source 4 + +instance Mov Reg8 (Reg32, Reg32, Scale) where + mov (Reg8 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest base 0 index (scaleToShift s) 1 + +instance Mov Reg16 (Reg32, Reg32, Scale) where + mov (Reg16 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest base 0 index (scaleToShift s) 2 + +instance Mov Reg32 (Reg32, Reg32, Scale) where + mov (Reg32 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest base 0 index (scaleToShift s) 4 + + +instance Mov (Disp, Reg32, Scale) Reg8 where + mov (Disp disp, Reg32 index, s) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg x86_nobasereg disp index (scaleToShift s) source 1 + +instance Mov (Disp, Reg32, Scale) Reg16 where + mov (Disp disp, Reg32 index, s) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg x86_nobasereg disp index (scaleToShift s) source 2 + +instance Mov (Disp, Reg32, Scale) Reg32 where + mov (Disp disp, Reg32 index, s) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg x86_nobasereg disp index (scaleToShift s) source 4 + +instance Mov Reg8 (Disp, Reg32, Scale) where + mov (Reg8 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest x86_nobasereg disp index (scaleToShift s) 1 + +instance Mov Reg16 (Disp, Reg32, Scale) where + mov (Reg16 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest x86_nobasereg disp index (scaleToShift s) 2 + +instance Mov Reg32 (Disp, Reg32, Scale) where + mov (Reg32 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest x86_nobasereg disp index (scaleToShift s) 4 + + +instance Mov (Disp, Reg32, Reg32, Scale) Reg8 where + mov (Disp disp, Reg32 5, Reg32 index, s) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg 5 disp index (scaleToShift s) source 1 + mov _ _ = onlyEbp + +instance Mov (Disp, Reg32, Reg32, Scale) Reg16 where + mov (Disp disp, Reg32 5, Reg32 index, s) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg 5 disp index (scaleToShift s) source 2 + mov _ _ = onlyEbp + +instance Mov (Disp, Reg32, Reg32, Scale) Reg32 where + mov (Disp disp, Reg32 5, Reg32 index, s) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> ensureBufferSize x86_max_instruction_bytes >> x86_mov_memindex_reg 5 disp index (scaleToShift s) source 4 + mov _ _ = onlyEbp + +instance Mov Reg8 (Disp, Reg32, Reg32, Scale) where + mov (Reg8 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest 5 disp index (scaleToShift s) 1 + mov _ _ = onlyEbp + +instance Mov Reg16 (Disp, Reg32, Reg32, Scale) where + mov (Reg16 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest 5 disp index (scaleToShift s) 2 + mov _ _ = onlyEbp + +instance Mov Reg32 (Disp, Reg32, Reg32, Scale) where + mov (Reg32 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_reg_memindex dest 5 disp index (scaleToShift s) 4 + mov _ _ = onlyEbp + + +-- move with sign-extension + +class Movsxb a b where + movsxb :: a -> b -> CodeGen e s () + +instance Movsxb Reg32 Reg8 where + movsxb (Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_reg dest source True False + +instance Movsxb Reg32 Addr where + movsxb (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_mem dest source True False + +instance Movsxb Reg32 (Disp, Reg32) where + movsxb (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source disp True False + +instance Movsxb Reg32 Ind where + movsxb (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source 0 True False + +instance Movsxb Reg32 (Disp, Reg32, Reg32, Scale) where + movsxb (Reg32 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest 5 disp index (scaleToShift s) True False + movsxb _ _ = onlyEbp + +instance Movsxb Reg32 (Disp, Reg32, Scale) where + movsxb (Reg32 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest x86_nobasereg disp index (scaleToShift s) True False + +instance Movsxb Reg32 (Reg32, Reg32, Scale) where + movsxb (Reg32 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest base 0 index (scaleToShift s) True False + +class Movsxw a b where + movsxw :: a -> b -> CodeGen e s () + +instance Movsxw Reg32 Reg16 where + movsxw (Reg32 dest) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_reg dest source True True + +instance Movsxw Reg32 Addr where + movsxw (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_mem dest source True True + +instance Movsxw Reg32 (Disp, Reg32) where + movsxw (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source disp True True + +instance Movsxw Reg32 Ind where + movsxw (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source 0 True True + +instance Movsxw Reg32 (Disp, Reg32, Reg32, Scale) where + movsxw (Reg32 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest 5 disp index (scaleToShift s) True True + movsxw _ _ = onlyEbp + +instance Movsxw Reg32 (Disp, Reg32, Scale) where + movsxw (Reg32 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest x86_nobasereg disp index (scaleToShift s) True True + +instance Movsxw Reg32 (Reg32, Reg32, Scale) where + movsxw (Reg32 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest base 0 index (scaleToShift s) True True + + +-- move with zero-extension + +class Movzxb a b where + movzxb :: a -> b -> CodeGen e s () + +instance Movzxb Reg32 Reg8 where + movzxb (Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_reg dest source False False + +instance Movzxb Reg32 Addr where + movzxb (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_mem dest source False False + +instance Movzxb Reg32 (Disp, Reg32) where + movzxb (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source disp False False + +instance Movzxb Reg32 Ind where + movzxb (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source 0 False False + +instance Movzxb Reg32 (Disp, Reg32, Reg32, Scale) where + movzxb (Reg32 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest 5 disp index (scaleToShift s) False False + movzxb _ _ = onlyEbp + +instance Movzxb Reg32 (Disp, Reg32, Scale) where + movzxb (Reg32 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest x86_nobasereg disp index (scaleToShift s) False False + +instance Movzxb Reg32 (Reg32, Reg32, Scale) where + movzxb (Reg32 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest base 0 index (scaleToShift s) False False + +class Movzxw a b where + movzxw :: a -> b -> CodeGen e s () + +instance Movzxw Reg32 Reg16 where + movzxw (Reg32 dest) (Reg16 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_reg dest source False True + +instance Movzxw Reg32 Addr where + movzxw (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_mem dest source False True + +instance Movzxw Reg32 (Disp, Reg32) where + movzxw (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source disp False True + +instance Movzxw Reg32 Ind where + movzxw (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_membase dest source 0 False True + +instance Movzxw Reg32 (Disp, Reg32, Reg32, Scale) where + movzxw (Reg32 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest 5 disp index (scaleToShift s) False True + movzxw _ _ = onlyEbp + +instance Movzxw Reg32 (Disp, Reg32, Scale) where + movzxw (Reg32 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest x86_nobasereg disp index (scaleToShift s) False True + +instance Movzxw Reg32 (Reg32, Reg32, Scale) where + movzxw (Reg32 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_widen_memindex dest base 0 index (scaleToShift s) False True + + +-- load effective address + +class Lea a b where + lea :: a -> b -> CodeGen e s () + +instance Lea Reg32 Addr where + lea (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_lea_mem dest source + +instance Lea Reg32 (Disp, Reg32) where + lea (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_lea_membase dest source disp + +instance Lea Reg32 Ind where + lea (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_lea_membase dest source 0 + +instance Lea Reg32 (Disp, Reg32, Reg32, Scale) where + lea (Reg32 dest) (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_lea_memindex dest 5 disp index (scaleToShift s) + lea _ _ = onlyEbp + +instance Lea Reg32 (Disp, Reg32, Scale) where + lea (Reg32 dest) (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_lea_memindex dest x86_nobasereg disp index (scaleToShift s) + +instance Lea Reg32 (Reg32, Reg32, Scale) where + lea (Reg32 dest) (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_lea_memindex dest base 0 index (scaleToShift s) + + +-- convert word to doubleword + +cdq = ensureBufferSize x86_max_instruction_bytes >> x86_cdq + + +-- wait for FPU + +wait = ensureBufferSize x86_max_instruction_bytes >> x86_wait + + +-- push to stack + +class Push a where + push :: a -> CodeGen e s () + +instance Push Reg32 where + push (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_push_reg source + +instance Push Ind where + push (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_push_regp source + +instance Push Addr where + push (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_push_mem source + +instance Push (Disp, Reg32) where + push (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_push_membase source disp + +instance Push Word32 where + push imm = ensureBufferSize x86_max_instruction_bytes >> x86_push_imm imm + +instance Push Label where + push l = do ensureBufferSize x86_max_instruction_bytes >> x86_push_imm_template + emitFixup l (-4) Fixup32Absolute + +instance Push (Disp, Reg32, Reg32, Scale) where + push (Disp disp, Reg32 5, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_push_memindex 5 disp index (scaleToShift s) + push _ = onlyEbp + +instance Push (Disp, Reg32, Scale) where + push (Disp disp, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_push_memindex x86_nobasereg disp index (scaleToShift s) + +instance Push (Reg32, Reg32, Scale) where + push (Reg32 base, Reg32 index, s) = ensureBufferSize x86_max_instruction_bytes >> x86_push_memindex base 0 index (scaleToShift s) + + +-- pop from stack + +class Pop a where + pop :: a -> CodeGen e s () + +instance Pop Reg32 where + pop (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_pop_reg dest + +instance Pop Addr where + pop (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_pop_mem dest + +instance Pop (Disp, Reg32) where + pop (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_pop_membase dest disp + +instance Pop Ind where + pop (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_pop_membase dest 0 + + +-- push/pop general purpose registers + +pushad = ensureBufferSize x86_max_instruction_bytes >> x86_pushad +popad = ensureBufferSize x86_max_instruction_bytes >> x86_popad + + +-- push/pop EFLAGS + +pushfd = ensureBufferSize x86_max_instruction_bytes >> x86_pushfd +popfd = ensureBufferSize x86_max_instruction_bytes >> x86_popfd + + +-- loop according to ECX counter + +class Loop a where + loop :: a -> CodeGen e s () + loope :: a -> CodeGen e s () + loopne :: a -> CodeGen e s () + +instance Loop Word8 where + loop w = ensureBufferSize x86_max_instruction_bytes >> x86_loop w + loope w = ensureBufferSize x86_max_instruction_bytes >> x86_loope w + loopne w = ensureBufferSize x86_max_instruction_bytes >> x86_loopne w + +instance Loop Label where + loop l = do ensureBufferSize x86_max_instruction_bytes >> x86_loop 0 + emitFixup l (-1) Fixup8 + loope l = do ensureBufferSize x86_max_instruction_bytes >> x86_loope 0 + emitFixup l (-1) Fixup8 + loopne l = do ensureBufferSize x86_max_instruction_bytes >> x86_loopne 0 + emitFixup l (-1) Fixup8 + +-- jump + +class Jmp a where + jmp :: a -> CodeGen e s () + +instance Jmp Word8 where + jmp imm = ensureBufferSize x86_max_instruction_bytes >> x86_jump8 imm + +instance Jmp Word32 where + jmp imm = ensureBufferSize x86_max_instruction_bytes >> x86_jump32 imm + +instance Jmp Reg32 where + jmp (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_jump_reg dest + +instance Jmp Addr where + jmp (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_jump_mem dest + +instance Jmp (Disp, Reg32) where + jmp (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_jump_membase dest disp + +instance Jmp Ind where + jmp (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_jump_membase dest 0 + +instance Jmp Label where + jmp l = do ensureBufferSize x86_max_instruction_bytes >> x86_jump32 0 + emitFixup l (-4) Fixup32 + +instance Jmp (Ptr a) where + jmp ptr = ensureBufferSize x86_max_instruction_bytes >> x86_jump_pointer ptr + +-- jump on condition code (branch) + +class Ja a where + ja :: a -> CodeGen e s () + +instance Ja Word8 where + ja imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_a imm False + +instance Ja Word32 where + ja imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_a imm False + +instance Ja (Ptr a) where + ja ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_a ptr False + +instance Ja Label where + ja l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_a 0 False + emitFixup l (-4) Fixup32 + +class Jae a where + jae :: a -> CodeGen e s () + +instance Jae Word8 where + jae imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_ae imm False + +instance Jae Word32 where + jae imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ae imm False + +instance Jae (Ptr a) where + jae ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_ae ptr False + +instance Jae Label where + jae l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ae 0 False + emitFixup l (-4) Fixup32 + +class Jb a where + jb :: a -> CodeGen e s () + +instance Jb Word8 where + jb imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_b imm False + +instance Jb Word32 where + jb imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_b imm False + +instance Jb (Ptr a) where + jb ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_b ptr False + +instance Jb Label where + jb l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_b 0 False + emitFixup l (-4) Fixup32 + +class Jbe a where + jbe :: a -> CodeGen e s () + +instance Jbe Word8 where + jbe imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_be imm False + +instance Jbe Word32 where + jbe imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_be imm False + +instance Jbe (Ptr a) where + jbe ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_be ptr False + +instance Jbe Label where + jbe l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_be 0 False + emitFixup l (-4) Fixup32 + +class Jc a where + jc :: a -> CodeGen e s () + +instance Jc Word8 where + jc imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_c imm False + +instance Jc Word32 where + jc imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_c imm False + +instance Jc (Ptr a) where + jc ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_c ptr False + +instance Jc Label where + jc l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_c 0 False + emitFixup l (-4) Fixup32 + +class Je a where + je :: a -> CodeGen e s () + +instance Je Word8 where + je imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_e imm False + +instance Je Word32 where + je imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_e imm False + +instance Je (Ptr a) where + je ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_e ptr False + +instance Je Label where + je l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_e 0 False + emitFixup l (-4) Fixup32 + +class Jna a where + jna :: a -> CodeGen e s () + +instance Jna Word8 where + jna imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_na imm False + +instance Jna Word32 where + jna imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_na imm False + +instance Jna (Ptr a) where + jna ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_na ptr False + +instance Jna Label where + jna l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_na 0 False + emitFixup l (-4) Fixup32 + +class Jnae a where + jnae :: a -> CodeGen e s () + +instance Jnae Word8 where + jnae imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_nae imm False + +instance Jnae Word32 where + jnae imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nae imm False + +instance Jnae (Ptr a) where + jnae ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_nae ptr False + +instance Jnae Label where + jnae l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nae 0 False + emitFixup l (-4) Fixup32 + +class Jnb a where + jnb :: a -> CodeGen e s () + +instance Jnb Word8 where + jnb imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_nb imm False + +instance Jnb Word32 where + jnb imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nb imm False + +instance Jnb (Ptr a) where + jnb ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_nb ptr False + +instance Jnb Label where + jnb l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nb 0 False + emitFixup l (-4) Fixup32 + +class Jnbe a where + jnbe :: a -> CodeGen e s () + +instance Jnbe Word8 where + jnbe imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_nbe imm False + +instance Jnbe Word32 where + jnbe imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nbe imm False + +instance Jnbe (Ptr a) where + jnbe ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_nbe ptr False + +instance Jnbe Label where + jnbe l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nbe 0 False + emitFixup l (-4) Fixup32 + +class Jnc a where + jnc :: a -> CodeGen e s () + +instance Jnc Word8 where + jnc imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_nc imm False + +instance Jnc Word32 where + jnc imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nc imm False + +instance Jnc (Ptr a) where + jnc ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_nc ptr False + +instance Jnc Label where + jnc l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nc 0 False + emitFixup l (-4) Fixup32 + +class Jne a where + jne :: a -> CodeGen e s () + +instance Jne Word8 where + jne imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_ne imm False + +instance Jne Word32 where + jne imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ne imm False + +instance Jne (Ptr a) where + jne ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_ne ptr False + +instance Jne Label where + jne l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ne 0 False + emitFixup l (-4) Fixup32 + +class Jnp a where + jnp :: a -> CodeGen e s () + +instance Jnp Word8 where + jnp imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_np imm False + +instance Jnp Word32 where + jnp imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_np imm False + +instance Jnp (Ptr a) where + jnp ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_np ptr False + +instance Jnp Label where + jnp l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_np 0 False + emitFixup l (-4) Fixup32 + +class Jnz a where + jnz :: a -> CodeGen e s () + +instance Jnz Word8 where + jnz imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_nz imm False + +instance Jnz Word32 where + jnz imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nz imm False + +instance Jnz (Ptr a) where + jnz ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_nz ptr False + +instance Jnz Label where + jnz l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_nz 0 False + emitFixup l (-4) Fixup32 + +class Jp a where + jp :: a -> CodeGen e s () + +instance Jp Word8 where + jp imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_p imm False + +instance Jp Word32 where + jp imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_p imm False + +instance Jp (Ptr a) where + jp ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_p ptr False + +instance Jp Label where + jp l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_p 0 False + emitFixup l (-4) Fixup32 + +class Jpe a where + jpe :: a -> CodeGen e s () + +instance Jpe Word8 where + jpe imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_pe imm False + +instance Jpe Word32 where + jpe imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_pe imm False + +instance Jpe (Ptr a) where + jpe ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_pe ptr False + +instance Jpe Label where + jpe l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_pe 0 False + emitFixup l (-4) Fixup32 + +class Jpo a where + jpo :: a -> CodeGen e s () + +instance Jpo Word8 where + jpo imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_po imm False + +instance Jpo Word32 where + jpo imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_po imm False + +instance Jpo (Ptr a) where + jpo ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_po ptr False + +instance Jpo Label where + jpo l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_po 0 False + emitFixup l (-4) Fixup32 + +class Jz a where + jz :: a -> CodeGen e s () + +instance Jz Word8 where + jz imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_z imm False + +instance Jz Word32 where + jz imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_z imm False + +instance Jz (Ptr a) where + jz ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_z ptr False + +instance Jz Label where + jz l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_z 0 False + emitFixup l (-4) Fixup32 + +class Jg a where + jg :: a -> CodeGen e s () + +instance Jg Word8 where + jg imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_gt imm True + +instance Jg Word32 where + jg imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_gt imm True + +instance Jg (Ptr a) where + jg ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_gt ptr True + +instance Jg Label where + jg l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_gt 0 True + emitFixup l (-4) Fixup32 + +class Jge a where + jge :: a -> CodeGen e s () + +instance Jge Word8 where + jge imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_ge imm True + +instance Jge Word32 where + jge imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ge imm True + +instance Jge (Ptr a) where + jge ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_ge ptr True + +instance Jge Label where + jge l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ge 0 True + emitFixup l (-4) Fixup32 + +class Jl a where + jl :: a -> CodeGen e s () + +instance Jl Word8 where + jl imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_lt imm True + +instance Jl Word32 where + jl imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_lt imm True + +instance Jl (Ptr a) where + jl ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_lt ptr True + +instance Jl Label where + jl l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_lt 0 True + emitFixup l (-4) Fixup32 + +class Jle a where + jle :: a -> CodeGen e s () + +instance Jle Word8 where + jle imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_le imm True + +instance Jle Word32 where + jle imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_le imm True + +instance Jle (Ptr a) where + jle ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_le ptr True + +instance Jle Label where + jle l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_le 0 True + emitFixup l (-4) Fixup32 + +class Jng a where + jng :: a -> CodeGen e s () + +instance Jng Word8 where + jng imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_le imm True + +instance Jng Word32 where + jng imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_le imm True + +instance Jng (Ptr a) where + jng ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_le ptr True + +instance Jng Label where + jng l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_le 0 True + emitFixup l (-4) Fixup32 + +class Jnge a where + jnge :: a -> CodeGen e s () + +instance Jnge Word8 where + jnge imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_lt imm True + +instance Jnge Word32 where + jnge imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_lt imm True + +instance Jnge (Ptr a) where + jnge ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_lt ptr True + +instance Jnge Label where + jnge l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_lt 0 True + emitFixup l (-4) Fixup32 + +class Jnl a where + jnl :: a -> CodeGen e s () + +instance Jnl Word8 where + jnl imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_ge imm True + +instance Jnl Word32 where + jnl imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ge imm True + +instance Jnl (Ptr a) where + jnl ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_ge ptr True + +instance Jnl Label where + jnl l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ge 0 True + emitFixup l (-4) Fixup32 + +class Jnle a where + jnle :: a -> CodeGen e s () + +instance Jnle Word8 where + jnle imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_gt imm True + +instance Jnle Word32 where + jnle imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_gt imm True + +instance Jnle (Ptr a) where + jnle ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_gt ptr True + +instance Jnle Label where + jnle l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_gt 0 True + emitFixup l (-4) Fixup32 + +class Jno a where + jno :: a -> CodeGen e s () + +instance Jno Word8 where + jno imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_no imm True + +instance Jno Word32 where + jno imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_no imm True + +instance Jno (Ptr a) where + jno ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_no ptr True + +instance Jno Label where + jno l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_no 0 True + emitFixup l (-4) Fixup32 + +class Jns a where + jns :: a -> CodeGen e s () + +instance Jns Word8 where + jns imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_ns imm True + +instance Jns Word32 where + jns imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ns imm True + +instance Jns (Ptr a) where + jns ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_ns ptr True + +instance Jns Label where + jns l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_ns 0 True + emitFixup l (-4) Fixup32 + +class Jo a where + jo :: a -> CodeGen e s () + +instance Jo Word8 where + jo imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_o imm True + +instance Jo Word32 where + jo imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_o imm True + +instance Jo (Ptr a) where + jo ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_o ptr True + +instance Jo Label where + jo l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_o 0 True + emitFixup l (-4) Fixup32 + +class Js a where + js :: a -> CodeGen e s () + +instance Js Word8 where + js imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch8 x86_cc_s imm True + +instance Js Word32 where + js imm = ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_s imm True + +instance Js (Ptr a) where + js ptr = ensureBufferSize x86_max_instruction_bytes >> x86_branch_pointer x86_cc_s ptr True + +instance Js Label where + js l = do ensureBufferSize x86_max_instruction_bytes >> x86_branch32 x86_cc_s 0 True + emitFixup l (-4) Fixup32 + +-- jump if ecx register is 0 + +jecxz :: Word8 -> CodeGen e s () +jecxz w = ensureBufferSize x86_max_instruction_bytes >> x86_jecxz w + + +-- set byte on condition code + +class Seta a where + seta :: a -> CodeGen e s () + +instance Seta Reg8 where + seta (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_a dest False + +instance Seta Addr where + seta (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_a dest False + +instance Seta (Disp, Reg32) where + seta (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_a dest disp False + +instance Seta Ind where + seta (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_a dest 0 False + +class Setae a where + setae :: a -> CodeGen e s () + +instance Setae Reg8 where + setae (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_ae dest False + +instance Setae Addr where + setae (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_ae dest False + +instance Setae (Disp, Reg32) where + setae (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ae dest disp False + +instance Setae Ind where + setae (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ae dest 0 False + +class Setb a where + setb :: a -> CodeGen e s () + +instance Setb Reg8 where + setb (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_b dest False + +instance Setb Addr where + setb (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_b dest False + +instance Setb (Disp, Reg32) where + setb (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_b dest disp False + +instance Setb Ind where + setb (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_b dest 0 False + +class Setbe a where + setbe :: a -> CodeGen e s () + +instance Setbe Reg8 where + setbe (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_be dest False + +instance Setbe Addr where + setbe (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_be dest False + +instance Setbe (Disp, Reg32) where + setbe (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_be dest disp False + +instance Setbe Ind where + setbe (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_be dest 0 False + +class Setc a where + setc :: a -> CodeGen e s () + +instance Setc Reg8 where + setc (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_c dest False + +instance Setc Addr where + setc (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_c dest False + +instance Setc (Disp, Reg32) where + setc (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_c dest disp False + +instance Setc Ind where + setc (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_c dest 0 False + +class Sete a where + sete :: a -> CodeGen e s () + +instance Sete Reg8 where + sete (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_e dest False + +instance Sete Addr where + sete (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_e dest False + +instance Sete (Disp, Reg32) where + sete (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_e dest disp False + +instance Sete Ind where + sete (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_e dest 0 False + +class Setna a where + setna :: a -> CodeGen e s () + +instance Setna Reg8 where + setna (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_na dest False + +instance Setna Addr where + setna (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_na dest False + +instance Setna (Disp, Reg32) where + setna (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_na dest disp False + +instance Setna Ind where + setna (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_na dest 0 False + +class Setnae a where + setnae :: a -> CodeGen e s () + +instance Setnae Reg8 where + setnae (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_nae dest False + +instance Setnae Addr where + setnae (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_nae dest False + +instance Setnae (Disp, Reg32) where + setnae (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nae dest disp False + +instance Setnae Ind where + setnae (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nae dest 0 False + +class Setnb a where + setnb :: a -> CodeGen e s () + +instance Setnb Reg8 where + setnb (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_nb dest False + +instance Setnb Addr where + setnb (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_nb dest False + +instance Setnb (Disp, Reg32) where + setnb (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nb dest disp False + +instance Setnb Ind where + setnb (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nb dest 0 False + +class Setnbe a where + setnbe :: a -> CodeGen e s () + +instance Setnbe Reg8 where + setnbe (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_nbe dest False + +instance Setnbe Addr where + setnbe (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_nbe dest False + +instance Setnbe (Disp, Reg32) where + setnbe (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nbe dest disp False + +instance Setnbe Ind where + setnbe (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nbe dest 0 False + +class Setnc a where + setnc :: a -> CodeGen e s () + +instance Setnc Reg8 where + setnc (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_nc dest False + +instance Setnc Addr where + setnc (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_nc dest False + +instance Setnc (Disp, Reg32) where + setnc (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nc dest disp False + +instance Setnc Ind where + setnc (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nc dest 0 False + +class Setne a where + setne :: a -> CodeGen e s () + +instance Setne Reg8 where + setne (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_ne dest False + +instance Setne Addr where + setne (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_ne dest False + +instance Setne (Disp, Reg32) where + setne (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ne dest disp False + +instance Setne Ind where + setne (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ne dest 0 False + +class Setnp a where + setnp :: a -> CodeGen e s () + +instance Setnp Reg8 where + setnp (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_np dest False + +instance Setnp Addr where + setnp (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_np dest False + +instance Setnp (Disp, Reg32) where + setnp (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_np dest disp False + +instance Setnp Ind where + setnp (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_np dest 0 False + +class Setnz a where + setnz :: a -> CodeGen e s () + +instance Setnz Reg8 where + setnz (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_nz dest False + +instance Setnz Addr where + setnz (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_nz dest False + +instance Setnz (Disp, Reg32) where + setnz (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nz dest disp False + +instance Setnz Ind where + setnz (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_nz dest 0 False + +class Setp a where + setp :: a -> CodeGen e s () + +instance Setp Reg8 where + setp (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_p dest False + +instance Setp Addr where + setp (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_p dest False + +instance Setp (Disp, Reg32) where + setp (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_p dest disp False + +instance Setp Ind where + setp (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_p dest 0 False + +class Setpe a where + setpe :: a -> CodeGen e s () + +instance Setpe Reg8 where + setpe (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_pe dest False + +instance Setpe Addr where + setpe (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_pe dest False + +instance Setpe (Disp, Reg32) where + setpe (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_pe dest disp False + +instance Setpe Ind where + setpe (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_pe dest 0 False + +class Setpo a where + setpo :: a -> CodeGen e s () + +instance Setpo Reg8 where + setpo (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_po dest False + +instance Setpo Addr where + setpo (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_po dest False + +instance Setpo (Disp, Reg32) where + setpo (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_po dest disp False + +instance Setpo Ind where + setpo (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_po dest 0 False + +class Setg a where + setg :: a -> CodeGen e s () + +instance Setg Reg8 where + setg (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_gt dest True + +instance Setg Addr where + setg (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_gt dest True + +instance Setg (Disp, Reg32) where + setg (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_gt dest disp True + +instance Setg Ind where + setg (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_gt dest 0 True + +class Setge a where + setge :: a -> CodeGen e s () + +instance Setge Reg8 where + setge (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_ge dest True + +instance Setge Addr where + setge (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_ge dest True + +instance Setge (Disp, Reg32) where + setge (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ge dest disp True + +instance Setge Ind where + setge (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ge dest 0 True + +class Setl a where + setl :: a -> CodeGen e s () + +instance Setl Reg8 where + setl (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_lt dest True + +instance Setl Addr where + setl (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_lt dest True + +instance Setl (Disp, Reg32) where + setl (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_lt dest disp True + +instance Setl Ind where + setl (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_lt dest 0 True + +class Setle a where + setle :: a -> CodeGen e s () + +instance Setle Reg8 where + setle (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_le dest True + +instance Setle Addr where + setle (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_le dest True + +instance Setle (Disp, Reg32) where + setle (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_le dest disp True + +instance Setle Ind where + setle (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_le dest 0 True + +class Setng a where + setng :: a -> CodeGen e s () + +instance Setng Reg8 where + setng (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_le dest True + +instance Setng Addr where + setng (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_le dest True + +instance Setng (Disp, Reg32) where + setng (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_le dest disp True + +instance Setng Ind where + setng (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_le dest 0 True + +class Setnge a where + setnge :: a -> CodeGen e s () + +instance Setnge Reg8 where + setnge (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_lt dest True + +instance Setnge Addr where + setnge (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_lt dest True + +instance Setnge (Disp, Reg32) where + setnge (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_lt dest disp True + +instance Setnge Ind where + setnge (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_lt dest 0 True + +class Setnl a where + setnl :: a -> CodeGen e s () + +instance Setnl Reg8 where + setnl (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_ge dest True + +instance Setnl Addr where + setnl (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_ge dest True + +instance Setnl (Disp, Reg32) where + setnl (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ge dest disp True + +instance Setnl Ind where + setnl (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ge dest 0 True + +class Setnle a where + setnle :: a -> CodeGen e s () + +instance Setnle Reg8 where + setnle (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_gt dest True + +instance Setnle Addr where + setnle (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_gt dest True + +instance Setnle (Disp, Reg32) where + setnle (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_gt dest disp True + +instance Setnle Ind where + setnle (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_gt dest 0 True + +class Setno a where + setno :: a -> CodeGen e s () + +instance Setno Reg8 where + setno (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_no dest True + +instance Setno Addr where + setno (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_no dest True + +instance Setno (Disp, Reg32) where + setno (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_no dest disp True + +instance Setno Ind where + setno (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_no dest 0 True + +class Setns a where + setns :: a -> CodeGen e s () + +instance Setns Reg8 where + setns (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_ns dest True + +instance Setns Addr where + setns (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_ns dest True + +instance Setns (Disp, Reg32) where + setns (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ns dest disp True + +instance Setns Ind where + setns (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_ns dest 0 True + +class Seto a where + seto :: a -> CodeGen e s () + +instance Seto Reg8 where + seto (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_o dest True + +instance Seto Addr where + seto (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_o dest True + +instance Seto (Disp, Reg32) where + seto (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_o dest disp True + +instance Seto Ind where + seto (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_o dest 0 True + +class Sets a where + sets :: a -> CodeGen e s () + +instance Sets Reg8 where + sets (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_s dest True + +instance Sets Addr where + sets (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_s dest True + +instance Sets (Disp, Reg32) where + sets (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_s dest disp True + +instance Sets Ind where + sets (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_s dest 0 True + +class Setz a where + setz :: a -> CodeGen e s () + +instance Setz Reg8 where + setz (Reg8 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_reg x86_cc_z dest False + +instance Setz Addr where + setz (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_mem x86_cc_z dest False + +instance Setz (Disp, Reg32) where + setz (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_z dest disp False + +instance Setz Ind where + setz (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_set_membase x86_cc_z dest 0 False + + +-- call procedure + +class Call a where + call :: a -> CodeGen e s () + +instance Call Word32 where + call imm = ensureBufferSize x86_max_instruction_bytes >> x86_call_imm imm + +instance Call Label where + call l = do ensureBufferSize x86_max_instruction_bytes >> x86_call_imm 0 + emitFixup l (-4) Fixup32 + +instance Call Reg32 where + call (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_call_reg dest + +instance Call Addr where + call (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_call_mem dest + +instance Call (Disp, Reg32) where + call (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_call_membase dest disp + +instance Call Ind where + call (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_call_membase dest 0 + +instance Call (FunPtr a) where + call f = ensureBufferSize x86_max_instruction_bytes >> x86_call_hs f + + +-- return from procedure + +ret :: CodeGen e s () +ret = ensureBufferSize x86_max_instruction_bytes >> x86_ret + +retN :: Word16 -> CodeGen e s () +retN n = ensureBufferSize x86_max_instruction_bytes >> x86_ret_imm n + + +-- make stack frame + +enter :: Word16 -> CodeGen e s () +enter w = ensureBufferSize x86_max_instruction_bytes >> x86_enter w + + +-- conditional move + +class Cmova a b where + cmova :: a -> b -> CodeGen e s () + +instance Cmova Reg32 Reg32 where + cmova (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_a False dest source + +instance Cmova Reg32 Addr where + cmova (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_a False dest source + +instance Cmova Reg32 (Disp, Reg32) where + cmova (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_a False dest source disp + +instance Cmova Reg32 Ind where + cmova (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_a False dest source 0 + +class Cmovae a b where + cmovae :: a -> b -> CodeGen e s () + +instance Cmovae Reg32 Reg32 where + cmovae (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_ae False dest source + +instance Cmovae Reg32 Addr where + cmovae (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_ae False dest source + +instance Cmovae Reg32 (Disp, Reg32) where + cmovae (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ae False dest source disp + +instance Cmovae Reg32 Ind where + cmovae (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ae False dest source 0 + +class Cmovb a b where + cmovb :: a -> b -> CodeGen e s () + +instance Cmovb Reg32 Reg32 where + cmovb (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_b False dest source + +instance Cmovb Reg32 Addr where + cmovb (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_b False dest source + +instance Cmovb Reg32 (Disp, Reg32) where + cmovb (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_b False dest source disp + +instance Cmovb Reg32 Ind where + cmovb (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_b False dest source 0 + +class Cmovbe a b where + cmovbe :: a -> b -> CodeGen e s () + +instance Cmovbe Reg32 Reg32 where + cmovbe (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_be False dest source + +instance Cmovbe Reg32 Addr where + cmovbe (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_be False dest source + +instance Cmovbe Reg32 (Disp, Reg32) where + cmovbe (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_be False dest source disp + +instance Cmovbe Reg32 Ind where + cmovbe (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_be False dest source 0 + +class Cmovc a b where + cmovc :: a -> b -> CodeGen e s () + +instance Cmovc Reg32 Reg32 where + cmovc (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_c False dest source + +instance Cmovc Reg32 Addr where + cmovc (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_c False dest source + +instance Cmovc Reg32 (Disp, Reg32) where + cmovc (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_c False dest source disp + +instance Cmovc Reg32 Ind where + cmovc (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_c False dest source 0 + +class Cmove a b where + cmove :: a -> b -> CodeGen e s () + +instance Cmove Reg32 Reg32 where + cmove (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_e False dest source + +instance Cmove Reg32 Addr where + cmove (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_e False dest source + +instance Cmove Reg32 (Disp, Reg32) where + cmove (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_e False dest source disp + +instance Cmove Reg32 Ind where + cmove (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_e False dest source 0 + +class Cmovna a b where + cmovna :: a -> b -> CodeGen e s () + +instance Cmovna Reg32 Reg32 where + cmovna (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_na False dest source + +instance Cmovna Reg32 Addr where + cmovna (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_na False dest source + +instance Cmovna Reg32 (Disp, Reg32) where + cmovna (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_na False dest source disp + +instance Cmovna Reg32 Ind where + cmovna (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_na False dest source 0 + +class Cmovnae a b where + cmovnae :: a -> b -> CodeGen e s () + +instance Cmovnae Reg32 Reg32 where + cmovnae (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_nae False dest source + +instance Cmovnae Reg32 Addr where + cmovnae (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_nae False dest source + +instance Cmovnae Reg32 (Disp, Reg32) where + cmovnae (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nae False dest source disp + +instance Cmovnae Reg32 Ind where + cmovnae (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nae False dest source 0 + +class Cmovnb a b where + cmovnb :: a -> b -> CodeGen e s () + +instance Cmovnb Reg32 Reg32 where + cmovnb (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_nb False dest source + +instance Cmovnb Reg32 Addr where + cmovnb (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_nb False dest source + +instance Cmovnb Reg32 (Disp, Reg32) where + cmovnb (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nb False dest source disp + +instance Cmovnb Reg32 Ind where + cmovnb (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nb False dest source 0 + +class Cmovnbe a b where + cmovnbe :: a -> b -> CodeGen e s () + +instance Cmovnbe Reg32 Reg32 where + cmovnbe (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_nbe False dest source + +instance Cmovnbe Reg32 Addr where + cmovnbe (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_nbe False dest source + +instance Cmovnbe Reg32 (Disp, Reg32) where + cmovnbe (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nbe False dest source disp + +instance Cmovnbe Reg32 Ind where + cmovnbe (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nbe False dest source 0 + +class Cmovnc a b where + cmovnc :: a -> b -> CodeGen e s () + +instance Cmovnc Reg32 Reg32 where + cmovnc (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_nc False dest source + +instance Cmovnc Reg32 Addr where + cmovnc (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_nc False dest source + +instance Cmovnc Reg32 (Disp, Reg32) where + cmovnc (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nc False dest source disp + +instance Cmovnc Reg32 Ind where + cmovnc (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nc False dest source 0 + +class Cmovne a b where + cmovne :: a -> b -> CodeGen e s () + +instance Cmovne Reg32 Reg32 where + cmovne (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_ne False dest source + +instance Cmovne Reg32 Addr where + cmovne (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_ne False dest source + +instance Cmovne Reg32 (Disp, Reg32) where + cmovne (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ne False dest source disp + +instance Cmovne Reg32 Ind where + cmovne (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ne False dest source 0 + +class Cmovnp a b where + cmovnp :: a -> b -> CodeGen e s () + +instance Cmovnp Reg32 Reg32 where + cmovnp (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_np False dest source + +instance Cmovnp Reg32 Addr where + cmovnp (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_np False dest source + +instance Cmovnp Reg32 (Disp, Reg32) where + cmovnp (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_np False dest source disp + +instance Cmovnp Reg32 Ind where + cmovnp (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_np False dest source 0 + +class Cmovnz a b where + cmovnz :: a -> b -> CodeGen e s () + +instance Cmovnz Reg32 Reg32 where + cmovnz (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_nz False dest source + +instance Cmovnz Reg32 Addr where + cmovnz (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_nz False dest source + +instance Cmovnz Reg32 (Disp, Reg32) where + cmovnz (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nz False dest source disp + +instance Cmovnz Reg32 Ind where + cmovnz (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_nz False dest source 0 + +class Cmovp a b where + cmovp :: a -> b -> CodeGen e s () + +instance Cmovp Reg32 Reg32 where + cmovp (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_p False dest source + +instance Cmovp Reg32 Addr where + cmovp (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_p False dest source + +instance Cmovp Reg32 (Disp, Reg32) where + cmovp (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_p False dest source disp + +instance Cmovp Reg32 Ind where + cmovp (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_p False dest source 0 + +class Cmovpe a b where + cmovpe :: a -> b -> CodeGen e s () + +instance Cmovpe Reg32 Reg32 where + cmovpe (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_pe False dest source + +instance Cmovpe Reg32 Addr where + cmovpe (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_pe False dest source + +instance Cmovpe Reg32 (Disp, Reg32) where + cmovpe (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_pe False dest source disp + +instance Cmovpe Reg32 Ind where + cmovpe (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_pe False dest source 0 + +class Cmovpo a b where + cmovpo :: a -> b -> CodeGen e s () + +instance Cmovpo Reg32 Reg32 where + cmovpo (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_po False dest source + +instance Cmovpo Reg32 Addr where + cmovpo (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_po False dest source + +instance Cmovpo Reg32 (Disp, Reg32) where + cmovpo (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_po False dest source disp + +instance Cmovpo Reg32 Ind where + cmovpo (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_po False dest source 0 + +class Cmovz a b where + cmovz :: a -> b -> CodeGen e s () + +instance Cmovz Reg32 Reg32 where + cmovz (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_z False dest source + +instance Cmovz Reg32 Addr where + cmovz (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_z False dest source + +instance Cmovz Reg32 (Disp, Reg32) where + cmovz (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_z False dest source disp + +instance Cmovz Reg32 Ind where + cmovz (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_z False dest source 0 + +class Cmovg a b where + cmovg :: a -> b -> CodeGen e s () + +instance Cmovg Reg32 Reg32 where + cmovg (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_gt True dest source + +instance Cmovg Reg32 Addr where + cmovg (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_gt True dest source + +instance Cmovg Reg32 (Disp, Reg32) where + cmovg (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_gt True dest source disp + +instance Cmovg Reg32 Ind where + cmovg (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_gt True dest source 0 + +class Cmovge a b where + cmovge :: a -> b -> CodeGen e s () + +instance Cmovge Reg32 Reg32 where + cmovge (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_ge True dest source + +instance Cmovge Reg32 Addr where + cmovge (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_ge True dest source + +instance Cmovge Reg32 (Disp, Reg32) where + cmovge (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ge True dest source disp + +instance Cmovge Reg32 Ind where + cmovge (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ge True dest source 0 + +class Cmovl a b where + cmovl :: a -> b -> CodeGen e s () + +instance Cmovl Reg32 Reg32 where + cmovl (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_lt True dest source + +instance Cmovl Reg32 Addr where + cmovl (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_lt True dest source + +instance Cmovl Reg32 (Disp, Reg32) where + cmovl (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_lt True dest source disp + +instance Cmovl Reg32 Ind where + cmovl (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_lt True dest source 0 + +class Cmovle a b where + cmovle :: a -> b -> CodeGen e s () + +instance Cmovle Reg32 Reg32 where + cmovle (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_le True dest source + +instance Cmovle Reg32 Addr where + cmovle (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_le True dest source + +instance Cmovle Reg32 (Disp, Reg32) where + cmovle (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_le True dest source disp + +instance Cmovle Reg32 Ind where + cmovle (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_le True dest source 0 + +class Cmovng a b where + cmovng :: a -> b -> CodeGen e s () + +instance Cmovng Reg32 Reg32 where + cmovng (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_le True dest source + +instance Cmovng Reg32 Addr where + cmovng (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_le True dest source + +instance Cmovng Reg32 (Disp, Reg32) where + cmovng (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_le True dest source disp + +instance Cmovng Reg32 Ind where + cmovng (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_le True dest source 0 + +class Cmovnge a b where + cmovnge :: a -> b -> CodeGen e s () + +instance Cmovnge Reg32 Reg32 where + cmovnge (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_lt True dest source + +instance Cmovnge Reg32 Addr where + cmovnge (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_lt True dest source + +instance Cmovnge Reg32 (Disp, Reg32) where + cmovnge (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_lt True dest source disp + +instance Cmovnge Reg32 Ind where + cmovnge (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_lt True dest source 0 + +class Cmovnl a b where + cmovnl :: a -> b -> CodeGen e s () + +instance Cmovnl Reg32 Reg32 where + cmovnl (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_ge True dest source + +instance Cmovnl Reg32 Addr where + cmovnl (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_ge True dest source + +instance Cmovnl Reg32 (Disp, Reg32) where + cmovnl (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ge True dest source disp + +instance Cmovnl Reg32 Ind where + cmovnl (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ge True dest source 0 + +class Cmovnle a b where + cmovnle :: a -> b -> CodeGen e s () + +instance Cmovnle Reg32 Reg32 where + cmovnle (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_gt True dest source + +instance Cmovnle Reg32 Addr where + cmovnle (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_gt True dest source + +instance Cmovnle Reg32 (Disp, Reg32) where + cmovnle (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_gt True dest source disp + +instance Cmovnle Reg32 Ind where + cmovnle (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_gt True dest source 0 + +class Cmovno a b where + cmovno :: a -> b -> CodeGen e s () + +instance Cmovno Reg32 Reg32 where + cmovno (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_no True dest source + +instance Cmovno Reg32 Addr where + cmovno (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_no True dest source + +instance Cmovno Reg32 (Disp, Reg32) where + cmovno (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_no True dest source disp + +instance Cmovno Reg32 Ind where + cmovno (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_no True dest source 0 + +class Cmovns a b where + cmovns :: a -> b -> CodeGen e s () + +instance Cmovns Reg32 Reg32 where + cmovns (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_ns True dest source + +instance Cmovns Reg32 Addr where + cmovns (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_ns True dest source + +instance Cmovns Reg32 (Disp, Reg32) where + cmovns (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ns True dest source disp + +instance Cmovns Reg32 Ind where + cmovns (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_ns True dest source 0 + +class Cmovo a b where + cmovo :: a -> b -> CodeGen e s () + +instance Cmovo Reg32 Reg32 where + cmovo (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_o True dest source + +instance Cmovo Reg32 Addr where + cmovo (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_o True dest source + +instance Cmovo Reg32 (Disp, Reg32) where + cmovo (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_o True dest source disp + +instance Cmovo Reg32 Ind where + cmovo (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_o True dest source 0 + +class Cmovs a b where + cmovs :: a -> b -> CodeGen e s () + +instance Cmovs Reg32 Reg32 where + cmovs (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_reg x86_cc_s True dest source + +instance Cmovs Reg32 Addr where + cmovs (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_mem x86_cc_s True dest source + +instance Cmovs Reg32 (Disp, Reg32) where + cmovs (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_s True dest source disp + +instance Cmovs Reg32 Ind where + cmovs (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_cmov_membase x86_cc_s True dest source 0 + + +-- release stack frame + +leave :: CodeGen e s () +leave = ensureBufferSize x86_max_instruction_bytes >> x86_leave + + +-- store ah into flags + +sahf :: CodeGen e s () +sahf = ensureBufferSize x86_max_instruction_bytes >> x86_sahf + +-- Floating point instructions + +fldz = ensureBufferSize x86_max_instruction_bytes >> x86_fldz +fld1 = ensureBufferSize x86_max_instruction_bytes >> x86_fld1 +fldpi = ensureBufferSize x86_max_instruction_bytes >> x86_fldpi + +fstsw = ensureBufferSize x86_max_instruction_bytes >> x86_fstsw +fnstsw = ensureBufferSize x86_max_instruction_bytes >> x86_fstsw + +fcompp = ensureBufferSize x86_max_instruction_bytes >> x86_fcompp +fucompp = ensureBufferSize x86_max_instruction_bytes >> x86_fucompp + +fchs = ensureBufferSize x86_max_instruction_bytes >> x86_fchs +frem = ensureBufferSize x86_max_instruction_bytes >> x86_frem + +fxch (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fxch idx + +fcomi (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fcomi idx +fcomip (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fcomip idx +fucomi (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fucomi idx +fucomip (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fucomip idx + +fsin = ensureBufferSize x86_max_instruction_bytes >> x86_fsin +fcos = ensureBufferSize x86_max_instruction_bytes >> x86_fcos +fptan = ensureBufferSize x86_max_instruction_bytes >> x86_fptan +fpatan = ensureBufferSize x86_max_instruction_bytes >> x86_fpatan +fabs = ensureBufferSize x86_max_instruction_bytes >> x86_fabs +ftst = ensureBufferSize x86_max_instruction_bytes >> x86_ftst +fxam = ensureBufferSize x86_max_instruction_bytes >> x86_fxam +fprem = ensureBufferSize x86_max_instruction_bytes >> x86_fprem +fprem1 = ensureBufferSize x86_max_instruction_bytes >> x86_fprem1 +frndint = ensureBufferSize x86_max_instruction_bytes >> x86_frndint +fsqrt = ensureBufferSize x86_max_instruction_bytes >> x86_fsqrt + +class Fadd a b where + fadd :: a -> b -> CodeGen e s () + +instance Fadd FPTopReg FPReg where + fadd FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fadd idx + +instance Fadd FPTopReg Addr where + fadd FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fadd a True + +instance Fadd FPTopReg (Disp, Reg32) where + fadd FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fadd r d True + +instance Fadd FPTopReg Ind where + fadd FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fadd r 0 True + +instance Fadd FPReg FPTopReg where + fadd (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fadd idx False + + +class Faddp a b where + faddp :: a -> b -> CodeGen e s () + +instance Faddp FPReg FPTopReg where + faddp (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fadd idx True + + +class Fiadd a b where + fiadd32 :: a -> b -> CodeGen e s () + fiadd16 :: a -> b -> CodeGen e s () + +instance Fiadd FPTopReg (Disp, Reg32) where + fiadd32 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fadd r d True + fiadd16 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fadd r d False + +instance Fiadd FPTopReg Ind where + fiadd32 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fadd r 0 True + fiadd16 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fadd r 0 False + + +class Fsub a b where + fsub :: a -> b -> CodeGen e s () + +instance Fsub FPTopReg FPReg where + fsub FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fsub idx + +instance Fsub FPTopReg Addr where + fsub FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fsub a True + +instance Fsub FPTopReg (Disp, Reg32) where + fsub FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fsub r d True + +instance Fsub FPTopReg Ind where + fsub FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fsub r 0 True + +instance Fsub FPReg FPTopReg where + fsub (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fsub idx False + + +class Fsubp a b where + fsubp :: a -> b -> CodeGen e s () + +instance Fsubp FPReg FPTopReg where + fsubp (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fsub idx True + + +class Fisub a b where + fisub32 :: a -> b -> CodeGen e s () + fisub16 :: a -> b -> CodeGen e s () + +instance Fisub FPTopReg (Disp, Reg32) where + fisub32 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fsub r d True + fisub16 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fsub r d False + +instance Fisub FPTopReg Ind where + fisub32 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fsub r 0 True + fisub16 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fsub r 0 False + + +class Fsubr a b where + fsubr :: a -> b -> CodeGen e s () + +instance Fsubr FPTopReg FPReg where + fsubr FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fsubr idx + +instance Fsubr FPTopReg Addr where + fsubr FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fsubr a True + +instance Fsubr FPTopReg (Disp, Reg32) where + fsubr FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fsubr r d True + +instance Fsubr FPTopReg Ind where + fsubr FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fsubr r 0 True + + +class Fmul a b where + fmul :: a -> b -> CodeGen e s () + +instance Fmul FPTopReg FPReg where + fmul FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fmul idx + +instance Fmul FPTopReg Addr where + fmul FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fmul a True + +instance Fmul FPTopReg (Disp, Reg32) where + fmul FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fmul r d True + +instance Fmul FPTopReg Ind where + fmul FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fmul r 0 True + +instance Fmul FPReg FPTopReg where + fmul (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fmul idx False + + +class Fmulp a b where + fmulp :: a -> b -> CodeGen e s () + +instance Fmulp FPReg FPTopReg where + fmulp (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fmul idx True + + +class Fimul a b where + fimul32 :: a -> b -> CodeGen e s () + fimul16 :: a -> b -> CodeGen e s () + +instance Fimul FPTopReg (Disp, Reg32) where + fimul32 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fmul r d True + fimul16 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fmul r d False + +instance Fimul FPTopReg Ind where + fimul32 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fmul r 0 True + fimul16 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fmul r 0 False + + +class Fdiv a b where + fdiv :: a -> b -> CodeGen e s () + +instance Fdiv FPTopReg FPReg where + fdiv FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fdiv idx + +instance Fdiv FPTopReg Addr where + fdiv FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fdiv a True + +instance Fdiv FPTopReg (Disp, Reg32) where + fdiv FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fdiv r d True + +instance Fdiv FPTopReg Ind where + fdiv FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fdiv r 0 True + +instance Fdiv FPReg FPTopReg where + fdiv (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fdiv idx False + + +class Fdivp a b where + fdivp :: a -> b -> CodeGen e s () + +instance Fdivp FPReg FPTopReg where + fdivp (FPReg idx) FPTopReg = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_reg x86_fdiv idx True + + +class Fidiv a b where + fidiv32 :: a -> b -> CodeGen e s () + fidiv16 :: a -> b -> CodeGen e s () + +instance Fidiv FPTopReg (Disp, Reg32) where + fidiv32 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fdiv r d True + fidiv16 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fdiv r d False + +instance Fidiv FPTopReg Ind where + fidiv32 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fdiv r 0 True + fidiv16 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_int_op_membase x86_fdiv r 0 False + + +class Fdivr a b where + fdivr :: a -> b -> CodeGen e s () + +instance Fdivr FPTopReg FPReg where + fdivr FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fdivr idx + +instance Fdivr FPTopReg Addr where + fdivr FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fdivr a True + +instance Fdivr FPTopReg (Disp, Reg32) where + fdivr FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fdivr r d True + +instance Fdivr FPTopReg Ind where + fdivr FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fdivr r 0 True + + +class Fcom a b where + fcom :: a -> b -> CodeGen e s () + +instance Fcom FPTopReg FPReg where + fcom FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fcom idx + +instance Fcom FPTopReg Addr where + fcom FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fcom a True + +instance Fcom FPTopReg (Disp, Reg32) where + fcom FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fcom r d True + +instance Fcom FPTopReg Ind where + fcom FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fcom r 0 True + + +class Fcomp a b where + fcomp :: a -> b -> CodeGen e s () + +instance Fcomp FPTopReg FPReg where + fcomp FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op x86_fcomp idx + +instance Fcomp FPTopReg Addr where + fcomp FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_mem x86_fcomp a True + +instance Fcomp FPTopReg (Disp, Reg32) where + fcomp FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fcomp r d True + +instance Fcomp FPTopReg Ind where + fcomp FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fp_op_membase x86_fcomp r 0 True + + +class Fld a b where + fld :: a -> b -> CodeGen e s () + +instance Fld FPTopReg FPReg where + fld FPTopReg (FPReg idx) = ensureBufferSize x86_max_instruction_bytes >> x86_fld_reg idx + +instance Fld FPTopReg Addr where + fld FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fld a True + +instance Fld FPTopReg (Disp, Reg32) where + fld FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fld_membase r d True + +instance Fld FPTopReg Ind where + fld FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fld_membase r 0 True + +class Fld80 a b where + fld80 :: a -> b -> CodeGen e s () + +instance Fld80 FPTopReg Addr where + fld80 FPTopReg (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fld80_mem a + +instance Fld80 FPTopReg (Disp, Reg32) where + fld80 FPTopReg (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fld80_membase r d + +instance Fld80 FPTopReg Ind where + fld80 FPTopReg (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fld80_membase r 0 + +class Fst a where + fst :: a -> CodeGen e s () + +instance Fst Addr where + fst (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fst a True False + +instance Fst (Disp, Reg32) where + fst (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fst_membase r d True False + +instance Fst Ind where + fst (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fst_membase r 0 True False + +class Fstp a where + fstp :: a -> CodeGen e s () + +instance Fstp FPReg where + fstp (FPReg r) = ensureBufferSize x86_max_instruction_bytes >> x86_fstp r + +instance Fstp Addr where + fstp (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fst a True True + +instance Fstp (Disp, Reg32) where + fstp (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fst_membase r d True True + +instance Fstp Ind where + fstp (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fst_membase r 0 True True + + +class Fst80 a where + fst80 :: a -> CodeGen e s () + +instance Fst80 Addr where + fst80 (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fst80_mem a + +instance Fst80 (Disp, Reg32) where + fst80 (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fst80_membase r d + +instance Fst80 Ind where + fst80 (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fst80_membase r 0 + + +class Fnstcw a where + fnstcw :: a -> CodeGen e s () + +instance Fnstcw Addr where + fnstcw (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fnstcw a + +instance Fnstcw (Disp, Reg32) where + fnstcw (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fnstcw_membase r d + +instance Fnstcw Ind where + fnstcw (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fnstcw_membase r 0 + + +class Fldcw a where + fldcw :: a -> CodeGen e s () + +instance Fldcw Addr where + fldcw (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fldcw a + +instance Fldcw (Disp, Reg32) where + fldcw (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fldcw_membase r d + +instance Fldcw Ind where + fldcw (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fldcw_membase r 0 + + +class Fild a where + fild :: a -> CodeGen e s () + +instance Fild Addr where + fild (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fild a FInt32 + +instance Fild (Disp, Reg32) where + fild (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fild_membase r d FInt32 + +instance Fild Ind where + fild (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fild_membase r 0 FInt32 + + +class Fist a where + fist :: a -> CodeGen e s () + +instance Fist (Disp, Reg32) where + fist (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fist_membase r d FInt32 + +instance Fist Ind where + fist (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fist_membase r 0 FInt32 + + +class Fistp a where + fistp :: a -> CodeGen e s () + +instance Fistp Addr where + fistp (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_fist_pop a FInt32 + +instance Fistp (Disp, Reg32) where + fistp (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_fist_pop_membase r d FInt32 + +instance Fistp Ind where + fistp (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_fist_pop_membase r 0 FInt32 + + +class Sqrtsd a b where + sqrtsd :: a -> b -> CodeGen e s () + +instance Sqrtsd XMMReg XMMReg where + sqrtsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_reg x86_sse_sd xd xs + +instance Sqrtsd XMMReg Addr where + sqrtsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_mem x86_sse_sd xd a + +instance Sqrtsd XMMReg Ind where + sqrtsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_sd xd r 0 + +instance Sqrtsd XMMReg (Disp, Reg32) where + sqrtsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_sd xd r d + + +class Sqrtss a b where + sqrtss :: a -> b -> CodeGen e s () + +instance Sqrtss XMMReg XMMReg where + sqrtss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_reg x86_sse_ss xd xs + +instance Sqrtss XMMReg Addr where + sqrtss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_mem x86_sse_ss xd a + +instance Sqrtss XMMReg Ind where + sqrtss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_ss xd r 0 + +instance Sqrtss XMMReg (Disp, Reg32) where + sqrtss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_ss xd r d + + +class Sqrtpd a b where + sqrtpd :: a -> b -> CodeGen e s () + +instance Sqrtpd XMMReg XMMReg where + sqrtpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_reg x86_sse_pd xd xs + +instance Sqrtpd XMMReg Addr where + sqrtpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_mem x86_sse_pd xd a + +instance Sqrtpd XMMReg Ind where + sqrtpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_pd xd r 0 + +instance Sqrtpd XMMReg (Disp, Reg32) where + sqrtpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_pd xd r d + + +class Sqrtps a b where + sqrtps :: a -> b -> CodeGen e s () + +instance Sqrtps XMMReg XMMReg where + sqrtps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_reg x86_sse_ps xd xs + +instance Sqrtps XMMReg Addr where + sqrtps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_mem x86_sse_ps xd a + +instance Sqrtps XMMReg Ind where + sqrtps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_ps xd r 0 + +instance Sqrtps XMMReg (Disp, Reg32) where + sqrtps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sqrt_sse_reg_membase x86_sse_ps xd r d + + +class Addsd a b where + addsd :: a -> b -> CodeGen e s () + +instance Addsd XMMReg XMMReg where + addsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_reg x86_sse_sd xd xs + +instance Addsd XMMReg Addr where + addsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_mem x86_sse_sd xd a + +instance Addsd XMMReg Ind where + addsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_sd xd r 0 + +instance Addsd XMMReg (Disp, Reg32) where + addsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_sd xd r d + + +class Addss a b where + addss :: a -> b -> CodeGen e s () + +instance Addss XMMReg XMMReg where + addss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_reg x86_sse_ss xd xs + +instance Addss XMMReg Addr where + addss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_mem x86_sse_ss xd a + +instance Addss XMMReg Ind where + addss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_ss xd r 0 + +instance Addss XMMReg (Disp, Reg32) where + addss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_ss xd r d + + +class Addpd a b where + addpd :: a -> b -> CodeGen e s () + +instance Addpd XMMReg XMMReg where + addpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_reg x86_sse_pd xd xs + +instance Addpd XMMReg Addr where + addpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_mem x86_sse_pd xd a + +instance Addpd XMMReg Ind where + addpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_pd xd r 0 + +instance Addpd XMMReg (Disp, Reg32) where + addpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_pd xd r d + + +class Addps a b where + addps :: a -> b -> CodeGen e s () + +instance Addps XMMReg XMMReg where + addps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_reg x86_sse_ps xd xs + +instance Addps XMMReg Addr where + addps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_mem x86_sse_ps xd a + +instance Addps XMMReg Ind where + addps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_ps xd r 0 + +instance Addps XMMReg (Disp, Reg32) where + addps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_add_sse_reg_membase x86_sse_ps xd r d + +class Subsd a b where + subsd :: a -> b -> CodeGen e s () + +instance Subsd XMMReg XMMReg where + subsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_reg x86_sse_sd xd xs + +instance Subsd XMMReg Addr where + subsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_mem x86_sse_sd xd a + +instance Subsd XMMReg Ind where + subsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_sd xd r 0 + +instance Subsd XMMReg (Disp, Reg32) where + subsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_sd xd r d + + +class Subss a b where + subss :: a -> b -> CodeGen e s () + +instance Subss XMMReg XMMReg where + subss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_reg x86_sse_ss xd xs + +instance Subss XMMReg Addr where + subss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_mem x86_sse_ss xd a + +instance Subss XMMReg Ind where + subss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_ss xd r 0 + +instance Subss XMMReg (Disp, Reg32) where + subss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_ss xd r d + + +class Subpd a b where + subpd :: a -> b -> CodeGen e s () + +instance Subpd XMMReg XMMReg where + subpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_reg x86_sse_pd xd xs + +instance Subpd XMMReg Addr where + subpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_mem x86_sse_pd xd a + +instance Subpd XMMReg Ind where + subpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_pd xd r 0 + +instance Subpd XMMReg (Disp, Reg32) where + subpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_pd xd r d + + +class Subps a b where + subps :: a -> b -> CodeGen e s () + +instance Subps XMMReg XMMReg where + subps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_reg x86_sse_ps xd xs + +instance Subps XMMReg Addr where + subps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_mem x86_sse_ps xd a + +instance Subps XMMReg Ind where + subps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_ps xd r 0 + +instance Subps XMMReg (Disp, Reg32) where + subps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_sub_sse_reg_membase x86_sse_ps xd r d + +class Mulsd a b where + mulsd :: a -> b -> CodeGen e s () + +instance Mulsd XMMReg XMMReg where + mulsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_reg x86_sse_sd xd xs + +instance Mulsd XMMReg Addr where + mulsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_mem x86_sse_sd xd a + +instance Mulsd XMMReg Ind where + mulsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_sd xd r 0 + +instance Mulsd XMMReg (Disp, Reg32) where + mulsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_sd xd r d + + +class Mulss a b where + mulss :: a -> b -> CodeGen e s () + +instance Mulss XMMReg XMMReg where + mulss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_reg x86_sse_ss xd xs + +instance Mulss XMMReg Addr where + mulss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_mem x86_sse_ss xd a + +instance Mulss XMMReg Ind where + mulss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_ss xd r 0 + +instance Mulss XMMReg (Disp, Reg32) where + mulss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_ss xd r d + + +class Mulpd a b where + mulpd :: a -> b -> CodeGen e s () + +instance Mulpd XMMReg XMMReg where + mulpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_reg x86_sse_pd xd xs + +instance Mulpd XMMReg Addr where + mulpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_mem x86_sse_pd xd a + +instance Mulpd XMMReg Ind where + mulpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_pd xd r 0 + +instance Mulpd XMMReg (Disp, Reg32) where + mulpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_pd xd r d + + +class Mulps a b where + mulps :: a -> b -> CodeGen e s () + +instance Mulps XMMReg XMMReg where + mulps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_reg x86_sse_ps xd xs + +instance Mulps XMMReg Addr where + mulps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_mem x86_sse_ps xd a + +instance Mulps XMMReg Ind where + mulps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_ps xd r 0 + +instance Mulps XMMReg (Disp, Reg32) where + mulps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_mul_sse_reg_membase x86_sse_ps xd r d + + +class Divsd a b where + divsd :: a -> b -> CodeGen e s () + +instance Divsd XMMReg XMMReg where + divsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_reg x86_sse_sd xd xs + +instance Divsd XMMReg Addr where + divsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_mem x86_sse_sd xd a + +instance Divsd XMMReg Ind where + divsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_sd xd r 0 + +instance Divsd XMMReg (Disp, Reg32) where + divsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_sd xd r d + + +class Divss a b where + divss :: a -> b -> CodeGen e s () + +instance Divss XMMReg XMMReg where + divss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_reg x86_sse_ss xd xs + +instance Divss XMMReg Addr where + divss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_mem x86_sse_ss xd a + +instance Divss XMMReg Ind where + divss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_ss xd r 0 + +instance Divss XMMReg (Disp, Reg32) where + divss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_ss xd r d + + +class Divpd a b where + divpd :: a -> b -> CodeGen e s () + +instance Divpd XMMReg XMMReg where + divpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_reg x86_sse_pd xd xs + +instance Divpd XMMReg Addr where + divpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_mem x86_sse_pd xd a + +instance Divpd XMMReg Ind where + divpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_pd xd r 0 + +instance Divpd XMMReg (Disp, Reg32) where + divpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_pd xd r d + + +class Divps a b where + divps :: a -> b -> CodeGen e s () + +instance Divps XMMReg XMMReg where + divps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_reg x86_sse_ps xd xs + +instance Divps XMMReg Addr where + divps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_mem x86_sse_ps xd a + +instance Divps XMMReg Ind where + divps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_ps xd r 0 + +instance Divps XMMReg (Disp, Reg32) where + divps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_div_sse_reg_membase x86_sse_ps xd r d + +class Minsd a b where + minsd :: a -> b -> CodeGen e s () + +instance Minsd XMMReg XMMReg where + minsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_reg x86_sse_sd xd xs + +instance Minsd XMMReg Addr where + minsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_mem x86_sse_sd xd a + +instance Minsd XMMReg Ind where + minsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_sd xd r 0 + +instance Minsd XMMReg (Disp, Reg32) where + minsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_sd xd r d + + +class Minss a b where + minss :: a -> b -> CodeGen e s () + +instance Minss XMMReg XMMReg where + minss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_reg x86_sse_ss xd xs + +instance Minss XMMReg Addr where + minss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_mem x86_sse_ss xd a + +instance Minss XMMReg Ind where + minss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_ss xd r 0 + +instance Minss XMMReg (Disp, Reg32) where + minss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_ss xd r d + + +class Minpd a b where + minpd :: a -> b -> CodeGen e s () + +instance Minpd XMMReg XMMReg where + minpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_reg x86_sse_pd xd xs + +instance Minpd XMMReg Addr where + minpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_mem x86_sse_pd xd a + +instance Minpd XMMReg Ind where + minpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_pd xd r 0 + +instance Minpd XMMReg (Disp, Reg32) where + minpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_pd xd r d + + +class Minps a b where + minps :: a -> b -> CodeGen e s () + +instance Minps XMMReg XMMReg where + minps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_reg x86_sse_ps xd xs + +instance Minps XMMReg Addr where + minps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_mem x86_sse_ps xd a + +instance Minps XMMReg Ind where + minps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_ps xd r 0 + +instance Minps XMMReg (Disp, Reg32) where + minps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_min_sse_reg_membase x86_sse_ps xd r d + + +class Maxsd a b where + maxsd :: a -> b -> CodeGen e s () + +instance Maxsd XMMReg XMMReg where + maxsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_reg x86_sse_sd xd xs + +instance Maxsd XMMReg Addr where + maxsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_mem x86_sse_sd xd a + +instance Maxsd XMMReg Ind where + maxsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_sd xd r 0 + +instance Maxsd XMMReg (Disp, Reg32) where + maxsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_sd xd r d + + +class Maxss a b where + maxss :: a -> b -> CodeGen e s () + +instance Maxss XMMReg XMMReg where + maxss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_reg x86_sse_ss xd xs + +instance Maxss XMMReg Addr where + maxss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_mem x86_sse_ss xd a + +instance Maxss XMMReg Ind where + maxss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_ss xd r 0 + +instance Maxss XMMReg (Disp, Reg32) where + maxss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_ss xd r d + + +class Maxpd a b where + maxpd :: a -> b -> CodeGen e s () + +instance Maxpd XMMReg XMMReg where + maxpd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_reg x86_sse_pd xd xs + +instance Maxpd XMMReg Addr where + maxpd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_mem x86_sse_pd xd a + +instance Maxpd XMMReg Ind where + maxpd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_pd xd r 0 + +instance Maxpd XMMReg (Disp, Reg32) where + maxpd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_pd xd r d + + +class Maxps a b where + maxps :: a -> b -> CodeGen e s () + +instance Maxps XMMReg XMMReg where + maxps (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_reg x86_sse_ps xd xs + +instance Maxps XMMReg Addr where + maxps (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_mem x86_sse_ps xd a + +instance Maxps XMMReg Ind where + maxps (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_ps xd r 0 + +instance Maxps XMMReg (Disp, Reg32) where + maxps (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_max_sse_reg_membase x86_sse_ps xd r d + + +class Movss a b where + movss :: a -> b -> CodeGen e s () + +instance Movss XMMReg XMMReg where + movss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_reg x86_sse_ss xd xs + +instance Movss XMMReg Addr where + movss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_mem x86_sse_ss xd a + +instance Movss Addr XMMReg where + movss (Addr a) (XMMReg xd) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_mem_reg x86_sse_ss a xd + +instance Movss XMMReg Ind where + movss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_membase x86_sse_ss xd r 0 + +instance Movss Ind XMMReg where + movss (Ind (Reg32 r)) (XMMReg xd) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_membase_reg x86_sse_ss r 0 xd + +instance Movss XMMReg (Disp, Reg32) where + movss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_membase x86_sse_ss xd r d + +instance Movss (Disp, Reg32) XMMReg where + movss (Disp d, Reg32 r) (XMMReg xd) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_membase_reg x86_sse_ss r d xd + + +class Movsd a b where + movsd :: a -> b -> CodeGen e s () + +instance Movsd XMMReg XMMReg where + movsd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_reg x86_sse_sd xd xs + +instance Movsd XMMReg Addr where + movsd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_mem x86_sse_sd xd a + +instance Movsd Addr XMMReg where + movsd (Addr a) (XMMReg xd) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_mem_reg x86_sse_sd a xd + +instance Movsd XMMReg Ind where + movsd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_membase x86_sse_sd xd r 0 + +instance Movsd Ind XMMReg where + movsd (Ind (Reg32 r)) (XMMReg xd) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_membase_reg x86_sse_sd r 0 xd + +instance Movsd XMMReg (Disp, Reg32) where + movsd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_reg_membase x86_sse_sd xd r d + +instance Movsd (Disp, Reg32) XMMReg where + movsd (Disp d, Reg32 r) (XMMReg xd) = ensureBufferSize x86_max_instruction_bytes >> x86_mov_sse_membase_reg x86_sse_sd r d xd + + +class Movups a b where + movups :: a -> b -> CodeGen e s () + +instance Movups XMMReg XMMReg where + movups (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movups_to_reg xd (xmmLocLowLevel xs) + +instance Movups XMMReg Addr where + movups (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movups_to_reg xd (xmmLocLowLevel xs) + +instance Movups Addr XMMReg where + movups xd (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_movups_from_reg xs (xmmLocLowLevel xd) + +instance Movups XMMReg Ind where + movups (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movups_to_reg xd (xmmLocLowLevel xs) + +instance Movups Ind XMMReg where + movups xd (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_movups_from_reg xs (xmmLocLowLevel xd) + +instance Movups XMMReg (Disp, Reg32) where + movups (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movups_to_reg xd (xmmLocLowLevel xs) + +instance Movups (Disp, Reg32) XMMReg where + movups xd (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_movups_from_reg xs (xmmLocLowLevel xd) + + +class Movlps a b where + movlps :: a -> b -> CodeGen e s () + +instance Movlps XMMReg XMMReg where + movlps (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_to_reg xd (xmmLocLowLevel xs) + +instance Movlps XMMReg Addr where + movlps (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_to_reg xd (xmmLocLowLevel xs) + +instance Movlps Addr XMMReg where + movlps xd (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_from_reg xs (xmmLocLowLevel xd) + +instance Movlps XMMReg Ind where + movlps (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_to_reg xd (xmmLocLowLevel xs) + +instance Movlps Ind XMMReg where + movlps xd (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_from_reg xs (xmmLocLowLevel xd) + +instance Movlps XMMReg (Disp, Reg32) where + movlps (XMMReg xd) xs = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_to_reg xd (xmmLocLowLevel xs) + +instance Movlps (Disp, Reg32) XMMReg where + movlps xd (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_movlps_from_reg xs (xmmLocLowLevel xd) + + +class Comisd a b where + comisd :: a -> b -> CodeGen e s () + +instance Comisd XMMReg XMMReg where + comisd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_comisd_reg_reg xd xs + +instance Comisd XMMReg Addr where + comisd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_comisd_reg_mem xd a + +instance Comisd XMMReg Ind where + comisd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_comisd_reg_membase xd r 0 + +instance Comisd XMMReg (Disp, Reg32) where + comisd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_comisd_reg_membase xd r d + + +class Comiss a b where + comiss :: a -> b -> CodeGen e s () + +instance Comiss XMMReg XMMReg where + comiss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_comiss_reg_reg xd xs + +instance Comiss XMMReg Addr where + comiss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_comiss_reg_mem xd a + +instance Comiss XMMReg Ind where + comiss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_comiss_reg_membase xd r 0 + +instance Comiss XMMReg (Disp, Reg32) where + comiss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_comiss_reg_membase xd r d + + +class Ucomisd a b where + ucomisd :: a -> b -> CodeGen e s () + +instance Ucomisd XMMReg XMMReg where + ucomisd (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomisd_reg_reg xd xs + +instance Ucomisd XMMReg Addr where + ucomisd (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomisd_reg_mem xd a + +instance Ucomisd XMMReg Ind where + ucomisd (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomisd_reg_membase xd r 0 + +instance Ucomisd XMMReg (Disp, Reg32) where + ucomisd (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomisd_reg_membase xd r d + + +class Ucomiss a b where + ucomiss :: a -> b -> CodeGen e s () + +instance Ucomiss XMMReg XMMReg where + ucomiss (XMMReg xd) (XMMReg xs) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomiss_reg_reg xd xs + +instance Ucomiss XMMReg Addr where + ucomiss (XMMReg xd) (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomiss_reg_mem xd a + +instance Ucomiss XMMReg Ind where + ucomiss (XMMReg xd) (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomiss_reg_membase xd r 0 + +instance Ucomiss XMMReg (Disp, Reg32) where + ucomiss (XMMReg xd) (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_ucomiss_reg_membase xd r d + + +class XMMLocation b => XMMLoc a b | a -> b where + xmmLocLowLevel :: a -> b + +instance XMMLoc XMMReg XMMReg where + xmmLocLowLevel = id + +instance XMMLoc Addr Mem where + xmmLocLowLevel (Addr a) = Mem a + +instance XMMLoc Ind MemBase where + xmmLocLowLevel (Ind (Reg32 r)) = MemBase r 0 + +instance XMMLoc (Disp, Reg32) MemBase where + xmmLocLowLevel (Disp d, Reg32 r) = MemBase r d + + +haddps :: XMMLoc xmm a => XMMReg -> xmm -> CodeGen e s () +haddps (XMMReg dreg) reg = + x86_haddps dreg (xmmLocLowLevel reg) + +haddpd :: XMMLoc xmm a => XMMReg -> xmm -> CodeGen e s () +haddpd (XMMReg dreg) reg = + x86_haddpd dreg (xmmLocLowLevel reg) + + +shufps :: XMMLoc xmm a => XMMReg -> xmm -> Word8 -> CodeGen e s () +shufps (XMMReg dreg) reg src = + x86_shufps dreg (xmmLocLowLevel reg) src + +shufpd :: XMMLoc xmm a => XMMReg -> xmm -> Word8 -> CodeGen e s () +shufpd (XMMReg dreg) reg src = + x86_shufpd dreg (xmmLocLowLevel reg) src + + +cvtdq2ps :: XMMLoc xmm a => XMMReg -> xmm -> CodeGen e s () +cvtdq2ps (XMMReg dreg) reg = + x86_cvtdq2ps dreg (xmmLocLowLevel reg) + +cvttps2dq :: XMMLoc xmm a => XMMReg -> xmm -> CodeGen e s () +cvttps2dq (XMMReg dreg) reg = + x86_cvttps2dq dreg (xmmLocLowLevel reg) + + +class Prefetchnta a where + prefetchnta :: a -> CodeGen e s () + +instance Prefetchnta Addr where + prefetchnta (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetchnta_mem a + +instance Prefetchnta (Disp, Reg32) where + prefetchnta (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetchnta_membase r d + +instance Prefetchnta Ind where + prefetchnta (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetchnta_regp r + +class Prefetch0 a where + prefetch0 :: a -> CodeGen e s () + +instance Prefetch0 Addr where + prefetch0 (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch0_mem a + +instance Prefetch0 (Disp, Reg32) where + prefetch0 (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch0_membase r d + +instance Prefetch0 Ind where + prefetch0 (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch0_regp r + +class Prefetch1 a where + prefetch1 :: a -> CodeGen e s () + +instance Prefetch1 Addr where + prefetch1 (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch1_mem a + +instance Prefetch1 (Disp, Reg32) where + prefetch1 (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch1_membase r d + +instance Prefetch1 Ind where + prefetch1 (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch1_regp r + +class Prefetch2 a where + prefetch2 :: a -> CodeGen e s () + +instance Prefetch2 Addr where + prefetch2 (Addr a) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch2_mem a + +instance Prefetch2 (Disp, Reg32) where + prefetch2 (Disp d, Reg32 r) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch2_membase r d + +instance Prefetch2 Ind where + prefetch2 (Ind (Reg32 r)) = ensureBufferSize x86_max_instruction_bytes >> x86_prefetch2_regp r + + +ptrToWord32 :: Ptr a -> Word32 +ptrToWord32 = fromIntegral . ptrToIntPtr + +ptrToInt :: Ptr a -> Int +ptrToInt = fromIntegral . ptrToIntPtr diff --git a/Harpy/X86CGCombinators.hs b/Harpy/X86CGCombinators.hs new file mode 100644 index 0000000..0da0afc --- /dev/null +++ b/Harpy/X86CGCombinators.hs @@ -0,0 +1,266 @@ +-------------------------------------------------------------------------- +-- | +-- Module : X86CodeGen +-- Copyright : (c) 2006 Martin Grabmueller and Dirk Kleeblatt +-- License : GPL +-- +-- Maintainer : {magr,klee}@cs.tu-berlin.de +-- Stability : quite experimental +-- Portability : portable (but generated code non-portable) +-- +-- This module exports several combinators for writing loops, +-- conditionals and function prolog\/epilog code. +-- +-- Note: this module is under heavy development and the exported API +-- is definitely not yet stable. +-------------------------------------------------------------------------- + +module Harpy.X86CGCombinators( + -- * Types + UserState(..), + UserEnv(..), + emptyUserEnv, + emptyUserState, + CtrlDest(..), + DataDest(..), + -- * Combinators + ifThenElse, + doWhile, + continue, + continueBranch, + saveRegs, + function, + withDataDest, + withCtrlDest, + withDest, + ) where + +import Text.PrettyPrint.HughesPJ + +import Foreign +import Data.Word + +import Harpy.CodeGenMonad +import Harpy.X86CodeGen +import Harpy.X86Assembler + +-- | Destination for a calculated value. +data DataDest = RegDest Reg32 -- ^ Store into specific register + | StackDest -- ^ Push onto stack + | MemBaseDest Reg32 Word32 -- ^ Store at memory address + | Ignore -- ^ Throw result away. + +-- | Destination for control transfers +data CtrlDest = FallThrough -- ^ Go to next instruction + | Return -- ^ Return from current functio + | Goto Label -- ^ Go to specific label + | Branch CtrlDest CtrlDest -- ^ Go to one of the given labels + -- depending on outcome of test + +-- | User state is used to maintain bitmask of registers currently in use. +data UserState = UserState {} + + +-- | User environment stores code generators for accessing specific +-- variables as well as the current data and control destinations +data UserEnv = UserEnv { bindings :: [(String, CodeGen UserEnv UserState ())], + dataDest :: DataDest, + ctrlDest :: CtrlDest } + +emptyUserState :: UserState +emptyUserState = UserState{} + +emptyUserEnv :: UserEnv +emptyUserEnv = UserEnv{bindings = [], dataDest = Ignore, + ctrlDest = Return} + +ifThenElse :: CodeGen UserEnv s r + -> CodeGen UserEnv s a + -> CodeGen UserEnv s a1 + -> CodeGen UserEnv s () +ifThenElse condCg thenCg elseCg = + do env <- getEnv + elseLabel <- newLabel + endLabel <- newLabel + withDest Ignore (Branch FallThrough (Goto elseLabel)) condCg + withCtrlDest (case ctrlDest env of + FallThrough -> Goto endLabel + _ -> ctrlDest env) + (thenCg >> continue) + elseLabel @@ (elseCg >> continue) + endLabel @@ return () + +doWhile :: CodeGen UserEnv s r -> CodeGen UserEnv s a -> CodeGen UserEnv s () +doWhile condCg bodyCg = + do topLabel <- newLabel + testLabel <- newLabel + jmp testLabel + topLabel @@ withCtrlDest FallThrough (bodyCg >> continue) + testLabel @@ withDest Ignore (Branch (Goto topLabel) FallThrough) + condCg + continue + +doFor :: (Mov a Word32, Add a Word32, Cmp a Word32) => a -> Word32 -> Word32 -> Int32 -> + CodeGen UserEnv s r -> + CodeGen UserEnv s () +doFor loc from to step body = + do topLabel <- newLabel + testLabel <- newLabel + mov loc from + jmp testLabel + topLabel @@ withCtrlDest FallThrough (body >> continue) + testLabel @@ cmp loc to + add loc (fromIntegral step :: Word32) + if step < 0 + then jge topLabel + else jle topLabel + continue + + +continue :: CodeGen UserEnv s () +continue = + do env <- getEnv + cont (ctrlDest env) + where + cont FallThrough = return () + cont (Goto l) = jmp l + cont (Branch _ _) = error "Branch in continue" + cont Return = x86_epilog 0 + + +continueBranch :: Int -> Bool -> CodeGen UserEnv s () +continueBranch cc isSigned = + do env <- getEnv + let Branch c1 c2 = ctrlDest env + cont cc isSigned c1 c2 + where + cont cc isSigned (Goto l1) (Goto l2) = + do x86_branch32 cc 0 isSigned + emitFixup l1 (-4) Fixup32 + x86_branch32 (negateCC cc) 0 isSigned + emitFixup l2 (-4) Fixup32 + cont cc isSigned (Goto l1) FallThrough = + do x86_branch32 cc 0 isSigned + emitFixup l1 (-4) Fixup32 + cont cc isSigned FallThrough (Goto l2) = + do x86_branch32 (negateCC cc) 0 isSigned + emitFixup l2 (-4) Fixup32 + cont cc isSigned (Goto l1) Return = + do x86_branch32 cc 0 isSigned + emitFixup l1 (-4) Fixup32 + withCtrlDest Return continue + cont cc isSigned Return (Goto l2) = + do x86_branch32 (negateCC cc) 0 isSigned + emitFixup l2 (-4) Fixup32 + withCtrlDest Return continue + cont _ _ _ _ = error "unhandled case in continueBranch" + +reg sreg = + do env <- getEnv + reg' sreg (dataDest env) + where + reg' sreg (RegDest r) = + do if sreg /= r + then mov r sreg + else return () + reg' sreg (StackDest) = + do push sreg + reg' sreg (MemBaseDest r offset) = + do mov (Disp offset, r) sreg + reg' sreg Ignore = return () + +membase reg ofs = + do env <- getEnv + membase' reg ofs (dataDest env) + where + membase' reg ofs (RegDest r) = + do mov r (Disp ofs, reg) + membase' reg ofs (StackDest) = + do push (Disp ofs, reg) + membase' reg ofs (MemBaseDest r offset) = + do push edi + mov edi (Disp ofs, reg) + mov (Disp offset, r) edi + pop edi + membase' reg ofs Ignore = return () + +global ofs = + do env <- getEnv + global' ofs (dataDest env) + where + global' ofs (RegDest r) = + do mov r (Addr ofs) + global' ofs (StackDest) = + do push (Addr ofs) + global' ofs (MemBaseDest r offset) = + do push edi + mov edi (Addr ofs) + mov (Disp offset, r) edi + pop edi + global' ofs Ignore = return () + +immediate value = + do env <- getEnv + immediate' value (dataDest env) + where + immediate' value (RegDest r) = + do mov r value + immediate' value (StackDest) = + do x86_push_imm value + immediate' value (MemBaseDest r offset) = + do push edi + mov edi value + mov (Disp offset, r) edi + pop edi + immediate' ofs Ignore = return () + +-- | Save a number of registers on the stack, perform the given code +-- generation, and restore the registers. +saveRegs :: [Reg32] -> CodeGen UserEnv s r -> CodeGen UserEnv s () +saveRegs [] cg = cg >> return () +saveRegs regs cg = + do gen_push regs + withCtrlDest FallThrough cg + gen_pop regs + continue + where + gen_push [] = return () + gen_push (r:regs) = push r >> gen_push regs + gen_pop [] = return () + gen_pop (r:regs) = gen_pop regs >> pop r + +-- | Perform the code generation associated with the variable given. +loadVar :: String -> CodeGen UserEnv UserState () +loadVar name = + do UserEnv{bindings = assoc} <- getEnv + case lookup name assoc of + Just cg -> cg + Nothing -> failCodeGen (text ("undefined variable: " ++ name)) + +-- | Set the data destinations to the given values while +-- running the code generator. +withDataDest :: DataDest -> CodeGen UserEnv s r -> CodeGen UserEnv s r +withDataDest ddest cg = + do env <- getEnv + withEnv (env{dataDest = ddest}) cg + +-- | Set the control destinations to the given values while +-- running the code generator. +withCtrlDest :: CtrlDest -> CodeGen UserEnv s r -> CodeGen UserEnv s r +withCtrlDest cdest cg = + do env <- getEnv + withEnv (env{ctrlDest = cdest}) cg + +-- | Set the data and control destinations to the given values while +-- running the code generator. +withDest :: DataDest -> CtrlDest -> CodeGen UserEnv s r -> CodeGen UserEnv s r +withDest ddest cdest cg = + do env <- getEnv + withEnv (env{dataDest = ddest, ctrlDest = cdest}) cg + +-- | Emit the necessary function prolog and epilog code and invoke the +-- given code generator for the code inbetween. +function :: CodeGen UserEnv s r -> CodeGen UserEnv s r +function cg = + do x86_prolog 0 0 + withDest (RegDest eax) Return $ cg diff --git a/Harpy/X86CodeGen.hs b/Harpy/X86CodeGen.hs new file mode 100644 index 0000000..fe8946a --- /dev/null +++ b/Harpy/X86CodeGen.hs @@ -0,0 +1,2184 @@ +-------------------------------------------------------------------------- +-- | +-- Module : X86CodeGen +-- Copyright : (c) 2006 Martin Grabmueller and Dirk Kleeblatt +-- License : GPL +-- +-- Maintainer : {magr,klee}@cs.tu-berlin.de +-- Stability : provisional +-- Portability : portable (but generated code non-portable) +-- +-- Functions for generating x86 machine code instructions. The +-- functions make use of the code generation monad in module +-- "Harpy.CodeGenMonad" for emitting binary code into a code buffer. +-- +-- This module is very low-level, since there are different +-- functions for different addressing modes. A more convenient +-- interface is provided in module "Harpy.X86Assembler", which uses +-- the operand types to determine the correct addressing modes for +-- all supported instructions. +-- +-- Note: this file does not (yet) provide the complete x86 +-- instruction set, not even all user-mode instructions. For some +-- operations, some addressing modes are missing as well. +-- +-- Copyright notice: +-- +-- The information in this file is based on the header file +-- x86-codegen.h from the mono distribution, which has the following +-- copyright information: +-- +-- @ +-- * x86-codegen.h: Macros for generating x86 code +-- * +-- * Authors: +-- * Paolo Molaro (lupus\@ximian.com) +-- * Intel Corporation (ORP Project) +-- * Sergey Chaban (serge\@wildwestsoftware.com) +-- * Dietmar Maurer (dietmar\@ximian.com) +-- * Patrik Torstensson +-- * +-- * Copyright (C) 2000 Intel Corporation. All rights reserved. +-- * Copyright (C) 2001, 2002 Ximian, Inc. +-- * +-- @ +-------------------------------------------------------------------------- + +module Harpy.X86CodeGen( + -- * Types + X86_SSE_PFX, + -- * Constants + -- ** Machine characteristics + -- | Sizes of various machine data types in bytes. + x86_dword_size, + x86_qword_size, + x86_max_instruction_bytes, + -- ** Register numbers + -- | x86 general-purpose register numbers + x86_eax, x86_ecx, x86_edx, x86_ebx, x86_esp, x86_ebp, x86_esi, x86_edi, + x86_nobasereg, + -- ** Register masks and predicates + -- | Bitvector masks for general-purpose registers + x86_eax_mask, x86_ecx_mask, x86_edx_mask, x86_ebx_mask, + x86_esi_mask, x86_edi_mask, x86_ebp_mask, + x86_callee_regs, x86_caller_regs, x86_byte_regs, + -- ** ALU operations + -- | Opcodes for ALU instructions + x86_add, x86_or, x86_adc, x86_sbb, x86_and, x86_sub, x86_xor, x86_cmp, + -- ** Shift operations + -- | Opcodes for shift instructions + x86_rol, x86_ror, x86_rcl, x86_rcr, x86_shl, + x86_shr, x86_sar, x86_shld, x86_shlr, + -- ** FP operations + -- | Opcodes for floating-point instructions + x86_fadd, x86_fmul, x86_fcom, x86_fcomp, x86_fsub, x86_fsubr, + x86_fdiv, x86_fdivr, + -- ** FP conditions and control codes + -- | FP status word codes + x86_fp_c0, x86_fp_c1, x86_fp_c2, x86_fp_c3, x86_fp_cc_mask, + -- | FP control word codes + x86_fpcw_invopex_mask, x86_fpcw_denopex_mask, x86_fpcw_zerodiv_mask, + x86_fpcw_ovfex_mask, x86_fpcw_undfex_mask, x86_fpcw_precex_mask, + x86_fpcw_precc_mask, x86_fpcw_roundc_mask, + x86_fpcw_prec_single, x86_fpcw_prec_double, + x86_fpcw_prec_extended, + x86_fpcw_round_nearest, x86_fpcw_round_down, x86_fpcw_round_up, + x86_fpcw_round_tozero, + -- ** Condition codes + -- | Integer conditions codes + x86_cc_eq, x86_cc_e, x86_cc_z, + x86_cc_ne, x86_cc_nz, + x86_cc_lt, x86_cc_b, x86_cc_c, x86_cc_nae, x86_cc_le, x86_cc_be, + x86_cc_na, x86_cc_gt, x86_cc_a, x86_cc_nbe, x86_cc_ge, x86_cc_ae, + x86_cc_nb, x86_cc_nc, x86_cc_lz, x86_cc_s, x86_cc_gez, x86_cc_ns, + x86_cc_p, x86_cc_np, x86_cc_pe, x86_cc_po, x86_cc_o, x86_cc_no, + -- ** Instruction prefix codes + x86_lock_prefix, x86_repnz_prefix, x86_repz_prefix, x86_rep_prefix, + x86_cs_prefix, x86_ss_prefix, x86_ds_prefix, x86_es_prefix, + x86_fs_prefix, x86_gs_prefix, x86_unlikely_prefix, + x86_likely_prefix, x86_operand_prefix, x86_address_prefix, + -- * Functions + -- ** Utility functions + x86_is_scratch, x86_is_callee, + -- ** Code emission + -- | These functions are used to emit parts of instructions, such + -- as constants or operand descriptions. + x86_imm_emit16, x86_imm_emit8, x86_imm_emit32, + x86_membase_emit, x86_alu_reg_imm, + -- ** Call instructions + x86_call_hs, x86_call_membase, x86_call_mem, x86_call_reg, x86_call_code, + x86_call_imm, + -- ** Function prologue and epilogue + x86_prolog, x86_epilog, x86_enter, x86_leave, + x86_ret, x86_ret_imm, + -- ** Jump and branch + x86_jecxz, x86_branch, x86_branch_pointer, x86_branch32, x86_branch8, + x86_jump_membase, x86_jump_pointer, x86_jump_mem, x86_jump_reg, + x86_jump32, x86_jump8, + x86_loopne, x86_loope, x86_loop, + -- ** Stack operations + x86_push_reg, x86_push_regp, x86_push_mem, x86_push_membase, + x86_push_imm, x86_push_imm_template, x86_push_memindex, + x86_pop_membase, x86_pop_mem, x86_pop_reg, + x86_popfd, x86_pushfd, x86_popad, x86_pushad, + -- ** Data movement + x86_mov_reg_reg, x86_mov_reg_imm, x86_mov_mem_imm, x86_mov_membase_imm, + x86_mov_memindex_imm, x86_mov_mem_reg, x86_mov_reg_mem, + x86_mov_regp_reg, x86_mov_reg_regp, x86_mov_membase_reg, + x86_mov_reg_membase, x86_mov_memindex_reg, x86_mov_reg_memindex, + -- ** Arithmetic + x86_xadd_reg_reg, x86_xadd_mem_reg, x86_xadd_membase_reg, + x86_inc_mem, x86_inc_membase, x86_inc_reg, + x86_dec_mem, x86_dec_membase, x86_dec_reg, + x86_not_mem, x86_not_membase, x86_not_reg, + x86_neg_mem, x86_neg_membase, x86_neg_reg, + x86_alu_mem_imm, x86_alu_membase_imm, x86_alu_membase8_imm, + x86_alu_mem_reg, x86_alu_membase_reg, x86_alu_reg_reg, + x86_alu_reg8_reg8, x86_alu_reg_mem, x86_alu_reg_membase, + x86_mul_reg, x86_mul_mem, x86_mul_membase, + x86_imul_reg_reg, x86_imul_reg_membase, x86_imul_reg_reg_imm, + x86_imul_reg_mem, + x86_imul_reg_mem_imm, x86_imul_reg_membase_imm, + x86_div_reg, x86_div_mem, x86_div_membase, + x86_test_reg_imm, x86_test_mem_imm, x86_test_membase_imm, + x86_test_reg_reg, x86_test_mem_reg, x86_test_membase_reg, + -- ** Exchange + x86_cmpxchg_reg_reg, x86_cmpxchg_mem_reg, x86_cmpxchg_membase_reg, + x86_xchg_reg_reg, x86_xchg_mem_reg, x86_xchg_membase_reg, + -- ** String operations + x86_stosb, x86_stosl, x86_stosd, x86_movsb, x86_movsl, x86_movsd, + -- ** Bitwise shift + x86_shift_reg_imm, x86_shift_mem_imm, x86_shift_membase_imm, + x86_shift_reg, x86_shift_mem, x86_shift_membase, + x86_shrd_reg, x86_shrd_reg_imm, x86_shld_reg, x86_shld_reg_imm, + -- ** Conditional move + x86_cmov_membase, x86_cmov_mem, x86_cmov_reg, + -- ** Conditional set + x86_set_membase, x86_set_mem, x86_set_reg, + -- ** Address calculation + x86_lea_mem, x86_lea_membase, x86_lea_memindex, + -- ** Conversion + x86_cdq,x86_widen_memindex, x86_widen_membase, x86_widen_mem, + x86_widen_reg, + -- ** Floating point + x86_fp_op_mem, x86_fp_op_membase, x86_fp_op, x86_fp_op_reg, + x86_fp_int_op_membase, x86_fstp, x86_fcompp, x86_fucompp, + x86_fnstsw, x86_fnstcw, x86_fnstcw_membase, + x86_fldcw, x86_fldcw_membase, x86_fchs, + x86_frem, x86_fxch, x86_fcomi, x86_fcomip, x86_fucomi, x86_fucomip, + x86_fld, x86_fld_membase, x86_fld80_mem, x86_fld80_membase, + x86_fld_reg, x86_fldz, x86_fld1, x86_fldpi, + x86_fst, x86_fst_membase, x86_fst80_mem, x86_fst80_membase, + FIntSize(..), + x86_fist_pop, x86_fist_pop_membase, x86_fstsw, + x86_fist_membase, x86_fild, x86_fild_membase, + x86_fsin, x86_fcos, x86_fabs, x86_ftst, x86_fxam, x86_fpatan, + x86_fprem, x86_fprem1, x86_frndint, x86_fsqrt, x86_fptan, + x86_fincstp, x86_fdecstp, + -- ** SSE instructions + x86_sse_ps, x86_sse_pd, x86_sse_ss, x86_sse_sd, + x86_add_sse_reg_reg, x86_add_sse_reg_mem, x86_add_sse_reg_membase, + x86_sub_sse_reg_reg, x86_sub_sse_reg_mem, x86_sub_sse_reg_membase, + x86_mul_sse_reg_reg, x86_mul_sse_reg_mem, x86_mul_sse_reg_membase, + x86_div_sse_reg_reg, x86_div_sse_reg_mem, x86_div_sse_reg_membase, + x86_max_sse_reg_reg, x86_max_sse_reg_mem, x86_max_sse_reg_membase, + x86_min_sse_reg_reg, x86_min_sse_reg_mem, x86_min_sse_reg_membase, + x86_sqrt_sse_reg_reg, x86_sqrt_sse_reg_mem, x86_sqrt_sse_reg_membase, + x86_mov_sse_reg_reg, x86_mov_sse_reg_mem, x86_mov_sse_reg_membase, x86_mov_sse_mem_reg ,x86_mov_sse_membase_reg, + x86_ucomisd_reg_reg, x86_ucomisd_reg_mem, x86_ucomisd_reg_membase, + x86_ucomiss_reg_reg, x86_ucomiss_reg_mem, x86_ucomiss_reg_membase, + x86_comisd_reg_reg, x86_comisd_reg_mem, x86_comisd_reg_membase, + x86_comiss_reg_reg, x86_comiss_reg_mem, x86_comiss_reg_membase, + XMMReg(XMMReg), Mem(Mem), MemBase(MemBase), + XMMLocation(xmm_location_emit), + x86_movss_to_reg, x86_movss_from_reg, + x86_movsd_to_reg, x86_movsd_from_reg, + x86_movlps_to_reg, x86_movlps_from_reg, + x86_movlpd_to_reg, x86_movlpd_from_reg, + x86_movups_to_reg, x86_movups_from_reg, + x86_movupd_to_reg, x86_movupd_from_reg, + x86_haddps, x86_haddpd, + x86_shufps, x86_shufpd, + x86_cvtdq2ps, x86_cvttps2dq, + -- ** Prefetch instructions + x86_prefetch0_mem, x86_prefetch1_mem, x86_prefetch2_mem, x86_prefetchnta_mem, + x86_prefetch0_membase, x86_prefetch1_membase, x86_prefetch2_membase, x86_prefetchnta_membase, + x86_prefetch0_regp, x86_prefetch1_regp, x86_prefetch2_regp, x86_prefetchnta_regp, + -- ** Miscellaneous + x86_sahf, x86_wait, x86_nop, x86_breakpoint, x86_rdtsc, x86_cld, + x86_prefix, x86_padding, + -- ** Other utilities + negateCC + ) where + +import qualified Text.PrettyPrint.HughesPJ as PP + +import Data.Word +import Data.Bits + +import Foreign.Ptr + +import Harpy.CodeGenMonad + +-- | Maximal length of an x86 instruction in bytes. +x86_max_instruction_bytes :: Int +x86_max_instruction_bytes = 16 -- According to Intel manual. + +x86_dword_size, x86_qword_size :: Int + +x86_dword_size = 4 -- Number of bytes in doubleword +x86_qword_size = 8 -- Number of bytes in quadword + +x86_eax, x86_ecx, x86_edx, x86_ebx, x86_esp, x86_ebp, x86_esi, + x86_edi :: Word8 +x86_eax = 0 +x86_ecx = 1 +x86_edx = 2 +x86_ebx = 3 +x86_esp = 4 +x86_ebp = 5 +x86_esi = 6 +x86_edi = 7 + +x86_cmp, x86_or, x86_adc, x86_sbb, x86_and, x86_sub, x86_xor, + x86_add :: Word8 +x86_add = 0 +x86_or = 1 +x86_adc = 2 +x86_sbb = 3 +x86_and = 4 +x86_sub = 5 +x86_xor = 6 +x86_cmp = 7 + +x86_sar, x86_shld, x86_shlr, x86_rol, x86_ror, x86_rcl, x86_rcr, + x86_shl, x86_shr :: Word8 + +x86_shld = 0 +x86_shlr = 1 +x86_rol = 0 +x86_ror = 1 +x86_rcl = 2 +x86_rcr = 3 +x86_shl = 4 +x86_shr = 5 +x86_sar = 7 + +x86_fadd, x86_fmul, x86_fcom, x86_fcomp, x86_fsub, x86_fsubr :: Word8 +x86_fdiv, x86_fdivr :: Word8 + +x86_fadd = 0 +x86_fmul = 1 +x86_fcom = 2 +x86_fcomp = 3 +x86_fsub = 4 +x86_fsubr = 5 +x86_fdiv = 6 +x86_fdivr = 7 + +x86_cc_no, x86_cc_eq, x86_cc_e, x86_cc_z, x86_cc_ne, x86_cc_nz, x86_cc_lt :: Int +x86_cc_b, x86_cc_c, x86_cc_nae, x86_cc_le, x86_cc_be, x86_cc_na :: Int +x86_cc_gt :: Int +x86_cc_a, x86_cc_nbe, x86_cc_ge, x86_cc_ae, x86_cc_nb, x86_cc_nc :: Int +x86_cc_lz, x86_cc_s, x86_cc_gez, x86_cc_ns, x86_cc_p, x86_cc_pe :: Int +x86_cc_np, x86_cc_po, x86_cc_o :: Int +x86_cc_eq = 0 +x86_cc_e = 0 +x86_cc_z = 0 +x86_cc_ne = 1 +x86_cc_nz = 1 +x86_cc_lt = 2 +x86_cc_b = 2 +x86_cc_c = 2 +x86_cc_nae = 2 +x86_cc_le = 3 +x86_cc_be = 3 +x86_cc_na = 3 +x86_cc_gt = 4 +x86_cc_a = 4 +x86_cc_nbe = 4 +x86_cc_ge = 5 +x86_cc_ae = 5 +x86_cc_nb = 5 +x86_cc_nc = 5 +x86_cc_lz = 6 +x86_cc_s = 6 +x86_cc_gez = 7 +x86_cc_ns = 7 +x86_cc_p = 8 +x86_cc_pe = 8 +x86_cc_np = 9 +x86_cc_po = 9 +x86_cc_o = 10 +x86_cc_no = 11 + +-- | FP status +x86_fp_c0, x86_fp_c1, x86_fp_c2, x86_fp_c3, x86_fp_cc_mask :: Word32 +x86_fp_c0 = 0x100 +x86_fp_c1 = 0x200 +x86_fp_c2 = 0x400 +x86_fp_c3 = 0x4000 +x86_fp_cc_mask = 0x4500 + +-- | FP control word +x86_fpcw_invopex_mask, x86_fpcw_denopex_mask, x86_fpcw_zerodiv_mask, + x86_fpcw_ovfex_mask, x86_fpcw_undfex_mask, x86_fpcw_precex_mask, + x86_fpcw_precc_mask, x86_fpcw_roundc_mask :: Word32 + +x86_fpcw_invopex_mask = 0x1 +x86_fpcw_denopex_mask = 0x2 +x86_fpcw_zerodiv_mask = 0x4 +x86_fpcw_ovfex_mask = 0x8 +x86_fpcw_undfex_mask = 0x10 +x86_fpcw_precex_mask = 0x20 +x86_fpcw_precc_mask = 0x300 +x86_fpcw_roundc_mask = 0xc00 + +-- | Values for precision control +x86_fpcw_prec_single, x86_fpcw_prec_double, + x86_fpcw_prec_extended :: Word32 +x86_fpcw_prec_single = 0 +x86_fpcw_prec_double = 0x200 +x86_fpcw_prec_extended = 0x300 + +-- | Values for rounding control +x86_fpcw_round_nearest, x86_fpcw_round_down, x86_fpcw_round_up, + x86_fpcw_round_tozero :: Word32 +x86_fpcw_round_nearest = 0 +x86_fpcw_round_down = 0x400 +x86_fpcw_round_up = 0x800 +x86_fpcw_round_tozero = 0xc00 + +-- | Prefix codes +x86_lock_prefix, x86_repnz_prefix, x86_repz_prefix, x86_rep_prefix, + x86_cs_prefix, x86_ss_prefix, x86_ds_prefix, x86_es_prefix, + x86_fs_prefix, x86_gs_prefix, x86_unlikely_prefix, + x86_likely_prefix, x86_operand_prefix, x86_address_prefix :: Word8 +x86_lock_prefix = 0xf0 +x86_repnz_prefix = 0xf2 +x86_repz_prefix = 0xf3 +x86_rep_prefix = 0xf3 +x86_cs_prefix = 0x2e +x86_ss_prefix = 0x36 +x86_ds_prefix = 0x3e +x86_es_prefix = 0x26 +x86_fs_prefix = 0x64 +x86_gs_prefix = 0x65 +x86_unlikely_prefix = 0x2e +x86_likely_prefix = 0x3e +x86_operand_prefix = 0x66 +x86_address_prefix = 0x67 + +-- | Mapping from condition code to opcode (unsigned) +x86_cc_unsigned_map :: [Word8] +x86_cc_unsigned_map = [ + 0x74, -- eq + 0x75, -- ne + 0x72, -- lt + 0x76, -- le + 0x77, -- gt + 0x73, -- ge + 0x78, -- lz + 0x79, -- gez + 0x7a, -- p + 0x7b, -- np + 0x70, -- o + 0x71 -- no + ] + +-- | Mapping from condition code to opcode (signed) +x86_cc_signed_map :: [Word8] +x86_cc_signed_map = [ + 0x74, -- eq + 0x75, -- ne + 0x7c, -- lt + 0x7e, -- le + 0x7f, -- gt + 0x7d, -- ge + 0x78, -- lz + 0x79, -- gez + 0x7a, -- p + 0x7b, -- np + 0x70, -- o + 0x71 -- no + ] + +-- | Mapping from condition code to negated condition code. +x86_cc_negate :: [(Int, Int)] +x86_cc_negate = [ + (x86_cc_eq, x86_cc_ne), -- eq + (x86_cc_ne, x86_cc_eq), -- ne + (x86_cc_lt, x86_cc_ge), -- lt + (x86_cc_le, x86_cc_gt), -- le + (x86_cc_gt, x86_cc_le), -- gt + (x86_cc_ge, x86_cc_lt), -- ge + (x86_cc_lz, x86_cc_gez), -- lz + (x86_cc_gez, x86_cc_lz), -- gez + (x86_cc_p, x86_cc_np), -- p + (x86_cc_np, x86_cc_p), -- np + (x86_cc_o, x86_cc_no), -- o + (x86_cc_no, x86_cc_o) -- no + ] + +-- | Invert a condition code. +negateCC :: Int -> Int +negateCC cc = + case lookup cc x86_cc_negate of + Just cc' -> cc' + Nothing -> error ("unhandled case in negateCC" ++ show cc) + +-- | Used to encode the fact that no base register is used in an +-- instruction. +x86_nobasereg :: Word8 +x86_nobasereg = (-1) + +x86_edi_mask, x86_esi_mask, x86_ebx_mask, x86_ebp_mask, + x86_eax_mask, x86_ecx_mask, x86_edx_mask:: Int +x86_esi_mask = (1 `shiftL` (fromIntegral x86_esi)) +x86_edi_mask = (1 `shiftL` (fromIntegral x86_edi)) +x86_ebx_mask = (1 `shiftL` (fromIntegral x86_ebx)) +x86_ebp_mask = (1 `shiftL` (fromIntegral x86_ebp)) +x86_eax_mask = (1 `shiftL` (fromIntegral x86_eax)) +x86_ecx_mask = (1 `shiftL` (fromIntegral x86_ecx)) +x86_edx_mask = (1 `shiftL` (fromIntegral x86_edx)) + +-- | Bitvector mask for callee-saved registers +x86_callee_regs :: Int +x86_callee_regs = ((1 `shiftL` (fromIntegral x86_eax)) .|. + (1 `shiftL` (fromIntegral x86_ecx)) .|. + (1 `shiftL` (fromIntegral x86_edx))) + +-- | Bitvector mask for caller-saved registers +x86_caller_regs :: Int +x86_caller_regs = ((1 `shiftL` (fromIntegral x86_ebx)) .|. + (1 `shiftL` (fromIntegral x86_ebp)) .|. + (1 `shiftL` (fromIntegral x86_esi)) .|. + (1 `shiftL` (fromIntegral x86_edi))) + +-- | Bitvector mask for byte-adressable registers +x86_byte_regs :: Int +x86_byte_regs = ((1 `shiftL` (fromIntegral x86_eax)) .|. + (1 `shiftL` (fromIntegral x86_ecx)) .|. + (1 `shiftL` (fromIntegral x86_edx)) .|. + (1 `shiftL` (fromIntegral x86_ebx))) + +-- | Returns true when the given register is caller-saved. +x86_is_scratch :: Int -> Bool +x86_is_scratch reg = (x86_caller_regs .&. (1 `shiftL` (reg))) /= 0 + +-- | Returns true when the given register is caller-saved. +x86_is_callee :: Int -> Bool + +x86_is_callee reg = (x86_callee_regs .&. (1 `shiftL` (reg))) /= 0 + +-- | Returns true when the given register is byte-addressable. +x86_is_byte_reg :: (Num a, Ord a) => a -> Bool +x86_is_byte_reg reg = ((reg) < 4) + + + +-- useful building blocks + + +--x86_modrm_mod modrm = ((modrm) `shiftR` 6) +--x86_modrm_reg :: Bits a => a -> a +--x86_modrm_reg modrm = (((modrm) `shiftR` 3) .&. 0x7) +--x86_modrm_rm modrm = ((modrm) .&. 0x7) + +x86_address_byte :: Word8 -> Word8 -> Word8 -> CodeGen e s () +x86_address_byte m o r = emit8 ((((m) .&. 0x03) `shiftL` 6) .|. + (((o) .&. 0x07) `shiftL` 3) .|. + (((r) .&. 0x07))) + +-- | Emit a 32-bit constant to the instruction stream. +x86_imm_emit32 :: Word32 -> CodeGen e s () +x86_imm_emit32 imm = emit32 imm + +-- -- | Emit a 32-bit constant to the instruction stream at the given offset. +-- x86_imm_emit32_at :: Int -> Word32 -> CodeGen e s () +-- x86_imm_emit32_at pos imm = emit32At pos imm + +-- | Emit a 16-bit constant to the instruction stream. +x86_imm_emit16 :: Word16 -> CodeGen e s () +x86_imm_emit16 imm = + let b0 = (imm .&. 0xff) + b1 = ((imm `shiftR` 8) .&. 0xff) + in do emit8 (fromIntegral b0) + emit8 (fromIntegral b1) + +-- | Emit a 8-bit constant to the instruction stream. +x86_imm_emit8 :: Word8 -> CodeGen e s () +x86_imm_emit8 imm = + emit8 (imm .&. 0xff) + +-- -- | Emit a 8-bit constant to the instruction stream at the given offset. +-- x86_imm_emit8_at :: Int -> Word8 -> CodeGen e s () +-- x86_imm_emit8_at pos imm = emit8At pos (imm .&. 0xff) + +-- | Return true if the given value is a signed 8-bit constant. +x86_is_imm8 :: Integral a => a -> Bool +x86_is_imm8 imm = (((fromIntegral imm :: Integer) >= -128) && ((fromIntegral imm :: Integer) <= 127)) +-- x86_is_imm16 :: Integral a => a -> Bool +-- x86_is_imm16 imm = (((fromIntegral imm :: Integer) >= -(1 `shiftL` 16)) && +-- ((fromIntegral imm :: Integer) <= ((1 `shiftL` 16)-1))) + +x86_reg_emit :: Word8 -> Word8 -> CodeGen e s () +x86_reg_emit r regno = x86_address_byte 3 r regno + +x86_reg8_emit :: Word8 -> Word8 -> Bool -> Bool -> CodeGen e s () +x86_reg8_emit r regno is_rh is_rnoh = + x86_address_byte 3 (if is_rh then (r .|. 4) else r) + (if is_rnoh then regno .|. 4 else regno) + +-- | Emit a register-indirect address encoding. +x86_regp_emit :: Word8 -> Word8 -> CodeGen e s () +x86_regp_emit r regno = x86_address_byte 0 r regno + +-- | Emit a memory+displacement address encoding. +x86_mem_emit :: Word8 -> Word32 -> CodeGen e s () +x86_mem_emit r disp = do x86_address_byte 0 r 5 + x86_imm_emit32 disp + +-- | Emit a mem+base address encoding +x86_membase_emit :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_membase_emit r basereg disp = + if basereg == x86_esp + then if disp == 0 + then do x86_address_byte 0 r x86_esp + x86_address_byte 0 x86_esp x86_esp + else if x86_is_imm8 disp + then do x86_address_byte 1 r x86_esp + x86_address_byte 0 x86_esp x86_esp + x86_imm_emit8 (fromIntegral disp) + else do x86_address_byte 2 r x86_esp + x86_address_byte 0 x86_esp x86_esp + x86_imm_emit32 (fromIntegral disp) + else do if (disp == 0 && (toInteger basereg) /= (toInteger x86_ebp)) + then x86_address_byte 0 r basereg + else if x86_is_imm8 (fromIntegral disp :: Word32) + then do x86_address_byte 1 r basereg + x86_imm_emit8 (fromIntegral disp) + else do x86_address_byte 2 r basereg + x86_imm_emit32 (fromIntegral disp) + +x86_memindex_emit :: Word8 -> Word8 -> Word32 -> Word8 -> Word8 -> CodeGen e s () +x86_memindex_emit r basereg disp indexreg shft = + if (basereg == x86_nobasereg) + then do x86_address_byte 0 r 4 + x86_address_byte shft indexreg 5 + x86_imm_emit32 disp + else if ((disp) == 0 && (basereg) /= x86_ebp) + then do x86_address_byte 0 r 4 + x86_address_byte shft indexreg (fromIntegral basereg) + else if x86_is_imm8 disp + then do x86_address_byte 1 r 4 + x86_address_byte shft indexreg + (fromIntegral basereg) + x86_imm_emit8 (fromIntegral disp) + else do x86_address_byte 2 r 4 + x86_address_byte shft indexreg 5 + x86_imm_emit32 disp + +{- +x86_jmp_ofs_size ins = + do instr <- peek8At ins + case instr of + 0xe8 -> return 1 + 0xe9 -> return 1 + 0x0f -> + do atPos <- peek8At (ins + 1) + if (atPos < 0x70 || atPos > 0x8f) + then failCodeGen (PP.text "Wrong Opcode") + else return 1 + _ -> return 0 +-} + +-- target is the position in the code where to jump to: + +-- target = code; +-- .. output loop code... +-- x86_mov_reg_imm (code, X86_EAX, 0); +-- loop = code; +-- x86_loop (code, -1); +-- ... finish method + +-- patch displacement + +-- x86_patch (loop, target); + +-- ins should point at the start of the instruction that encodes a target. +-- the instruction is inspected for validity and the correct displacement +-- is inserted. + +{- +x86_patch ins target = + let pos = ins + 1 + in do size <- x86_jmp_ofs_size ins + instr <- peek8At ins + let disp = target - (if instr == 0x0f then pos + 1 else pos) + if size == 1 + then x86_imm_emit32_at pos (fromIntegral (disp - 4)) + else if (x86_is_imm8 (disp - 1)) + then x86_imm_emit8_at pos (fromIntegral (disp - 1)) + else failCodeGen (PP.text "Wrong offset") +-} + +x86_breakpoint, x86_cld, x86_stosb, x86_stosl, x86_stosd, x86_movsb, + x86_movsl, x86_movsd :: CodeGen s e () +x86_breakpoint = emit8 0xcc +x86_cld = emit8 0xfc +x86_stosb = emit8 0xaa +x86_stosl = emit8 0xab +x86_stosd = x86_stosl +x86_movsb = emit8 0xa4 +x86_movsl = emit8 0xa5 +x86_movsd = x86_movsl + +x86_prefix :: Word8 -> CodeGen s e () +x86_prefix p = emit8 p + +x86_rdtsc :: CodeGen s e () +x86_rdtsc = emit8 0x0f >> emit8 0x31 + +x86_cmpxchg_reg_reg :: Word8 -> Word8 -> CodeGen e s () +x86_cmpxchg_reg_reg dreg reg = + emit8 0x0f >> emit8 0xb1 >> x86_reg_emit reg dreg + +x86_cmpxchg_mem_reg :: Word32 -> Word8 -> CodeGen e s () +x86_cmpxchg_mem_reg mem reg = emit8 0x0f >> emit8 0xb1 >> x86_mem_emit reg mem + +x86_cmpxchg_membase_reg :: Word8 -> Word32 -> Word8 -> CodeGen e s () +x86_cmpxchg_membase_reg basereg disp reg = + emit8 0x0f >> emit8 0xb1 >> x86_membase_emit reg basereg disp + +x86_xchg :: Num a => a -> CodeGen e s () +x86_xchg size = if size == 1 then emit8 0x86 else emit8 0x87 + +x86_xchg_reg_reg dreg reg size = + do x86_xchg size ; x86_reg_emit reg dreg +x86_xchg_mem_reg mem reg size = + do x86_xchg size ; x86_mem_emit reg mem +x86_xchg_membase_reg basereg disp reg size = + do x86_xchg size ; x86_membase_emit reg basereg disp + +x86_xadd :: Num a => a -> CodeGen e s () +x86_xadd size = do emit8 0x0f ; if size == 1 then emit8 0xc0 else emit8 0xc1 +x86_xadd_reg_reg dreg reg size = x86_xadd size >> x86_reg_emit reg dreg +x86_xadd_mem_reg mem reg size = x86_xadd size >> x86_mem_emit reg mem +x86_xadd_membase_reg basereg disp reg size = + x86_xadd size >> x86_membase_emit reg basereg disp + +x86_inc_mem mem = emit8 0xff >> x86_mem_emit 0 mem +x86_inc_membase basereg disp = emit8 0xff >> x86_membase_emit 0 basereg disp +x86_inc_reg reg = emit8 (0x40 + reg) + +x86_dec_mem mem = emit8 0xff >> x86_mem_emit 1 mem +x86_dec_membase basereg disp = emit8 0xff >> x86_membase_emit 1 basereg disp +x86_dec_reg reg = emit8 (0x48 + reg) + +x86_not_mem mem = emit8 0xf7 >> x86_mem_emit 2 mem +x86_not_membase basereg disp = emit8 0xf7 >> x86_membase_emit 2 basereg disp +x86_not_reg reg = emit8 0xf7 >> x86_reg_emit 2 reg + +x86_neg_mem mem = emit8 0xf7 >> x86_mem_emit 3 mem +x86_neg_membase basereg disp = emit8 0xf7 >> x86_membase_emit 3 basereg disp +x86_neg_reg reg = emit8 0xf7 >> x86_reg_emit 3 reg + +x86_nop :: CodeGen s e () +x86_nop = emit8 0x90 + +x86_alu_reg_imm :: Word8 -> Word8 -> Int -> CodeGen e s () +x86_alu_reg_imm opc reg imm = + do if reg == x86_eax + then emit8 (fromIntegral (((opc) `shiftL` 3) + 5)) >> x86_imm_emit32 (fromIntegral imm) + else if x86_is_imm8 imm + then do emit8 0x83 + x86_reg_emit (fromIntegral opc) (fromIntegral reg) + x86_imm_emit8 (fromIntegral imm) + else do emit8 0x81 + x86_reg_emit (fromIntegral opc) (fromIntegral reg) + x86_imm_emit32 (fromIntegral imm) + + +x86_alu_mem_imm opc mem imm = + if x86_is_imm8 imm + then do emit8 0x83 + x86_mem_emit opc mem + x86_imm_emit8 (fromIntegral imm) + else do emit8 0x81 + x86_mem_emit opc mem + x86_imm_emit32 imm + + +x86_alu_membase_imm opc basereg disp imm = + if x86_is_imm8 imm + then do emit8 0x83 + x86_membase_emit opc basereg disp + x86_imm_emit8 (fromIntegral imm) + else do emit8 0x81 + x86_membase_emit opc basereg disp + x86_imm_emit32 imm +x86_alu_membase8_imm opc basereg disp imm = + do emit8 0x80 + x86_membase_emit opc basereg disp + x86_imm_emit8 imm +x86_alu_mem_reg opc mem reg = + do emit8 ((opc `shiftL` 3) + 1) + x86_mem_emit reg mem +x86_alu_membase_reg opc basereg disp reg = + do emit8 ((opc `shiftL` 3) + 1) + x86_membase_emit reg basereg disp +x86_alu_reg_reg opc dreg reg = + do emit8 ((opc `shiftL` 3) + 3) + x86_reg_emit dreg reg + +-- @x86_alu_reg8_reg8: +-- Supports ALU operations between two 8-bit registers. +-- dreg := dreg opc reg +-- X86_Reg_No enum is used to specify the registers. +-- Additionally is_*_h flags are used to specify what part +-- of a given 32-bit register is used - high (TRUE) or low (FALSE). +-- For example: dreg = X86_EAX, is_dreg_h = TRUE -> use AH + +x86_alu_reg8_reg8 opc dreg reg is_dreg_h is_reg_h = + do emit8 ((opc `shiftL` 3) + 2) + x86_reg8_emit dreg reg is_dreg_h is_reg_h +x86_alu_reg_mem opc reg mem = + do emit8 ((opc `shiftL` 3) + 3) + x86_mem_emit reg mem +x86_alu_reg_membase opc reg basereg disp = + do emit8 ((opc `shiftL` 3) + 3) + x86_membase_emit reg basereg disp + +x86_test_reg_imm reg imm = + do if reg == x86_eax + then emit8 0xa9 + else do emit8 0xf7 ; x86_reg_emit 0 (fromIntegral reg) + x86_imm_emit32 imm +x86_test_mem_imm mem imm = + do emit8 0xf7 ; x86_mem_emit 0 mem ; x86_imm_emit32 imm +x86_test_membase_imm basereg disp imm = + do emit8 0xf7 ; x86_membase_emit 0 basereg disp ; x86_imm_emit32 imm +x86_test_reg_reg dreg reg = do emit8 0x85 ; x86_reg_emit reg dreg +x86_test_mem_reg mem reg = + do emit8 0x85 ; x86_mem_emit reg mem +x86_test_membase_reg basereg disp reg = + do emit8 0x85 ; x86_membase_emit reg basereg disp + +x86_shift_reg_imm opc reg imm = + if imm == 1 + then do emit8 0xd1 ; x86_reg_emit opc reg + else do emit8 0xc1 + x86_reg_emit opc reg + x86_imm_emit8 imm +x86_shift_mem_imm opc mem imm = + if imm == 1 + then do emit8 0xd1 ; x86_mem_emit opc mem + else do emit8 0xc1 + x86_mem_emit opc mem + x86_imm_emit8 imm +x86_shift_membase_imm opc basereg disp imm = + if imm == 1 + then do emit8 0xd1 ; x86_membase_emit opc basereg disp + else do emit8 0xc1 + x86_membase_emit opc basereg disp + x86_imm_emit8 imm +x86_shift_reg opc reg = + emit8 0xd3 >> x86_reg_emit opc reg +x86_shift_mem opc mem = + emit8 0xd3 >> x86_mem_emit opc mem +x86_shift_membase opc basereg disp = + emit8 0xd3 >> x86_membase_emit opc basereg disp + +-- Multi op shift missing. + +x86_shrd_reg dreg reg = + emit8 0x0f >> emit8 0xad >> x86_reg_emit reg dreg +x86_shrd_reg_imm dreg reg shamt = + emit8 0x0f >> emit8 0xac >> x86_reg_emit reg dreg >> x86_imm_emit8 shamt +x86_shld_reg dreg reg = + emit8 0x0f >> emit8 0xa5 >> x86_reg_emit reg dreg +x86_shld_reg_imm dreg reg shamt = + emit8 0x0f >> emit8 0xa4 >> x86_reg_emit reg dreg >>x86_imm_emit8 shamt + +-- EDX:EAX = EAX * rm + +x86_mul_reg :: Word8 -> Bool -> CodeGen e s () +x86_mul_reg reg is_signed = + emit8 0xf7 >> x86_reg_emit (4 + (if is_signed then 1 else 0)) reg + +x86_mul_mem :: Word32 -> Bool -> CodeGen e s () +x86_mul_mem mem is_signed = + emit8 0xf7 >> x86_mem_emit (4 + (if is_signed then 1 else 0)) mem + +x86_mul_membase :: Word8 -> Word32 -> Bool -> CodeGen e s () +x86_mul_membase basereg disp is_signed = + do emit8 0xf7 + x86_membase_emit (4 + (if is_signed then 1 else 0)) basereg disp + +-- r *= rm + +x86_imul_reg_reg :: Word8 -> Word8 -> CodeGen e s () +x86_imul_reg_reg dreg reg = + emit8 0x0f >> emit8 0xaf >> x86_reg_emit dreg reg + +x86_imul_reg_mem :: Word8 -> Word32 -> CodeGen e s () +x86_imul_reg_mem reg mem = + emit8 0x0f >> emit8 0xaf >> x86_mem_emit reg mem + +x86_imul_reg_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_imul_reg_membase reg basereg disp = + emit8 0x0f >> emit8 0xaf >> x86_membase_emit reg basereg disp + +-- dreg = rm * imm + +x86_imul_reg_reg_imm :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_imul_reg_reg_imm dreg reg imm = + if x86_is_imm8 imm + then emit8 0x6b >> x86_reg_emit dreg reg >> + x86_imm_emit8 (fromIntegral imm) + else emit8 0x69 >> x86_reg_emit dreg reg >> x86_imm_emit32 imm + +x86_imul_reg_mem_imm :: Word8 -> Word32 -> Word32 -> CodeGen e s () +x86_imul_reg_mem_imm reg mem imm = + if x86_is_imm8 imm + then emit8 0x6b >> x86_mem_emit reg mem >> + x86_imm_emit8 (fromIntegral imm) + else emit8 0x69 >> x86_reg_emit reg (fromIntegral mem) >> + x86_imm_emit32 imm + +x86_imul_reg_membase_imm :: Word8 -> Word8 -> Word32 -> Word32 -> CodeGen e s () +x86_imul_reg_membase_imm reg basereg disp imm = + if x86_is_imm8 imm + then emit8 0x6b >> x86_membase_emit reg basereg disp >> + x86_imm_emit8 (fromIntegral imm) + else do emit8 0x69 + x86_membase_emit reg basereg disp + x86_imm_emit32 imm + +-- divide EDX:EAX by rm; +-- eax = quotient, edx = remainder + +x86_div_reg :: Word8 -> Bool -> CodeGen e s () +x86_div_reg reg is_signed = + emit8 0xf7 >> x86_reg_emit (6 + (if is_signed then 1 else 0)) reg +x86_div_mem :: Word32 -> Bool -> CodeGen e s () +x86_div_mem mem is_signed = + emit8 0xf7 >> x86_mem_emit (6 + (if is_signed then 1 else 0)) mem + +x86_div_membase :: Word8 -> Word32 -> Bool -> CodeGen e s () +x86_div_membase basereg disp is_signed = + do emit8 0xf7 + x86_membase_emit (6 + (if is_signed then 1 else 0)) basereg disp + +x86_mov1 :: Num t => t -> CodeGen e s () +x86_mov1 size = + case size of + 1 -> emit8 0x88 + 2 -> emit8 0x66 >> emit8 0x89 + 4 -> emit8 0x89 + _ -> failCodeGen (PP.text "invalid operand size") + +x86_mov2 :: Num t => t -> CodeGen e s () +x86_mov2 size = + case size of + 1 -> emit8 0x8a + 2 -> emit8 0x66 >> emit8 0x8b + 4 -> emit8 0x8b + _ -> failCodeGen (PP.text "invalid operand size") + +x86_mov_mem_reg :: (Num t) => Word32 -> Word8 -> t -> CodeGen e s () +x86_mov_mem_reg mem reg size = + do x86_mov1 size ; x86_mem_emit reg mem + +x86_mov_regp_reg :: (Num t) => Word8 -> Word8 -> t -> CodeGen e s () +x86_mov_regp_reg regp reg size = + do x86_mov1 size ; x86_regp_emit reg regp + +x86_mov_reg_regp :: (Num t) => Word8 -> Word8 -> t -> CodeGen e s () +x86_mov_reg_regp reg regp size = + do x86_mov2 size ; x86_regp_emit reg regp + +x86_mov_membase_reg :: (Num t) => Word8 -> Word32 -> Word8 -> t -> CodeGen e s () +x86_mov_membase_reg basereg disp reg size = + do x86_mov1 size ; x86_membase_emit reg basereg disp + +x86_mov_memindex_reg :: (Num t) => Word8 -> Word32 -> Word8 -> Word8 -> Word8 -> t -> CodeGen e s () +x86_mov_memindex_reg basereg disp indexreg shft reg size = + do x86_mov1 size ; x86_memindex_emit reg basereg disp indexreg shft + +x86_mov_reg_reg :: (Num t) => Word8 -> Word8 -> t -> CodeGen e s () +x86_mov_reg_reg dreg reg size = + do x86_mov2 size + x86_reg_emit dreg reg + +x86_mov_reg_mem :: (Num t) => Word8 -> Word32 -> t -> CodeGen e s () +x86_mov_reg_mem reg mem size = + do x86_mov2 size + x86_mem_emit reg mem + +x86_mov_reg_membase :: (Num t) => Word8 -> Word8 -> Word32 -> t -> CodeGen e s () +x86_mov_reg_membase reg basereg disp size = + do x86_mov2 size + x86_membase_emit reg basereg disp + +x86_mov_reg_memindex :: (Num t) => Word8 -> Word8 -> Word32 -> Word8 -> Word8 -> t -> CodeGen e s () +x86_mov_reg_memindex _ _ _ 4 _ _ = + failCodeGen $ PP.text "x86_mov_reg_memindex: cannot use (E)SP as index register" +x86_mov_reg_memindex reg basereg disp indexreg shft size = + do x86_mov2 size + x86_memindex_emit reg basereg disp indexreg shft + +x86_mov_reg_imm :: Word8 -> Word32 -> CodeGen e s () +x86_mov_reg_imm reg imm = + emit8 (0xb8 + reg) >> x86_imm_emit32 imm + +x86_mov_mem_imm :: (Num a) => Word32 -> Word32 -> a -> CodeGen e s () +x86_mov_mem_imm mem imm size = + if size == 1 + then do emit8 0xc6; + x86_mem_emit 0 mem + x86_imm_emit8 (fromIntegral imm) + else if size == 2 + then do emit8 0x66 + emit8 0xc7 + x86_mem_emit 0 mem + x86_imm_emit16 (fromIntegral imm) + else do emit8 0xc7 + x86_mem_emit 0 mem + x86_imm_emit32 imm + +x86_mov_membase_imm :: (Num a) => Word8 -> Word32 -> Word32 -> a -> CodeGen e s () +x86_mov_membase_imm basereg disp imm size = + if size == 1 + then do emit8 0xc6 + x86_membase_emit 0 basereg disp + x86_imm_emit8 (fromIntegral imm) + else if size == 2 + then do emit8 0x66 + emit8 0xc7 + x86_membase_emit 0 basereg disp + x86_imm_emit16 (fromIntegral imm) + else do emit8 0xc7 + x86_membase_emit 0 basereg disp + x86_imm_emit32 imm + +x86_mov_memindex_imm :: (Num a) => Word8 -> Word32 -> Word8 -> Word8 -> Word32 -> a -> CodeGen e s () +x86_mov_memindex_imm basereg disp indexreg shft imm size = + if size == 1 + then do emit8 0xc6 + x86_memindex_emit 0 basereg disp indexreg shft + x86_imm_emit8 (fromIntegral imm) + else if size == 2 + then do emit8 0x66 + emit8 0xc7 + x86_memindex_emit 0 basereg disp indexreg shft + x86_imm_emit16 (fromIntegral imm) + else do emit8 0xc7 + x86_memindex_emit 0 basereg disp indexreg shft + x86_imm_emit32 imm + +-- LEA: Load Effective Address + +x86_lea_mem :: Word8 -> Word32 -> CodeGen e s () +x86_lea_mem reg mem = emit8 0x8d >> x86_mem_emit reg mem + +x86_lea_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_lea_membase reg basereg disp = + emit8 0x8d >> x86_membase_emit reg basereg disp + +x86_lea_memindex :: Word8 -> Word8 -> Word32 -> Word8 -> Word8 -> CodeGen e s () +x86_lea_memindex reg basereg disp indexreg shft = + emit8 0x8d >> x86_memindex_emit reg basereg disp indexreg shft + +x86_widen_reg :: Word8 -> Word8 -> Bool -> Bool -> CodeGen e s () +x86_widen_reg dreg reg is_signed is_half = + if is_half || x86_is_byte_reg reg + then do let op = 0xb6 + (if is_signed then 0x08 else 0) + + (if is_half then 0x1 else 0) + emit8 0x0f + emit8 op + x86_reg_emit dreg reg + else failCodeGen (PP.text "widen: need byte register or is_half=True") + +x86_widen_mem :: Word8 -> Word32 -> Bool -> Bool -> CodeGen e s () +x86_widen_mem dreg mem is_signed is_half = + do let op = 0xb6 + (if is_signed then 0x08 else 0) + + (if is_half then 0x1 else 0) + emit8 0x0f + emit8 op + x86_mem_emit dreg mem + +x86_widen_membase :: Word8 -> Word8 -> Word32 -> Bool -> Bool -> CodeGen e s () +x86_widen_membase dreg basereg disp is_signed is_half = + do let op = 0xb6 + (if is_signed then 0x08 else 0) + + (if is_half then 0x1 else 0) + emit8 0x0f + emit8 op + x86_membase_emit dreg basereg disp + +x86_widen_memindex :: Word8 -> Word8 -> Word32 -> Word8 -> Word8 -> Bool -> Bool -> CodeGen e s () +x86_widen_memindex dreg basereg disp indexreg shft is_signed is_half = + do let op = 0xb6 + (if is_signed then 0x08 else 0) + + (if is_half then 0x1 else 0) + emit8 0x0f + emit8 op + x86_memindex_emit dreg basereg disp indexreg shft + +x86_cdq, x86_wait :: CodeGen s e () +x86_cdq = emit8 0x99 +x86_wait = emit8 0x9b + +x86_fp_op_mem :: Word8 -> Word32 -> Bool -> CodeGen e s () +x86_fp_op_mem opc mem is_double = + do emit8 (if is_double then 0xdc else 0xd8) + x86_mem_emit opc mem +x86_fp_op_membase :: Word8 -> Word8 -> Word32 -> Bool -> CodeGen e s () +x86_fp_op_membase opc basereg disp is_double = + do emit8 (if is_double then 0xdc else 0xd8) + x86_membase_emit opc basereg disp +x86_fp_op ::Word8 -> Word8 -> CodeGen e s () +x86_fp_op opc index = + do emit8 0xd8 + emit8 (0xc0 + (opc `shiftL` 3) + (index .&. 0x07)) +x86_fp_op_reg :: Word8 -> Word8 -> Bool -> CodeGen e s () +x86_fp_op_reg opc index pop_stack = + do let opcMap = [ 0, 1, 2, 3, 5, 4, 7, 6, 8] + emit8 (if pop_stack then 0xde else 0xdc) + emit8 (0xc0 + ((opcMap !! fromIntegral opc) `shiftL` 3) + (index .&. 0x07)) + + +-- @x86_fp_int_op_membase +-- Supports FPU operations between ST(0) and integer operand in memory. +-- Operation encoded using X86_FP_Opcode enum. +-- Operand is addressed by [basereg + disp]. +-- is_int specifies whether operand is int32 (TRUE) or int16 (FALSE). + +x86_fp_int_op_membase :: Word8 -> Word8 -> Word32 -> Bool -> CodeGen e s () +x86_fp_int_op_membase opc basereg disp is_int = + do emit8 (if is_int then 0xda else 0xde) + x86_membase_emit opc basereg disp +x86_fstp :: Word8 -> CodeGen e s () +x86_fstp index = + emit8 0xdd >> emit8 (0xd8 + index) +x86_fcompp :: CodeGen e s () +x86_fcompp = emit8 0xde >> emit8 0xd9 +x86_fucompp :: CodeGen e s () +x86_fucompp = emit8 0xda >> emit8 0xe9 +x86_fnstsw :: CodeGen e s () +x86_fnstsw = emit8 0xdf >> emit8 0xe0 +x86_fnstcw :: Word32 -> CodeGen e s () +x86_fnstcw mem = emit8 0xd9 >> x86_mem_emit 7 mem +x86_fnstcw_membase :: Word8 -> Word32 -> CodeGen e s () +x86_fnstcw_membase basereg disp = + emit8 0xd9 >> x86_membase_emit 7 basereg disp +x86_fldcw :: Word32 -> CodeGen e s () +x86_fldcw mem = emit8 0xd9 >> x86_mem_emit 5 mem +x86_fldcw_membase :: Word8 -> Word32 -> CodeGen e s () +x86_fldcw_membase basereg disp = + emit8 0xd9 >> x86_membase_emit 5 basereg disp +x86_fchs :: CodeGen e s () +x86_fchs = emit8 0xd9 >> emit8 0xe0 +x86_frem :: CodeGen e s () +x86_frem = emit8 0xd9 >> emit8 0xf8 +x86_fxch :: Word8 -> CodeGen e s () +x86_fxch index = emit8 0xd9 >> emit8 (0xc8 + (index .&. 0x07)) +x86_fcomi :: Word8 -> CodeGen e s () +x86_fcomi index = emit8 0xdb >> emit8 (0xf0 + (index .&. 0x07)) +x86_fcomip :: Word8 -> CodeGen e s () +x86_fcomip index = emit8 0xdf >> emit8 (0xf0 + (index .&. 0x07)) +x86_fucomi :: Word8 -> CodeGen e s () +x86_fucomi index = emit8 0xdb >> emit8 (0xe8 + (index .&. 0x07)) +x86_fucomip :: Word8 -> CodeGen e s () +x86_fucomip index = emit8 0xdf >> emit8 (0xe8 + (index .&. 0x07)) + +data FIntSize = FInt16 | FInt32 | FInt64 + +x86_fld :: Word32 -> Bool -> CodeGen e s () +x86_fld mem is_double = + do emit8 (if is_double then 0xdd else 0xd9) + x86_mem_emit 0 mem +x86_fld_membase :: Word8 -> Word32 -> Bool -> CodeGen e s () +x86_fld_membase basereg disp is_double = + do emit8 (if is_double then 0xdd else 0xd9) + x86_membase_emit 0 basereg disp +x86_fld80_mem :: Word32 -> CodeGen e s () +x86_fld80_mem mem = emit8 0xdb >> x86_mem_emit 5 mem +x86_fld80_membase :: Word8 -> Word32 -> CodeGen e s () +x86_fld80_membase basereg disp = + emit8 0xdb >> x86_membase_emit 5 basereg disp +x86_fild :: Word32 -> FIntSize -> CodeGen e s () +x86_fild mem size = + case size of + FInt16 -> emit8 0xdf >> x86_mem_emit 0 mem + FInt32 -> emit8 0xdb >> x86_mem_emit 0 mem + FInt64 -> emit8 0xdf >> x86_mem_emit 5 mem +x86_fild_membase :: Word8 -> Word32 -> FIntSize -> CodeGen e s () +x86_fild_membase basereg disp size = + case size of + FInt16 -> emit8 0xdb >> x86_membase_emit 0 basereg disp + FInt32 -> emit8 0xdb >> x86_membase_emit 0 basereg disp + FInt64 -> emit8 0xdf >> x86_membase_emit 5 basereg disp +x86_fld_reg :: Word8 -> CodeGen e s () +x86_fld_reg index = + emit8 0xd9 >> emit8 (0xc0 + (index .&. 0x07)) +x86_fldz :: CodeGen e s () +x86_fldz = emit8 0xd9 >> emit8 0xee +x86_fld1 :: CodeGen e s () +x86_fld1 = emit8 0xd9 >> emit8 0xe8 +x86_fldpi :: CodeGen e s () +x86_fldpi = emit8 0xd9 >> emit8 0xeb + +x86_fst :: Word32 -> Bool -> Bool -> CodeGen e s () +x86_fst mem is_double pop_stack = + do emit8 (if is_double then 0xdd else 0xd9) + x86_mem_emit (2 + (if pop_stack then 1 else 0)) mem +x86_fst_membase :: Word8 -> Word32 -> Bool -> Bool -> CodeGen e s () +x86_fst_membase basereg disp is_double pop_stack = + do emit8 (if is_double then 0xdd else 0xd9) + x86_membase_emit (2 + (if pop_stack then 1 else 0)) basereg disp +x86_fst80_mem :: Word32 -> CodeGen e s () +x86_fst80_mem mem = emit8 0xdb >> x86_mem_emit 7 mem +x86_fst80_membase :: Word8 -> Word32 -> CodeGen e s () +x86_fst80_membase basereg disp = + emit8 0xdb >> x86_membase_emit 7 basereg disp +x86_fist_pop :: Word32 -> FIntSize -> CodeGen e s () +x86_fist_pop mem size = + case size of + FInt16 -> emit8 0xdf >> x86_mem_emit 3 mem + FInt32 -> emit8 0xdb >> x86_mem_emit 3 mem + FInt64 -> emit8 0xdf >> x86_mem_emit 7 mem +x86_fist_pop_membase :: Word8 -> Word32 -> FIntSize -> CodeGen e s () +x86_fist_pop_membase basereg disp size = + case size of + FInt16 -> emit8 0xdf >> x86_membase_emit 3 basereg disp + FInt32 -> emit8 0xdb >> x86_membase_emit 3 basereg disp + FInt64 -> emit8 0xdf >> x86_membase_emit 7 basereg disp +x86_fstsw :: CodeGen e s () +x86_fstsw = emit8 0x9b >> emit8 0xdf >> emit8 0xe0 + +-- @x86_fist_membase +-- Converts content of ST(0) to integer and stores it at memory location +-- addressed by [basereg + disp]. +-- size specifies whether destination is int32 or int16. + +x86_fist_membase :: Word8 -> Word32 -> FIntSize -> CodeGen e s () +x86_fist_membase basereg disp size = + case size of + FInt16 -> emit8 0xdf >> x86_membase_emit 2 basereg disp + FInt32 -> emit8 0xdb >> x86_membase_emit 2 basereg disp + FInt64 -> error "fist does not support 64 bit access" + +x86_fincstp :: CodeGen e s () +x86_fincstp = emit8 0xd9 >> emit8 0xf7 + +x86_fdecstp :: CodeGen e s () +x86_fdecstp = emit8 0xd9 >> emit8 0xf6 + +-- PUSH instruction. + +x86_push_reg :: Word8 -> CodeGen e s () +x86_push_reg reg = emit8 (0x50 + reg) + +x86_push_regp :: Word8 -> CodeGen e s () +x86_push_regp reg = emit8 0xff >> x86_regp_emit 6 reg + +x86_push_mem :: Word32 -> CodeGen e s () +x86_push_mem mem = emit8 0xff >> x86_mem_emit 6 mem + +x86_push_membase :: Word8 -> Word32 -> CodeGen e s () +x86_push_membase basereg disp = + emit8 0xff >> x86_membase_emit 6 basereg disp + +x86_push_memindex :: Word8 -> Word32 -> Word8 -> Word8 -> CodeGen e s () +x86_push_memindex basereg disp indexreg shft = + emit8 0xff >> x86_memindex_emit 6 basereg disp indexreg shft + +x86_push_imm_template :: CodeGen e s () +x86_push_imm_template = x86_push_imm 0xf0f0f0f0 + +x86_push_imm :: Word32 -> CodeGen e s () +x86_push_imm imm = + if x86_is_imm8 imm + then emit8 0x6A >> x86_imm_emit8 (fromIntegral imm) + else emit8 0x68 >> x86_imm_emit32 imm + +-- POP instruction. + +x86_pop_reg :: Word8 -> CodeGen e s () +x86_pop_reg reg = emit8 (0x58 + reg) + +x86_pop_mem :: Word32 -> CodeGen e s () +x86_pop_mem mem = emit8 0x87 >> x86_mem_emit 0 mem + +x86_pop_membase :: Word8 -> Word32 -> CodeGen e s () +x86_pop_membase basereg disp = + emit8 0x87 >> x86_membase_emit 0 basereg disp + +x86_pushad :: CodeGen e s () +x86_pushad = emit8 0x60 + +x86_pushfd :: CodeGen e s () +x86_pushfd = emit8 0x9c + +x86_popad :: CodeGen e s () +x86_popad = emit8 0x61 + +x86_popfd :: CodeGen e s () +x86_popfd = emit8 0x9d + +x86_loop :: Word8 -> CodeGen e s () +x86_loop imm = emit8 0xe2 >> x86_imm_emit8 imm + +x86_loope :: Word8 -> CodeGen e s () +x86_loope imm = emit8 0xe1 >> x86_imm_emit8 imm + +x86_loopne :: Word8 -> CodeGen e s () +x86_loopne imm = emit8 0xe0 >> x86_imm_emit8 imm + +x86_jump32 :: Word32 -> CodeGen e s () +x86_jump32 imm = emit8 0xe9 >> x86_imm_emit32 imm + +x86_jump8 :: Word8 -> CodeGen e s () +x86_jump8 imm = emit8 0xeb >> x86_imm_emit8 imm + +x86_jump_reg :: Word8 -> CodeGen e s () +x86_jump_reg reg = emit8 0xff >> x86_reg_emit 4 reg + +x86_jump_mem :: Word32 -> CodeGen e s () +x86_jump_mem mem = emit8 0xff >> x86_mem_emit 4 mem + +x86_jump_membase :: Word8 -> Word32 -> CodeGen e s () +x86_jump_membase basereg disp = + emit8 0xff >> x86_membase_emit 4 basereg disp + +x86_jump_pointer :: Ptr a -> CodeGen e s () +x86_jump_pointer target = + do inst <- getCodeOffset + base <- getBasePtr + let ptr = base `plusPtr` inst + x86_jump32 (fromIntegral (target `minusPtr` ptr - 5)) + +-- target is a pointer in our buffer. + +{- +x86_jump_code target = + do inst <- getCodeOffset + let t = target - inst - 2 + if x86_is_imm8 t + then x86_jump8 (fromIntegral t) + else x86_jump32 (fromIntegral (t - 3)) +-} +{- +x86_jump_disp disp = + do let t = disp - 2 + if x86_is_imm8 t + then x86_jump8 (fromIntegral t) + else x86_jump32 (t - 3) +-} + +x86_branch8 :: Int -> Word8 -> Bool -> CodeGen e s () +x86_branch8 cond imm is_signed = + do if is_signed + then emit8 (x86_cc_signed_map !! cond) + else emit8 (x86_cc_unsigned_map !! cond) + x86_imm_emit8 imm + +x86_branch32 :: Int -> Word32 -> Bool -> CodeGen e s () +x86_branch32 cond imm is_signed = + do emit8 0x0f + if is_signed + then emit8 ((x86_cc_signed_map !! cond) + 0x10) + else emit8 ((x86_cc_unsigned_map !! cond) + 0x10) + x86_imm_emit32 imm + +x86_branch :: Int -> Int -> Bool -> CodeGen e s () +x86_branch cond target is_signed = + do inst <- getCodeOffset + let offset = target - inst - 2; + if x86_is_imm8 offset + then x86_branch8 cond (fromIntegral offset) is_signed + else x86_branch32 cond (fromIntegral (offset - 4)) is_signed + +x86_branch_pointer :: Int -> Ptr a -> Bool -> CodeGen e s () +x86_branch_pointer cond target is_signed = + do inst <- getCodeOffset + base <- getBasePtr + let ptr = base `plusPtr` inst + x86_branch32 cond (fromIntegral (target `minusPtr` ptr - 5)) is_signed + +{- +x86_branch_disp cond disp is_signed = + do let offset = disp - 2 + if x86_is_imm8 offset + then x86_branch8 cond (fromIntegral offset) is_signed + else x86_branch32 cond (offset - 4) is_signed +-} + +x86_jecxz :: Word8 -> CodeGen e s () +x86_jecxz imm = emit8 0xe3 >> emit8 imm + +x86_set_reg :: Int -> Word8 -> Bool -> CodeGen e s () +x86_set_reg cond reg is_signed = + do emit8 0x0f + if is_signed + then emit8 ((x86_cc_signed_map !! cond) + 0x20) + else emit8 ((x86_cc_unsigned_map !! cond) + 0x20) + x86_reg_emit 0 reg + +x86_set_mem :: Int -> Word32 -> Bool -> CodeGen e s () +x86_set_mem cond mem is_signed = + do emit8 0x0f + if is_signed + then emit8 ((x86_cc_signed_map !! cond) + 0x20) + else emit8 ((x86_cc_unsigned_map !! cond) + 0x20) + x86_mem_emit 0 mem +x86_set_membase :: Int -> Word8 -> Word32 -> Bool -> CodeGen e s () +x86_set_membase cond basereg disp is_signed = + do emit8 0x0f + if is_signed + then emit8 ((x86_cc_signed_map !! cond) + 0x20) + else emit8 ((x86_cc_unsigned_map !! cond) + 0x20) + x86_membase_emit 0 basereg disp + +-- Call instructions. + +x86_call_imm :: Word32 -> CodeGen s e () +x86_call_imm disp = emit8 0xe8 >> x86_imm_emit32 disp + +x86_call_reg :: Word8 -> CodeGen s e () +x86_call_reg reg = emit8 0xff >> x86_reg_emit 2 reg + +x86_call_mem :: Word32 -> CodeGen s e () +x86_call_mem mem = emit8 0xff >> x86_mem_emit 2 mem + +x86_call_membase :: Word8 -> Word32 -> CodeGen s e () +x86_call_membase basereg disp = + emit8 0xff >> x86_membase_emit 2 basereg disp + +x86_call_code :: Int -> CodeGen s e () +x86_call_code target = + do inst <- getCodeOffset + let _x86_offset = (target - inst - 5) + x86_call_imm (fromIntegral _x86_offset) + +x86_call_hs :: FunPtr a -> CodeGen e s () +x86_call_hs fptr = do { offset <- getCodeOffset + ; base <- getBasePtr + ; emitRelocInfo (offset + 1) + RelocPCRel fptr + ; x86_call_imm $ (fromIntegral (minusPtr (castFunPtrToPtr fptr) (plusPtr base offset) - 5)) + } + +-- RET instruction. + +x86_ret :: CodeGen s e () +x86_ret = emit8 0xc3 + +x86_ret_imm :: Word16 -> CodeGen s e () +x86_ret_imm imm = + if imm == 0 then x86_ret else emit8 0xc2 >> x86_imm_emit16 imm + +-- Conditional move instructions. +x86_cmov ::Int -> Bool -> CodeGen e s () +x86_cmov cond is_signed = + do emit8 0x0f + if is_signed + then emit8 ((x86_cc_signed_map !! cond) - 0x30) + else emit8 ((x86_cc_unsigned_map !! cond) - 0x30) +x86_cmov_reg :: Int -> Bool -> Word8 -> Word8 -> CodeGen e s () +x86_cmov_reg cond is_signed dreg reg = + do x86_cmov cond is_signed + x86_reg_emit dreg reg +x86_cmov_mem :: Int -> Bool -> Word8 -> Word32 -> CodeGen e s () +x86_cmov_mem cond is_signed reg mem = + do x86_cmov cond is_signed + x86_mem_emit reg mem +x86_cmov_membase :: Int -> Bool -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_cmov_membase cond is_signed reg basereg disp = + do x86_cmov cond is_signed + x86_membase_emit reg basereg disp + +-- Note: definition for ENTER instruction is not complete. The counter +-- for the display setup is set to 0. + +x86_enter :: Word16 -> CodeGen s e () +x86_enter framesize = emit8 0xc8 >> x86_imm_emit16 framesize >> emit8 0 + +x86_leave :: CodeGen s e () +x86_leave = emit8 0xc9 + +x86_sahf :: CodeGen s e () +x86_sahf = emit8 0x9e + +-- Trigonometric floating point functions + +x86_fsin, x86_fcos, x86_fabs, x86_ftst, x86_fxam, x86_fpatan, + x86_fprem, x86_fprem1, x86_frndint, x86_fsqrt, x86_fptan :: CodeGen s e () +x86_fsin = emit8 0xd9 >> emit8 0xfe +x86_fcos = emit8 0xd9 >> emit8 0xff +x86_fabs = emit8 0xd9 >> emit8 0xe1 +x86_ftst = emit8 0xd9 >> emit8 0xe4 +x86_fxam = emit8 0xd9 >> emit8 0xe5 +x86_fpatan = emit8 0xd9 >> emit8 0xf3 +x86_fprem = emit8 0xd9 >> emit8 0xf8 +x86_fprem1 = emit8 0xd9 >> emit8 0xf5 +x86_frndint = emit8 0xd9 >> emit8 0xfc +x86_fsqrt = emit8 0xd9 >> emit8 0xfa +x86_fptan = emit8 0xd9 >> emit8 0xf2 + +-- Fast instruction sequences for 1 to 7-byte noops. + +x86_padding ::(Num t) => t -> CodeGen e s () +x86_padding size = + case size of + 1 -> x86_nop + 2 -> emit8 0x8b >> emit8 0xc0 + 3 -> emit8 0x8d >> emit8 0x6d >> emit8 0x00 + 4 -> emit8 0x8d >> emit8 0x64 >> emit8 0x24 >> emit8 0x00 + 5 -> emit8 0x8d >> emit8 0x64 >> emit8 0x24 >> emit8 0x00 >> + x86_nop + 6 -> emit8 0x8d >> emit8 0xad >> + emit8 0x00 >> emit8 0x00 >> + emit8 0x00 >> emit8 0x00 + 7 -> emit8 0x8d >> emit8 0xa4 >> + emit8 0x24 >> emit8 0x00 >> + emit8 0x00 >> emit8 0x00 >> + emit8 0x00 + _ -> failCodeGen (PP.text "invalid padding size") + +-- Generate the code for a function prologue. The frame_size is the +-- number of bytes to be allocated as the frame size, and the reg_mask +-- specifies which registers to save on function entry. + +x86_prolog :: Int -> Int -> CodeGen e s () +x86_prolog frame_size reg_mask = + do x86_push_reg x86_ebp + x86_mov_reg_reg x86_ebp x86_esp x86_dword_size + gen_push 0 1 + if frame_size /= 0 + then x86_alu_reg_imm x86_sub x86_esp frame_size + else return () + where + gen_push i m = + if i <= x86_edi + then do if (reg_mask .&. m) /= 0 + then x86_push_reg i + else return () + gen_push (i + 1) (m `shiftL` 1) + else return () + +-- Opposite to x86_prolog: destroys the stack frame and restores the +-- registers in reg_mask, which should be the same as the register mask +-- used on function entry. + +x86_epilog :: Int -> CodeGen e s () +x86_epilog reg_mask = + do gen_pop x86_edi (1 `shiftL` (fromIntegral x86_edi)) + x86_mov_reg_reg x86_esp x86_ebp x86_dword_size + x86_pop_reg x86_ebp + x86_ret + where + gen_pop i m = + if m /= 0 + then do if (reg_mask .&. m) /= 0 + then x86_pop_reg i + else return () + gen_pop (i - 1) (m `shiftR` 1) + else return () + +-- TODO: Move signatures to definition, delete duplicates. +x86_xchg_reg_reg :: + (Num a) => + Word8 + -> Word8 + -> a + -> CodeGen e s () +x86_xchg_mem_reg :: + (Num a) => + Word32 + -> Word8 + -> a + -> CodeGen e s () +x86_xchg_membase_reg :: + (Num a) => + Word8 + -> Word32 + -> Word8 + -> a + -> CodeGen e s () +x86_xadd_reg_reg :: + (Num a) => + Word8 + -> Word8 + -> a + -> CodeGen e s () +x86_xadd_mem_reg :: + (Num a) => + Word32 + -> Word8 + -> a + -> CodeGen e s () +x86_xadd_membase_reg :: + (Num a) => + Word8 + -> Word32 + -> Word8 + -> a + -> CodeGen e s () +x86_inc_mem :: + Word32 -> CodeGen e s () +x86_inc_membase :: + Word8 + -> Word32 + -> CodeGen e s () +x86_inc_reg :: + Word8 -> CodeGen e s () +x86_dec_mem :: + Word32 -> CodeGen e s () +x86_dec_membase :: + Word8 + -> Word32 + -> CodeGen e s () +x86_dec_reg :: + Word8 -> CodeGen e s () +x86_not_mem :: + Word32 -> CodeGen e s () +x86_not_membase :: + Word8 + -> Word32 + -> CodeGen e s () +x86_not_reg :: + Word8 -> CodeGen e s () +x86_neg_mem :: + Word32 -> CodeGen e s () +x86_neg_membase :: + Word8 + -> Word32 + -> CodeGen e s () +x86_neg_reg :: + Word8 -> CodeGen e s () +x86_alu_mem_imm :: + Word8 + -> Word32 + -> Word32 + -> CodeGen e s () +x86_alu_membase_imm :: + Word8 + -> Word8 + -> Word32 + -> Word32 + -> CodeGen e s () +x86_alu_membase8_imm :: + Word8 + -> Word8 + -> Word32 + -> Word8 + -> CodeGen e s () +x86_alu_mem_reg :: + Word8 + -> Word32 + -> Word8 + -> CodeGen e s () +x86_alu_membase_reg :: + Word8 + -> Word8 + -> Word32 + -> Word8 + -> CodeGen e s () +x86_alu_reg_reg :: + Word8 + -> Word8 + -> Word8 + -> CodeGen e s () +x86_alu_reg8_reg8 :: + Word8 + -> Word8 + -> Word8 + -> Bool + -> Bool + -> CodeGen e s () +x86_alu_reg_mem :: + Word8 + -> Word8 + -> Word32 + -> CodeGen e s () +x86_alu_reg_membase :: + Word8 + -> Word8 + -> Word8 + -> Word32 + -> CodeGen e s () +x86_test_reg_imm :: + Word8 + -> Word32 + -> CodeGen e s () +x86_test_mem_imm :: + Word32 + -> Word32 + -> CodeGen e s () +x86_test_membase_imm :: + Word8 + -> Word32 + -> Word32 + -> CodeGen e s () +x86_test_reg_reg :: + Word8 + -> Word8 + -> CodeGen e s () +x86_test_mem_reg :: + Word32 + -> Word8 + -> CodeGen e s () +x86_test_membase_reg :: + Word8 + -> Word32 + -> Word8 + -> CodeGen e s () +x86_shift_reg_imm :: + Word8 + -> Word8 + -> Word8 + -> CodeGen e s () +x86_shift_mem_imm :: + Word8 + -> Word32 + -> Word8 + -> CodeGen e s () +x86_shift_membase_imm :: + Word8 + -> Word8 + -> Word32 + -> Word8 + -> CodeGen e s () +x86_shift_reg :: + Word8 + -> Word8 + -> CodeGen e s () +x86_shift_mem :: + Word8 + -> Word32 + -> CodeGen e s () +x86_shift_membase :: + Word8 + -> Word8 + -> Word32 + -> CodeGen e s () +x86_shrd_reg :: + Word8 + -> Word8 + -> CodeGen e s () +x86_shrd_reg_imm :: + Word8 + -> Word8 + -> Word8 + -> CodeGen e s () +x86_shld_reg :: + Word8 + -> Word8 + -> CodeGen e s () +x86_shld_reg_imm :: + Word8 + -> Word8 + -> Word8 + -> CodeGen e s () + +-- ============================================================================= +-- SSE instructions. +-- ============================================================================= + +data X86_SSE_PFX = X86_SSE_SD + | X86_SSE_SS + | X86_SSE_PD + | X86_SSE_PS +--newtype X86_SSE_PFX = X86_SSE_PFX (forall e s. CodeGen e s ()) + +x86_sse_sd, x86_sse_ss, x86_sse_pd, x86_sse_ps :: X86_SSE_PFX +x86_sse_sd = X86_SSE_SD +x86_sse_ss = X86_SSE_SS +x86_sse_pd = X86_SSE_PD +x86_sse_ps = X86_SSE_PS + +emit_sse :: X86_SSE_PFX -> CodeGen e s () +emit_sse X86_SSE_SD = emit8 0xf2 +emit_sse X86_SSE_SS = emit8 0xf3 +emit_sse X86_SSE_PD = emit8 0x66 +emit_sse X86_SSE_PS = return () + +x86_sqrt_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_sqrt_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x51 + x86_reg_emit dreg reg + +x86_sqrt_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_sqrt_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x51 + x86_mem_emit dreg mem + +x86_sqrt_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_sqrt_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x51 + x86_membase_emit dreg basereg disp + +x86_add_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_add_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x58 + x86_reg_emit dreg reg + +x86_add_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_add_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x58 + x86_mem_emit dreg mem + +x86_add_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_add_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x58 + x86_membase_emit dreg basereg disp + +x86_mul_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_mul_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x59 + x86_reg_emit dreg reg + +x86_mul_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_mul_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x59 + x86_mem_emit dreg mem + +x86_mul_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_mul_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x59 + x86_membase_emit dreg basereg disp + +x86_sub_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_sub_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x5c + x86_reg_emit dreg reg + +x86_sub_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_sub_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x5c + x86_mem_emit dreg mem + +x86_sub_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_sub_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x5c + x86_membase_emit dreg basereg disp + +x86_min_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_min_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x5d + x86_reg_emit dreg reg + +x86_min_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_min_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x5d + x86_mem_emit dreg mem + +x86_min_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_min_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x5d + x86_membase_emit dreg basereg disp + +x86_div_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_div_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x5e + x86_reg_emit dreg reg + +x86_div_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_div_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x5e + x86_mem_emit dreg mem + +x86_div_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_div_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x5e + x86_membase_emit dreg basereg disp + +x86_max_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_max_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x5f + x86_reg_emit dreg reg + +x86_max_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_max_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x5f + x86_mem_emit dreg mem + +x86_max_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_max_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x5f + x86_membase_emit dreg basereg disp + +x86_mov_sse_reg_reg :: X86_SSE_PFX -> Word8 -> Word8 -> CodeGen e s () +x86_mov_sse_reg_reg pfx dreg reg = + do emit_sse pfx + emit8 0x0f + emit8 0x10 + x86_reg_emit dreg reg + +x86_mov_sse_reg_mem :: X86_SSE_PFX -> Word8 -> Word32 -> CodeGen e s () +x86_mov_sse_reg_mem pfx dreg mem = + do emit_sse pfx + emit8 0x0f + emit8 0x10 + x86_mem_emit dreg mem + +x86_mov_sse_reg_membase :: X86_SSE_PFX -> Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_mov_sse_reg_membase pfx dreg basereg disp = + do emit_sse pfx + emit8 0x0f + emit8 0x10 + x86_membase_emit dreg basereg disp + +x86_mov_sse_mem_reg :: X86_SSE_PFX -> Word32 -> Word8 -> CodeGen e s () +x86_mov_sse_mem_reg pfx mem reg = + do emit_sse pfx + emit8 0x0f + emit8 0x11 + x86_mem_emit reg mem + +x86_mov_sse_membase_reg :: X86_SSE_PFX -> Word8 -> Word32 -> Word8 -> CodeGen e s () +x86_mov_sse_membase_reg pfx basereg disp reg = + do emit_sse pfx + emit8 0x0f + emit8 0x11 + x86_membase_emit reg basereg disp + +x86_ucomisd_reg_reg :: Word8 -> Word8 -> CodeGen e s () +x86_ucomisd_reg_reg dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x2e + x86_reg_emit dreg reg + +x86_ucomisd_reg_mem :: Word8 -> Word32 -> CodeGen e s () +x86_ucomisd_reg_mem dreg mem = + do emit8 0x66 + emit8 0x0f + emit8 0x2e + x86_mem_emit dreg mem + +x86_ucomisd_reg_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_ucomisd_reg_membase dreg basereg disp = + do emit8 0x66 + emit8 0x0f + emit8 0x2e + x86_membase_emit dreg basereg disp + +x86_ucomiss_reg_reg :: Word8 -> Word8 -> CodeGen e s () +x86_ucomiss_reg_reg dreg reg = + do emit8 0x0f + emit8 0x2e + x86_reg_emit dreg reg + +x86_ucomiss_reg_mem :: Word8 -> Word32 -> CodeGen e s () +x86_ucomiss_reg_mem dreg mem = + do emit8 0x0f + emit8 0x2e + x86_mem_emit dreg mem + +x86_ucomiss_reg_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_ucomiss_reg_membase dreg basereg disp = + do emit8 0x0f + emit8 0x2e + x86_membase_emit dreg basereg disp + +x86_comisd_reg_reg :: Word8 -> Word8 -> CodeGen e s () +x86_comisd_reg_reg dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x2f + x86_reg_emit dreg reg + +x86_comisd_reg_mem :: Word8 -> Word32 -> CodeGen e s () +x86_comisd_reg_mem dreg mem = + do emit8 0x66 + emit8 0x0f + emit8 0x2f + x86_mem_emit dreg mem + +x86_comisd_reg_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_comisd_reg_membase dreg basereg disp = + do emit8 0x66 + emit8 0x0f + emit8 0x2e + x86_membase_emit dreg basereg disp + +x86_comiss_reg_reg :: Word8 -> Word8 -> CodeGen e s () +x86_comiss_reg_reg dreg reg = + do emit8 0x0f + emit8 0x2f + x86_reg_emit dreg reg + +x86_comiss_reg_mem :: Word8 -> Word32 -> CodeGen e s () +x86_comiss_reg_mem dreg mem = + do emit8 0x0f + emit8 0x2f + x86_mem_emit dreg mem + +x86_comiss_reg_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_comiss_reg_membase dreg basereg disp = + do emit8 0x0f + emit8 0x2e + x86_membase_emit dreg basereg disp + + +newtype XMMReg = XMMReg Word8 + deriving (Eq, Ord) + +newtype Mem = Mem Word32 + +data MemBase = MemBase Word8 Word32 + + +class XMMLocation xmm where + xmm_location_emit :: Word8 -> xmm -> CodeGen e s () + +instance XMMLocation XMMReg where + xmm_location_emit dreg (XMMReg reg) = + x86_reg_emit dreg reg + +instance XMMLocation Mem where + xmm_location_emit dreg (Mem mem) = + x86_mem_emit dreg mem + +instance XMMLocation MemBase where + xmm_location_emit dreg (MemBase basereg disp) = + x86_membase_emit dreg basereg disp + + +x86_movss_to_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movss_to_reg dreg reg = + do emit8 0xf3 + emit8 0x0f + emit8 0x10 + xmm_location_emit dreg reg + +x86_movss_from_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movss_from_reg dreg reg = + do emit8 0xf3 + emit8 0x0f + emit8 0x11 + xmm_location_emit dreg reg + +x86_movsd_to_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movsd_to_reg dreg reg = + do emit8 0xf2 + emit8 0x0f + emit8 0x10 + xmm_location_emit dreg reg + +x86_movsd_from_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movsd_from_reg dreg reg = + do emit8 0xf2 + emit8 0x0f + emit8 0x11 + xmm_location_emit dreg reg + + +-- | xmm must not be a register +x86_movlps_to_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movlps_to_reg dreg reg = + do emit8 0x0f + emit8 0x12 + xmm_location_emit dreg reg + +-- | xmm must not be a register +x86_movlps_from_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movlps_from_reg dreg reg = + do emit8 0x0f + emit8 0x13 + xmm_location_emit dreg reg + +-- | xmm must not be a register +x86_movlpd_to_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movlpd_to_reg dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x12 + xmm_location_emit dreg reg + +-- | xmm must not be a register +x86_movlpd_from_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movlpd_from_reg dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x13 + xmm_location_emit dreg reg + + +x86_movups_to_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movups_to_reg dreg reg = + do emit8 0x0f + emit8 0x10 + xmm_location_emit dreg reg + +x86_movups_from_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movups_from_reg dreg reg = + do emit8 0x0f + emit8 0x11 + xmm_location_emit dreg reg + +x86_movupd_to_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movupd_to_reg dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x10 + xmm_location_emit dreg reg + +x86_movupd_from_reg :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_movupd_from_reg dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x11 + xmm_location_emit dreg reg + + +x86_haddps :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_haddps dreg reg = + do emit8 0xf2 + emit8 0x0f + emit8 0x7c + xmm_location_emit dreg reg + +x86_haddpd :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_haddpd dreg reg = + do emit8 0x66 + emit8 0x0f + emit8 0x7c + xmm_location_emit dreg reg + + +x86_shufps :: XMMLocation xmm => Word8 -> xmm -> Word8 -> CodeGen e s () +x86_shufps dreg reg src = + do emit8 0x0f + emit8 0xc6 + xmm_location_emit dreg reg + emit8 src + +x86_shufpd :: XMMLocation xmm => Word8 -> xmm -> Word8 -> CodeGen e s () +x86_shufpd dreg reg src = + do emit8 0x66 + emit8 0x0f + emit8 0xc6 + xmm_location_emit dreg reg + emit8 src + + +x86_cvtdq2ps :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_cvtdq2ps dreg reg = + do emit8 0x0f + emit8 0x5b + xmm_location_emit dreg reg + +x86_cvttps2dq :: XMMLocation xmm => Word8 -> xmm -> CodeGen e s () +x86_cvttps2dq dreg reg = + do emit8 0xf3 + emit8 0x0f + emit8 0x5b + xmm_location_emit dreg reg + + + +-- ============================================================================= +-- Prefetching instructions. +-- ============================================================================= + +x86_prefetch0_mem :: Word32 -> CodeGen e s () +x86_prefetch0_mem m = x86_prefetch_mem 1 m + +x86_prefetch1_mem :: Word32 -> CodeGen e s () +x86_prefetch1_mem m = x86_prefetch_mem 2 m + +x86_prefetch2_mem :: Word32 -> CodeGen e s () +x86_prefetch2_mem m = x86_prefetch_mem 3 m + +x86_prefetchnta_mem :: Word32 -> CodeGen e s () +x86_prefetchnta_mem m = x86_prefetch_mem 0 m + +x86_prefetch_mem :: Word8 -> Word32 -> CodeGen e s () +x86_prefetch_mem hint disp = + do emit8 0x0f + emit8 0x18 + x86_address_byte 0 hint 0 + x86_imm_emit32 disp + +x86_prefetch0_membase :: Word8 -> Word32 -> CodeGen e s () +x86_prefetch0_membase r m = x86_prefetch_membase 1 r m + +x86_prefetch1_membase :: Word8 -> Word32 -> CodeGen e s () +x86_prefetch1_membase r m = x86_prefetch_membase 2 r m + +x86_prefetch2_membase :: Word8 -> Word32 -> CodeGen e s () +x86_prefetch2_membase r m = x86_prefetch_membase 3 r m + +x86_prefetchnta_membase :: Word8 -> Word32 -> CodeGen e s () +x86_prefetchnta_membase r m = x86_prefetch_membase 0 r m + +x86_prefetch_membase :: Word8 -> Word8 -> Word32 -> CodeGen e s () +x86_prefetch_membase hint reg disp = + do emit8 0x0f + emit8 0x18 + x86_membase_emit hint reg disp + +x86_prefetch0_regp :: Word8 -> CodeGen e s () +x86_prefetch0_regp r = x86_prefetch_regp 1 r + +x86_prefetch1_regp :: Word8 -> CodeGen e s () +x86_prefetch1_regp r = x86_prefetch_regp 2 r + +x86_prefetch2_regp :: Word8 -> CodeGen e s () +x86_prefetch2_regp r = x86_prefetch_regp 3 r + +x86_prefetchnta_regp :: Word8 -> CodeGen e s () +x86_prefetchnta_regp r = x86_prefetch_regp 0 r + +x86_prefetch_regp :: Word8 -> Word8 -> CodeGen e s () +x86_prefetch_regp hint reg = + do emit8 0x0f + emit8 0x18 + x86_regp_emit hint reg + diff --git a/Harpy/X86Disassembler.hs b/Harpy/X86Disassembler.hs new file mode 100644 index 0000000..d7cccc8 --- /dev/null +++ b/Harpy/X86Disassembler.hs @@ -0,0 +1,32 @@ +-------------------------------------------------------------------------- +-- | +-- Module : Harpy.X86Disassembler +-- Copyright : (c) Martin Grabmueller and Dirk Kleeblatt +-- License : GPL +-- +-- Maintainer : {magr,klee}@cs.tu-berlin.de +-- Stability : provisional +-- Portability : portable +-- +-- Disassembler for x86 machine code. +-- +-- This is a module for compatibility with earlier Harpy releases. It +-- re-exports the disassembler from the disassembler package. +-------------------------------------------------------------------------- + +module Harpy.X86Disassembler( + -- * Types + Opcode, + Operand(..), + InstrOperandSize(..), + Instruction(..), + ShowStyle(..), + -- * Functions + disassembleBlock, + disassembleList, + disassembleArray, + showIntel, + showAtt + ) where + +import Text.Disassembler.X86Disassembler diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8c5a3bd --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: all clean install reinstall uninstall doc + +all: + runhaskell Setup.hs configure --prefix=$(HOME)/ + runhaskell Setup.hs build + +clean: + runhaskell Setup.hs clean + + +install: + runhaskell Setup.hs install --user + +reinstall: + runhaskell Setup.hs clean + runhaskell Setup.hs configure --prefix=$(HOME)/ + runhaskell Setup.hs build + runhaskell Setup.hs install --user + +uninstall: + runhaskell Setup.hs unregister --user + +doc: + runhaskell Setup.hs haddock diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..6cf860c --- /dev/null +++ b/NEWS @@ -0,0 +1,93 @@ + -*-outline-*- +* Harpy NEWS + +** New in version 0.4.2 + +*** package structure + +- The disassembler is now in a separate package, and is re-exported for + compatibility by Harpy. This allows us to give the more liberal BSD licence + to the disassembler. + +*** New instructions + +- The "mov", "jcc" (jump on condition code), and "cmp" instructions support + "Ptr a" as operand + +- Henning Thielemann provided some further floating point and SSE + instructions. + +- The loop instruction supports labels now. + +*** Enhancements + +- The disassembly of Harpy's internal code buffers includes all labels + now, even when multiple labels are defined for the same location. + +** New in version 0.4.1 + +*** New Instances + +- Many of Harpy's types are now instances of Eq. + +*** New instructions + +- Added support for the prefetching instructions PREFETCH0, PREFETCH1, + PREFETCH2 and PREFETCHNTA. + +*** Bug fixes + +- Harpy.X86Disassembler.disassembleBloc was too strict and caused + stack overflows for large inputs. This was fixed. + +- Disassembler: The instruction prefix list was not cleared when + beginning to parse a new instruction. This caused incorrect + disassembly of SSE instructions. + +- Disassembler: A bug has been fixed in the parsing routine for the + addressing mode "scaled index + 32 bit offset" without base + register. + +** New in version 0.4 + +- New convenience top-level module "Harpy", which re-exports + Harpy.CodeGenMonad, Harpy.Call and Harpy.X86Assembler + +- It is now possible to override Harpy's automatic code buffer + management. The new field 'customCodeBuffer' in the type + 'CodeGenConfig' can be set to 'Just (buf, size)', where 'buf' is a + pointer to a memory region of 'size' bytes. Harpy will then use the + supplied code buffer and will not perform any automatic code buffer + allocation on overflow. Overflow checking is still performed and + will result in an exception in the CodeGen monad. + +- When using the high-level assembler in X86Assembler, the code buffer + is automatically protected from overflow. + +- Floating point operations added to X86Assembler (only for double + operands yet). + +- Preliminary support for SSE instructions. Currently, only the + packed and scalar floating-point arithmetic operations are supported + (both in the low-level module Harpy.X86CodeGen and as methods in + Harpy.X86Assembler) + +- Code buffer default size has been increased from 128 to 4096 bytes. + +- The CodeGenMonad fails when a label is defined twice. + +- It is now possible to associate names with labels, using the new + operation newNamedLabel. The given names will show up in the + disassembly, which makes debugging of generated code much easier. + +- The doc directory contains a second, slightly larger tutorial now. + +- The examples/evaluator directory contains a small example + interpreter for arithmetic expressions, which translates expressions + entered at the keayboard to machine code on the fly. This is the + demo program we presented at the Haskell Workshop 2007. + +** New in version 0.2 + +- Everything is new! This is the first released version. + diff --git a/README b/README new file mode 100644 index 0000000..5d276a4 --- /dev/null +++ b/README @@ -0,0 +1,65 @@ + -*-outline-*- +* README file for the Harpy Haskell Run-time Code Generator + +Codename: Harpy - Haskell Assembler at Run-time produces Y... + Harpy [myth.] f: die Harpyie + http://en.wikipedia.org/wiki/Harpy + +** Introduction + +Harpy is a library for run-time code generation in Haskell programs. + +Harpy requires several Haskell extensions and GHC-specific features +(the Haskell FFI, Template Haskell, multi-parameter type classes and +monad transformers). + +** Features + +The following modules are included in this package: + +Harpy.CodeGenMonad: This module defines the code generator monad, + which is a combined state/reader/exception monad. It contains + all the necessary details for allocating and managing code buffers. + +Harpy.X86CodeGen: This module contains all the functions for generating + native x86 machine code. The functions are very simple, and it is + necessary to specify all addressing modes etc. when emitting an + instruction. + +Harpy.X86Assembler: A type class based layer on top of X86CodeGen + which determines the addressing modes from the types of the + operands. + +Harpy.X86CGCombinators: Code generation combinators for conditionals, + loops, function entry/exit code etc. + +Harpy.X86Disassembler: A disassembler for x86 machine code. + +Harpy.Call: Exports functions for invoking the generated code. + +** Notes about the implementation + +*** X86CodeGen.lhs + +The file X86CodeGen.lhs is based on a header file called x86-codegen.h +from the Mono distribution, which defines macros for emitting x86 +machine code directly into a memory buffer. The Haskell module is a +nearly one-to-one mapping from the original macros to Haskell +functions. The main differences are: + +- Instead of emitting the data directly into a buffer, it uses the + CodeGen monad from file CodeGenMonad.lhs. + +- The functions are strongly typed. + +Several things should be kept in mind when using this file: + +- Buffer overflow checks have to be done manually with checkBufferSize or + ensureBufferSize + +- MMX, SSE, SSE2 and SSE3 instructions and registers are not supported. + +- 64-bit mode is not supported. + +- The disassembler supports (in principle) 64-bit mode and SSE + instructions, but this has not been tested. diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..a18d22c --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,18 @@ +all: larger-tutorial.pdf + +larger-tutorial.pdf: larger-tutorial.tex + +larger-tutorial.tex: larger-tutorial.lhs + lhs2TeX $< > $@ + +%.pdf: %.tex + pdflatex $< + pdflatex $< + +clean: + rm -f larger-tutorial.aux larger-tutorial.toc\ + larger-tutorial.tex larger-tutorial.log larger-tutorial.out\ + larger-tutorial.ptb + +really-clean: clean + rm -f larger-tutorial.pdf diff --git a/doc/larger-tutorial.lhs b/doc/larger-tutorial.lhs new file mode 100644 index 0000000..1366af3 --- /dev/null +++ b/doc/larger-tutorial.lhs @@ -0,0 +1,312 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage[margin=2.5cm]{geometry} +\usepackage{hyperref} + +%include polycode.fmt +%format alpha = "\alpha" + + +\title{\textbf{Slightly Larger Harpy Tutorial}} +\author{Martin Grabmüller \and Dirk Kleeblatt} + +\begin{document} +\maketitle +\begin{abstract}\noindent +This tutorial is an introduction to some of the more advanced features +of Harpy. In the course of the tutorial, we will build a small +run-time compiler for a call-by-value lambda-calculus. +This document is written as a literate Haskell program, so you can +compile and run it without any modifications. +\end{abstract} + +\section{Introduction} + +In this tutorial, we develop a small run-time compiler for a simple +call-by-value lambda calculus extended with natural number constants. + +Before reading, you should have read the Harpy tutorial, which +introduces the most basic concepts. We also recommend to have a +running \verb|ghci| session running for loading the literate Haskell +script of this tutorial and to try it out. Maybe you want to have the +Harpy API documentation available, too. + +\section{The Code} + +To make use of Harpy and (a subset of) the x86 assembler instructions, we need +to import some modules. + +\begin{code} +import Harpy.CodeGenMonad +import Harpy.X86Assembler +import Harpy.X86Disassembler +import Foreign +import Control.Monad +import Control.Monad.Trans +import Data.List +\end{code} + +The following module system hackery is necessary, because the +|Harpy.X86Assembler| module exports a method called +|div|, which clashes with the |div| function +exported by the Haskell Prelude. The prelude |div| will be +hidden, but is still available as a qualified name. + +\begin{code} +import Prelude hiding (div) +import qualified Prelude +\end{code} + +\subsection{Data Types} + +In the following, we define several data types for representing lambda +calculus terms + +A |Name| represents a variable name. In a real +implementation, it would probably be more complicated data type for +handling qualified or compiler-generated names. For now, a string +will suffice. + +\begin{code} +type Name = String +\end{code} + +In our implementation, a variable may refer to (a) a global variable, +which is represented by its address, (b) a parameter, which is +represented by the number of enclosing lambda expression, or (c) a +free variable, which is represented by its index into the current code +closure. + +\begin{code} +data VarLoc = Global Word32 + | Param Int + | Free Int + deriving (Show) +\end{code} + +A compile-time environment represents a mapping from variable names to +variable locations. + +\begin{code} +data Env = Env [(Name, VarLoc)] +\end{code} + +An expression is represented by the following data type and may be a +variable, an immediate value (integer constant), a lambda abstraction +or an application expression. + +\begin{code} +data Exp = Var Name + | Imm Int + | Abs Name Exp + | App Exp Exp +\end{code} + +The |State| type represents the state of a running program. +It consists of a pointer to the next available word of heap memory, +and a pointer to the end of the heap. These two values are necessary +for dynamically allocating memory and for performing heap-overflow +checks. + +\begin{code} +data State = State { heap :: Ptr Word32, + heapEnd :: Ptr Word32} +\end{code} + +The following test expressions are constructed using the constructors of +type |Exp| and are to be evaluated by the main program. + +\begin{code} +testExp0 = App (Abs "x" (Var "x")) (Imm 12) +testExp1 = App (App (Abs "x" (Abs "y" (Var "x"))) (Imm 12)) (Imm 23) +\end{code} + +\subsection{Main Program} + +Before presenting the compiler, we will have a look at how it is used. +The entry point to the dynamic compiler is the function +|interpret|, which takes an expression and returns the value +calculated by the expression. The main program simply prints the +result. + +\begin{code} +$(callDecl "callFunc" [t|Word32|]) +\end{code} + +\begin{code} +main :: IO () +main = do res <- interpret testExp1 + putStrLn $ "Result: " ++ show res +\end{code} + +The |interpret| function allocates 16 kbytes of heap and +compiles the expression. The |State| of the compiler is +passed to the |runCodeGen| function as a user state. + +\begin{code} +interpret :: Exp -> IO Word32 +interpret exp = + do let heapSize = 1024 * 16 + heap <- mallocBytes heapSize + (_, Right res) <- runCodeGen (compileTop exp) (Env []) + (State heap (heap `plusPtr` + (heapSize `Prelude.div` 4))) + return res +\end{code} + +\subsection{Compilation} + +The compilation starts in the function |compileTop|, which emits code +for creating a stack frame, saving all general-purpose registers +(except \verb|eax|, which will contain the result of the execution), +and finally compiles the expression. Afterwards, all registers are +restored and the function is called. In addition we call the +disassembler on the generated code and print it out. This is a useful +debuggin aid when generating assembler code. + +\begin{code} +compileTop :: Exp -> CodeGen Env State Word32 +compileTop exp = + do st <- getState + push ebp + mov ebp esp + push ebx + push ecx + push edi + push esi + mov ecx ((fromIntegral (ptrToWordPtr (heap st))) :: Word32) + compile exp + pop esi + pop edi + pop ecx + pop ebx + mov esp ebp + pop ebp + ret + y <- callFunc + dis <- disassemble + liftIO $ mapM_ (putStrLn . showIntel) dis + return y + +\end{code} + +\subsubsection{Handling Variables} + +The |findVar| function looks up a variable in the +environment and returns its binding. + +\begin{code} +findVar s = + do Env e <- getEnv + case lookup s e of + Just vl -> return vl + Nothing -> error ("unbound variable: " ++ s) +\end{code} + +For the implementation of closures, we need to calculate free +variables of expressions, so that we know what to store into closures +and how to access free variables from the body of a lambda expression. + +\begin{code} +freeVariables (Var s) = return [s] +freeVariables (Imm _) = return [] +freeVariables (Abs x b) = liftM (delete x) (freeVariables b) +freeVariables (App e1 e2) = liftM2 union (freeVariables e1) (freeVariables e2) +\end{code} + +\subsubsection{Heap Allocation} + +Closures are the only dynamically allocated structures in our little +compiler. They are allocated from a contiguous block of malloc'ed +memory, which is passed in the code generator monad's state. The +following function generates code for allocating $w$ words of memory +in the heap, and returning a pointer to the memory in register +\verb|eax|. On heap overflow, a breakpoint instruction is executed. + +\begin{code} +emitAlloc w = + do mov eax ecx + st <- getState + cmp ecx (fromIntegral (ptrToWordPtr (heapEnd st)) :: Word32) + next <- newLabel + jl next + breakpoint + defineLabel next + add ecx ((4 * w) :: Word32) +\end{code} + +\subsubsection{The Compilation Proper} + +Finally, the |compile| function compiles an expression. +Constants are simply loaded into the result register, values of +variables are retrieved from their respective addresses (global +variables from absolute addresses, parameters relative to the stack +base pointer, and free variables relative to the closure pointer. + +\begin{code} +compile :: Exp -> CodeGen Env State () +compile (Imm i) = + do mov eax (fromIntegral i :: Word32) +compile (Var s) = + do c <- findVar s + case c of + Global addr -> mov eax (Addr addr) + Param ofs -> mov eax (Disp (fromIntegral ofs), ebp) + Free ofs -> mov eax (Disp (fromIntegral ofs), esi) +\end{code} + +Lambda expressions are more complicated. We first need to calculate +the set of free variables of the body expression. Then the body of +the expression is compiled (with a jump around its code, so that it is +not actually executed at this point). Then a closure record is +allocated on the heap, a code pointer to the body is stored in the +first word, and the values of all free variables of the body are +calculated and moved into the remaining fields of the closure. + +The result is a pointer to the new closure, returned in \verb|eax|, as +usual. + +\begin{code} +compile exp@(Abs x body) = + do fv <- freeVariables exp + let frees = zip fv (map Free [4,8..]) + next <- newLabel + jmp next + f <- setLabel + push ebp + mov ebp esp + mov esi (Disp 8, ebp) + withEnv (Env ((x, Param 12) : frees)) (compile body) + mov esp ebp + pop ebp + ret + defineLabel next + emitAlloc (fromIntegral (length frees + 1)) + mov edi eax + mov (Disp 0, edi) f + if length frees > 0 + then do push eax + mapM_ (\ (x, Free ofs) -> + do compile (Var x) + mov (Disp (fromIntegral ofs), edi) eax) + frees + pop eax + else return () +compile (App e1 e2) = + do compile e2 + push eax + compile e1 + push eax + call (Disp 0, eax) + add esp (8 :: Word32) +\end{code} + +\section{Conclusion} + +This completes our little just-in-time compiled lambda calculus +evaluator. We hope that this tutorial makes clear many of the fine +points in using the library. + +Happy Harpy Hacking in Haskell! + +\end{document} diff --git a/doc/tutorial.lhs b/doc/tutorial.lhs new file mode 100644 index 0000000..7540abc --- /dev/null +++ b/doc/tutorial.lhs @@ -0,0 +1,199 @@ +\documentclass[a4paper]{article} + +\usepackage[latin1]{inputenc} + +\usepackage{listings} + +\lstnewenvironment{code}{}{} +\lstset{ + basicstyle=\ttfamily, + keywordstyle=\normalfont\bfseries, + identifierstyle=\bfseries, + commentstyle=\rmfamily, + texcl=true, + language=Haskell, + flexiblecolumns=false, + basewidth={0.5em,0.45em}, + extendedchars=true, + frame=leftline, + numbers=left, + firstnumber=last, + literate={+}{{$+$}}1 {/}{{$/$}}1 {*}{{$*$}}1 {=}{{$=$}}1 + {>}{{$>$}}1 {<}{{$<$}}1 + {->}{{$\rightarrow$}}2 {>=}{{$\geq$}}2 {<-}{{$\leftarrow$}}2 + {<=}{{$\leq$}}2 {=>}{{$\Rightarrow$}}2 {\ .}{{ $\circ$}}2, + numberstyle=\tiny +} + +\title{Harpy Tutorial} +\author{Martin Grabmüller \and Dirk Kleeblatt} + +\begin{document} +\maketitle +\abstract{ +We present some of the features of +Harpy, an in-line assembler for Haskell. This little tutorial shows how to +write assembler programs without making one's hands dirty, staying in the +beautiful pure functional world of Haskell. During this tutorial, we develop +step by step an assembler implementation of the factorial function, and show +how assembler code can be called from ordinary Haskell code. + +This document is written as a literate Haskell program, so you can compile and run it +without any modifications. +} + +\section{Introduction} + +To make use of Harpy and (a subset of) the x86 assembler instructions, we need +to import some modules. + +\begin{code} +import Harpy.CodeGenMonad +import Harpy.X86Assembler +import Foreign +import Control.Monad.Trans +\end{code} + +The module \lstinline-Harpy.CodeGenMonad- defines the polymorphic type +\lstinline-CodeGen e s-, which is an instance of the \lstinline-Monad- +class. The type parameters \lstinline-e- and \lstinline-s- can be instantiated +to the type of an user's environment and state, respectively. These behave +like the environments and states known from the \lstinline-Reader- and +\lstinline-State- monads. Besides this monadic type, this module defines some +functions to make use of code labels, and provides an interface to a +disassembler. + +The module \lstinline-Harpy.X86Assembler- provides a subset of the x86 +assembler instructions, e.~g. \verb-mov- for moving memory words around. These +instructions are implemented as class methods, to allow different addressing +modes without hassle. + +We additionally import the module \lstinline-Foreign-, since we need some low +level types to exchange parameters and results with our assembler code, and +\lstinline-Control.Monad.MonadTrans- to have some instances available. + +\section{A fast factorial function} + +Now we are ready to define the factorial function in assembler code. + +\lstset{firstnumber=4} +\begin{code} +fac :: CodeGen e s () +fac = do loopTest <- newLabel + loopStart <- newLabel + ensureBufferSize 160 + push ecx + mov ecx (Disp 8, esp) + mov eax (1 :: Word32) + jmp loopTest + loopStart @@ mul ecx + sub ecx (1 :: Word32) + loopTest @@ cmp ecx (0 :: Word32) + jne loopStart + pop ecx + ret +\end{code} + +We first create two labels, \lstinline-loopTest- and \lstinline-loopStart-, to +mark the test and the beginning of a loop. In lines 5 and 6, these labels are +merely announced to Harpy, they are not (yet) defined to sit at a specific +code position. + +Line 8 saves the \lstinline-ecx- rigister on the system stack, because we will +use it as a loop counter, and want to restore it before returning to Haskell +functions. + +Line 9 shows an indirect adressing with displacement. Note, that all Harpy +functions use Intel assembler style, i.~e. the first operand is the +destination and the second one the source of each instruction. So this line +moves the memory contents at address \lstinline-esp+8- into +\lstinline-ecx-. Since we will make a C call into our assembler code, this +accesses the first parameter on the stack. When returning to the Haskell world +via \lstinline-ret-, we leave our result in \lstinline-eax-, again adhering to +the C calling convention. + +The rest of \lstinline-fac- just accumulates the factorial in \lstinline-eax- +while counting down \lstinline-ecx-. Lines 12 and 14 show how our labels +\lstinline-loopStart- and \lstinline-loopTest- are placed at specific code +positions. + +The function \lstinline-fac- is not really our wanted factorial +function. Instead it is a monadic command that, when executed, writes +assembler code into a buffer. To ensure, that this buffer is always large +enough to hold the generated instruction, you have to sprinkle your code with +calls to \lstinline-ensureBufferSize-. In line 7 we make sure that 160 bytes +are available, which is enough for our 10 instructions. As a rule of thumb, no +instruction can be larger than 16 bytes, so the number of assembler +instructions times 16 is a safe upper bound. + +The next section shows how to prepare a call into such a buffer. + +\section{Preparing a call} + +The module \lstinline-Harpy.Call- defines some functions to call functions +written in assembler with various argument and result types. But since it is +possible to use all types suitable for FFI calls as argument or result, sooner +or later you will need some combination not yet implemented. So here we show +how to define your own calling stub. + +\lstset{firstnumber=18} +\begin{code} +$(callDecl "callFac" [t|Word32 -> Word32|]) +\end{code} + +The Template Haskell function \lstinline-callDecl- is used to declare a +function \lstinline-callFac- which will call our assembler fragment. We want +to pass a parameter of type \lstinline-Word32-, and expect a result of the +same type, that's why we give \lstinline+Word32 -> Word32+ as argument to +\lstinline-callDecl-. If you wonder about the fancy \lstinline-$- and +\lstinline-[t| |]-, either look them up in the Template Haskell +documentation, or just ignore them. However, to make this line compile, you +have to switch on Template Haskell, which is done for the Glasgow Haskell +compiler by the command line flag \verb+-fth+. + +\section{Calling \lstinline-fac-} + +Now we have all we need to call into our factorial function. + +\lstset{firstnumber=19} +\begin{code} +runFac :: CodeGen e s () +runFac = do fac + x <- liftIO readLn + y <- callFac x + liftIO (putStrLn (show y)) +\end{code} + +We first call \lstinline-fac- to write our assembler code into the internal +buffer. Since the \lstinline-CodeGen- monad ist an instance of +\lstinline-MonadIO-, we can use \lstinline-liftIO- to use all commands we wish +from the \lstinline-IO- monad. Here, we use this to read the argument to the +factorial function from the keyboard, and to write the result back to the +screen. Line 21 calls into the internal code buffer with our assembler +instructions using the stub declared in the last section. + +\section{How to use it} + +Up to now, all our functions live in the \lstinline-CodeGen- monad. To make +use of them, we have to \emph{unlift} them into the \lstinline-IO- monad. This +is done by \lstinline-runCodeGen-. + +\lstset{firstnumber=24} +\begin{code} +main :: IO () +main = do + (finalState, result) <- runCodeGen runFac () () + case result of + Right () -> return () + Left err -> putStrLn (show err) +\end{code} + +The second and third arguments to \lstinline-runCodeGen- are the initial +environment and state. Since we did not use them, their type is polymorphic +and we can use \lstinline-()- as initial values. The result is a pair +consisting of the final state, and a result value. A value constructed with +the constructor \lstinline-Right- indicates a successful run, while +\lstinline-Left- values indicate runtime errors. These might occur for +instance because of infeasible addressing modes. + + \end{document} diff --git a/examples/evaluator/ArithParser.hs b/examples/evaluator/ArithParser.hs new file mode 100644 index 0000000..798a03b --- /dev/null +++ b/examples/evaluator/ArithParser.hs @@ -0,0 +1,73 @@ +module ArithParser where + +import Control.Monad + +import ArithTypes + +import Foreign + +import Text.ParserCombinators.Parsec +import qualified Text.ParserCombinators.Parsec.Token as P +import Text.ParserCombinators.Parsec.Language +import Text.ParserCombinators.Parsec.Expr + +lexer :: P.TokenParser () +lexer = P.makeTokenParser + (haskellStyle + { reservedOpNames = ["*","/","+","-"] + }) + +statement :: Parser Stmt +statement = do s <- statement' + eof + return s + +statement' :: Parser Stmt +statement' = try((do [i] <- identifier + if i < 'a' || i > 'z' + then fail "character a-z expected" + else return () + symbol ":=" + e <- expr + return $ Assign i e) "assignment") + <|> liftM Cmd cmd + <|> liftM Print expr + +cmd :: Parser Cmd +cmd = try (do symbol ":help" + return Help) + <|> try (do symbol ":verbose" + return Verbose) + <|> (do symbol ":quit" + return Quit) + +expr :: Parser Exp +expr = buildExpressionParser table factor + "expression" + +table = [[op "*" Mul AssocLeft, op "/" Div AssocLeft] + ,[op "+" Add AssocLeft, op "-" Sub AssocLeft] + ] + where + op s f assoc + = Infix (do{ reservedOp s; return f} "operator") assoc + +factor = parens expr + <|> liftM (Lit . fromInteger) natural + <|> (do [i] <- identifier + if i < 'a' || i > 'z' + then fail "character a-z expected" + else return () + return $ Var i) + "simple expression" + +whiteSpace= P.whiteSpace lexer +lexeme = P.lexeme lexer +symbol = P.symbol lexer +natural = P.natural lexer +parens = P.parens lexer +semi = P.semi lexer +identifier= P.identifier lexer +reserved = P.reserved lexer +reservedOp= P.reservedOp lexer + diff --git a/examples/evaluator/ArithTypes.hs b/examples/evaluator/ArithTypes.hs new file mode 100644 index 0000000..112ae6a --- /dev/null +++ b/examples/evaluator/ArithTypes.hs @@ -0,0 +1,22 @@ +module ArithTypes where + +import Foreign + +data Stmt = Assign Char Exp + | Print Exp + | Cmd Cmd + deriving (Show) + +data Cmd = Help + | Quit + | Verbose + deriving (Show) + +data Exp = Add Exp Exp + | Sub Exp Exp + | Mul Exp Exp + | Div Exp Exp + | Lit Int32 + | Var Char + deriving (Show) + diff --git a/examples/evaluator/Evaluator.hs b/examples/evaluator/Evaluator.hs new file mode 100644 index 0000000..a9cdd3d --- /dev/null +++ b/examples/evaluator/Evaluator.hs @@ -0,0 +1,118 @@ +module Main(main) where + +import ArithTypes +import ArithParser + +import Harpy +import Harpy.X86Disassembler + +import Foreign + +import Control.Monad + +import System.Console.Readline + +import Text.ParserCombinators.Parsec + +$(callDecl "callAsWord32" [t|Word32|]) + +main :: IO () +main = do putStrLn "\n\n\n\nHarpy Interpreter" + putStrLn "(type :help to see a help message)" + allocaArray 26 (\ p -> mapM_ (\ i -> poke (advancePtr p i) 0) [0..25] >> repl p False) + +repl :: Ptr Int32 -> Bool -> IO () +repl env verbose = + do s <- readline "@ " + case s of + Nothing -> return () + Just s' -> do addHistory s' + interpret env verbose s' + +interpret :: Ptr Int32 -> Bool -> String -> IO () +interpret env verbose s = + do let e = parse statement "" s + case e of + Left err -> do putStrLn (show err) + repl env verbose + Right stmt -> run env verbose stmt + +run :: Ptr Int32 -> Bool -> Stmt -> IO () +run env verbose (Cmd Help) = + do putStrLn "Enter an arithmetic expression to evaluate it" + putStrLn " e.g. 5 / 2" + putStrLn "Enter an assignment to set a variable" + putStrLn " e.g. a := 4 * 2 - (6 + 1)" + putStrLn "Enter :help to see this message again" + putStrLn "Enter :quit to exit" + putStrLn "Enter :verbose to toggle disassembly output" + repl env verbose + +run env _ (Cmd Quit) = return () + +run env verbose (Cmd Verbose) = repl env (Prelude.not verbose) + +run env verbose stmt@(Assign var exp) = + do (i, ins) <- eval' env stmt + when verbose (mapM_ (putStrLn . showIntel) ins) + repl env verbose + +run env verbose stmt@(Print exp) = + do (i, ins) <- eval' env stmt + putStrLn (show i) + when verbose (mapM_ (putStrLn . showIntel) ins) + repl env verbose + +-- Function for compiling and executing statements. +eval' :: Ptr Int32 -> Stmt -> IO (Int32, [Instruction]) +eval' env e = do (_, Right v) <- runCodeGen (compileAndRun e) env () + return v + +compileAndRun :: Stmt -> CodeGen (Ptr Int32) s (Int32, [Instruction]) +compileAndRun (Assign c exp) = + do entryCode + compileExp exp + env <- getEnv + mov (variableAddress env c) eax + exitCode + d <- disassemble + callAsVoid + return (0, d) +compileAndRun (Print exp) = + do entryCode + compileExp exp + exitCode + d <- disassemble + r <- callAsWord32 + return (fromIntegral r, d) + +compileExp :: Exp -> CodeGen (Ptr Int32) s () +compileExp (Add e1 e2) = compileBinOp e1 e2 (add eax (Ind esp)) +compileExp (Sub e1 e2) = compileBinOp e1 e2 (sub eax (Ind esp)) +compileExp (Mul e1 e2) = compileBinOp e1 e2 (imul InPlace eax (Ind esp)) +compileExp (Div e1 e2) = compileBinOp e1 e2 (cdq >> idiv (Ind esp)) +compileExp (Lit i) = mov eax ((fromIntegral i) :: Word32) +compileExp (Var c) = do env <- getEnv + mov eax (variableAddress env c) + +compileBinOp :: Exp -> Exp -> CodeGen (Ptr Int32) s a -> CodeGen (Ptr Int32) s () +compileBinOp e1 e2 op = do compileExp e2 + push eax + compileExp e1 + op + add esp (4 :: Word32) + +entryCode :: CodeGen e s () +entryCode = do push ebp + mov ebp esp + +exitCode :: CodeGen e s () +exitCode = do mov esp ebp + pop ebp + ret + +variableAddress :: Ptr Int32 -> Char -> Addr +variableAddress env c = + let ofs = fromEnum c - fromEnum 'a' + env' = advancePtr env ofs + in Addr (fromIntegral (ptrToWordPtr env')) diff --git a/harpy.cabal b/harpy.cabal new file mode 100644 index 0000000..5c253c6 --- /dev/null +++ b/harpy.cabal @@ -0,0 +1,67 @@ +Cabal-version: >=1.2 +Build-type: Simple +Name: harpy +Version: 0.4.3.0 +License: GPL +License-file: COPYING +Author: Dirk Kleeblatt + Martin Grabmueller +Maintainer: klee@cs.tu-berlin.de, martin.grabmueller@eleven.de +Homepage: http://uebb.cs.tu-berlin.de/harpy/ +Category: Code Generation +Synopsis: Runtime code generation for x86 machine code +Description: The package contains the following components: + . + * An x86 assembler. We provide both low-level code generation in + module "Harpy.X86CodeGen" as well as a (slightly) higher-level + implementation in module "Harpy.X86Assembler", which figures out + addressing modes based on an instruction's operand types. + . + * An x86 disassembler which knows most of the opcodes available on + modern x86 processors and can display its output both in the style + used in Intel documents an in AT&T style, like the GNU tools. The + disassembler can be found in module "Harpy.X86Disassembler". The + disassembler is re-exported from the disassembler package for + compatibility with earlier Harpy releases. + . + * Some abstractions over the abovementioned code generation modules, + such as automatic label management and code generation + combinators (for if-then-else statements, while-loops, functions) + (module "Harpy.X86CGCombinators"). + . + * All the above modules use the code generation monad defined in module + "Harpy.CodeGenMonad". + . + * The Darcs repo and two tutorials on using Harpy can be found at + Harpy's homepage: +Stability: Experimental + +Extra-source-files: + NEWS README Makefile + doc/Makefile doc/tutorial.lhs doc/larger-tutorial.lhs + examples/evaluator/ArithTypes.hs examples/evaluator/ArithParser.hs + examples/evaluator/Evaluator.hs + +Library + Build-depends: + base >= 4 && < 5, + parsec >= 1 && < 3, + mtl >= 1 && < 2, + template-haskell >= 2 && < 3, + pretty >= 1 && < 2, + containers >= 0.3 && < 1, + array >= 0.3 && < 1, + disassembler >= 0.1.0.1 + Exposed-Modules: + Harpy, + Harpy.X86CodeGen, + Harpy.X86Assembler, + Harpy.CodeGenMonad, + Harpy.Call, + Harpy.X86Disassembler, + Harpy.X86CGCombinators + Extensions: + ForeignFunctionInterface, MultiParamTypeClasses, + TemplateHaskell, CPP, FlexibleContexts, FlexibleInstances, + RankNTypes + -- 2.25.1