mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-23 13:23:47 +00:00
083d376e6598628362ee91c2da170febd83590f4
32 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cb1da20600 |
Stop ancestor imports "shadowing" unused local imports.
compiler/make_hlds_passes.m:
We used to add all modules imported by an ancestor of the current module
to the set of used modules. Once upon a time, this was meant to stop
the compiler generating misleading warnings about imports being unused
when the import wasn't even done by the current module. However, since
we introduced structured representations of import- and use_module
declarations and taught unused_imports.m to use them, that has not been
an issue. However, a bad side-effect remained, which was that if
a module A imported a module B but did not use it, or it imported
module B in its interface but did not use in its interface, then
any warning we could generate about that import being unused was
suppressed by any import of module B in any of module A's ancestors.
(The "shadowing" mentioned above.)
Fix the problem by adding modules imported by ancestors of the
current module NOT to the set of used modules, but to a new field
in the module_info.
compiler/hlds_module.m:
Add this new field. As it happens, it is not needed right now,
but it may be needed later.
Update some documentation.
Note an only-tangentially-related problem.
compiler/unused_imports.m:
Fix a bug that was hiding behind the shadowing, which was that whether
the text of the warning message we generated for an unused local import-
or use_module declaration could be affected by the presence of an
import- or use_module declaration in an ancestor module.
Improve debugging infrastructure.
Make a predicate name more descriptive.
NEWS:
Announce the bugfix.
compiler/add_pragma_tabling.m:
compiler/add_solver.m:
compiler/add_type.m:
compiler/parse_string_format.m:
compiler/recompilation.usage.m:
compiler/recompilation.used_file.m:
library/io.call_system.m:
library/io.text_read.m:
library/random.sfc32.m:
library/random.sfc64.m:
library/random.system_rng.m:
library/string.parse_runtime.m:
library/string.parse_util.m:
library/string.to_string.m:
library/thread.closeable_channel.m:
mdbcomp/feedback.automatic_parallelism.m:
Delete imports that the fixed compiler now generates unused import
warnings for.
|
||
|
|
ee8589d111 | Harmonize the two main backends' packages. | ||
|
|
d145d77970 |
Split up unify_gen.m.
compiler/unify_gen_construct.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_gen_test.m:
compiler/unify_gen_util.m:
Carve these four modules out of unify_gen.m. The first two handle
the construction and deconstruction of terms, the third tests whether
a variable is bound to a given cons_id, and the fourth contains utility
types and predicates needed by more than one of the other modules.
compiler/unify_gen.m:
Remove the code moved to the modules above.
compiler/ll_backend.m:
compiler/notes/compiler_design.html:
Add and document the new modules.
compiler/Mercury.options:
Require the new modules to have consistency between the order of predicate
declarations and the order of predicate definitions.
compiler/code_gen.m:
compiler/mercury_compile_llds_back_end.m:
compiler/middle_rec.m:
compiler/proc_gen.m:
compiler/switch_gen.m:
Conform to the change above.
|
||
|
|
8ecd9b1f5f |
Carve closure_gen.m out of unify_gen.m.
compiler/closure_gen.m:
New module containing the part of unify_gen.m concerned with creating
closures.
compiler/code_info.m:
Move a utility predicate here from unify_gen.m, since it is needed
by both the code moved to closure_gen.m and the code that stays
in unify_gen.m.
compiler/unify_gen.m:
Remove the code moved to other modules.
compiler/ll_backend.m:
compiler/notes/compiler_design.html:
Add the new module.
|
||
|
|
cc9912faa8 |
Don't import anything in packages.
Packages are modules whose only job is to serve as a container for submodules. Modules like top_level.m, hlds.m, parse_tree.m and ll_backend.m are packages in this (informal) sense. Besides the include_module declarations for their submodules, most of the packages in the compiler used to import some modules, mostly other packages whose component modules their submodules may need. For example, ll_backend.m used to import parse_tree.m. This meant that modules in the ll_backend package did not have to import parse_tree.m before importing modules in the parse_tree package. However, this had a price. When we add a new module to the parse_tree package, parse_tree.int would change, and this would require the recompilation of ALL the modules in the ll_backend package, even the ones that did NOT import ANY of the modules in the parse_tree package. This happened even at one remove. Pretty much all modules in every one of the backend have to import one or more modules in the hlds package, and they therefore have import hlds.m. Since hlds.m imported transform_hlds.m, any addition of a new middle pass to the transform_hlds package required the recompilation of all backend modules, even in the usual case of the two having nothing to do with each other. This diff removes all import_module declarations from the packages, and replaces them with import_module declarations in the modules that need them. This includes only a SUBSET of their child modules and of the non-child modules that import them. |
||
|
|
4d2788ff9e |
Separate out the location-dependent parts of the code_info.
The code_info type was originally designed to be a single data structure
that holds all of the state of the LLDS code generator. It HAD to be a single
data structure then, because the DCGs we used to pass state around only
supported passing around ONE piece of state. Nevertheless, it contained
three separate kinds of information:
1 static information, which never changed during the lifetime of a code_info
structure (such as the pred and proc id of the procedure being compiled),
2 persistent information, whose updates were never undone (such as the maximum
number of temporaries that were ever needed at any one time), and
3 location dependent information, such as "which variables are stored where",
whose updates *can* be undone when the code generator jumps back to
a previously visited point in the code, e.g. to start generating code
for the next disjunct in a disjunction.
Originally, these three kinds of fields were all jumbled up together, but
about ten years ago, I grouped all the fields of the same kind together,
into substructures of code_info named code_info_static, code_info_persistent
and code_info_loc_dep respectively. This improved matters, but some problems
remained, the most important of which is that the code_info always contained
the location dependent information, even when it wasn't meaningful, and there
was no way of indicating this fact. (After initialization, the other two parts
are always meaningful.)
This diff separates out the location dependent part of the code_info
into a new type, code_loc_dep, that can be passed around independently
of the code_info, which now contains only the first two kinds of information
above. In places where the location-dependent information is not meaningful,
you don't need to have a current code_loc_dep.
This separation also makes it easier to see what updates to the code generator
state change only the persistent part (the updated code_info type), only
the location-dependent part (the new code_loc_dep type), or both.
In the process of making this change, I found several places where the
location-dependent part of the code_info (now the code_loc_dep) was being
updated, only for those updates to be thrown away, unread, a short time later.
This happened at the ends of branches in e.g. switches, with the updated
code_loc_deps being thrown away when code generation started working on
the next branch.
compiler/code_loc_dep.m:
New module containing the location-dependent part of the LLDS code
generator state. Its contents are derived from those parts of the
old contents of code_info.m that deal with location-dependent state.
Many of the predicates moved here work on only on the code_loc_dep
structure, some others work on both the code_info and code_loc_dep
structure, and a few work only on the code_info. Predicates in the last
category are in code_loc_dep.m only if they are either (a) used only
in this module, or (b) used only with other predicates in this module.
compiler/ll_backend.m:
compiler/notes/compiler_design.html:
Mention the new module.
compiler/code_info.m:
Delete the code now in code_loc_dep.m.
Make the vartypes a field in the static part of the code_info, since it is
used quite often. (We used to look it up in the proc_info every time.)
Put the declarations and definitions of the access predicates in an order
that is consistent with the order of the fields they work on.
Give some fields and predicates more descriptive names.
compiler/call_gen.m:
compiler/code_gen.m:
compiler/commit_gen.m:
compiler/dense_switch.m:
compiler/disj_gen.m:
compiler/ite_gen.m:
compiler/ll_backend.m:
compiler/lookup_switch.m:
compiler/lookup_util.m:
compiler/middle_rec.m:
compiler/par_conj_gen.m:
compiler/pragma_c_gen.m:
compiler/proc_gen.m:
compiler/string_switch.m:
compiler/switch_case.m:
compiler/switch_gen.m:
compiler/tag_switch.m:
compiler/trace_gen.m:
compiler/unify_gen.m:
compiler/var_locn.m:
Conform to and take advantage of the changes above.
Often this required passing an in/out pair of code_loc_deps as well as
an in/out pair of code_infos, but in many cases, one or more of these
would not be needed.
Don't make changes to the code_loc_dep at the end of an arm of a branched
control structure if those updates are about be thrown away when we
start generating code for the next arm.
In several cases, switch to a strategy of taking a snapshot of the
code_loc_dep before entering a branched control structure as a whole,
and restoring that state at the start of each arm. We used to take
a snapshot at the start of each branch, and restore it at its end,
to be ready for the next branch. The former is easier to make
correctness arguments about, since the code_loc_dep in an arm
often has limited scope.
Make some minor unrelated improvements, such as eliminating the
unnecessary use of solutions/2, and reordering tests for slightly
better performance.
|
||
|
|
13b6f03f46 |
Module qualify end_module declarations.
compiler/*.m:
Module qualify the end_module declarations. In some cases, add them.
compiler/table_gen.m:
Remove an unused predicate, and inline another in the only place
where it is used.
compiler/add_pragma.m:
Give some predicates more meaningful names.
|
||
|
|
c3c4ec7772 |
Delete the LLDS->x86_64 asm backend.
No progress has been made on the LLDS->x86_64 backend since the initial work on it and it is now more have a maintenance headache then anything else. compiler/llds_to_x86_64.m: compiler/llds_to_x86_64_out.m: compiler/x86_64_instrs.m: compiler/x86_64_out.m: compiler/x86_64_regs.m: Delete these modules. compiler/globals.m: Delete the x86_64 target type. compiler/*.m: Conform to the above changes. |
||
|
|
2d0bfc0674 |
The algorithm that decides whether the order independent state update
Estimated hours taken: 120 Branches: main The algorithm that decides whether the order independent state update transformation is applicable in a given module needs access to the list of oisu pragmas in that module, and to information about the types of variables in the procedures named in those pragmas. This diff puts this information in Deep.procrep files, to make them available to the autoparallelization feedback program, to which that algorithm will later be added. Compilers that have this diff will generate Deep.procrep files in a new, slightly different format, but the deep profiler will be able to read Deep.procrep files not just in the new format, but in the old format as well. runtime/mercury_stack_layout.h: Add to module layout structures the fields holding the new information we want to put into Deep.procrep files. This means three things: - a bytecode array in module layout structures encoding the list of oisu pragmas in the module; - additions to the bytecode arrays in procedure layout structures mapping the procedure's variables to their types; and - a bytecode array containing the encoded versions of those types themselves in the module layout structure. This allows us to represent each type used in the module just once. Since there is now information in module layout structures that is needed only for deep profiling, as well as information that is needed only for debugging, the old arrangement that split a module's information between two structures, MR_ModuleLayout (debug specific info) and MR_ModuleCommonLayout (info used by both debugging and profiling), is no longer approriate. We could add a third structure containing profiling-specific info, but it is simpler to move all the info into just one structure, some of whose fields may not be used. This wastes only a few words of memory per module, but allows the runtime system to avoid unnecessary indirections. runtime/mercury_types.h: Remove the type synonym for the deleted type. runtime/mercury_grade.h: The change in mercury_stack_layout.h destroys binary compatibility with previous versions of Mercury for debug and deep profiling grades, so bump their grade-component-specific version numbers. runtime/mercury_deep_profiling.c: Write out the information in the new fields in module layout structures, if they are filled in. Since this changes the format of the Deep.procrep file, bump its version number. runtime/mercury_deep_profiling.h: runtime/mercury_stack_layout.c: Conform to the change to mercury_stack_layout.h. mdbcomp/program_representation.m: Add to module representations information about the oisu pragmas defined in that module, and the type table of the module. Optionally add to procedure representations a map mapping the variables of the procedure to their types. Rename the old var_table type to be the var_name_table type, since it contains just names. Make the var to type map separate, since it will be there only for selected procedures. Modify the predicates reading in module and procedure representations to allow them to read in the new representation, while still accepting the old one. Use the version number in the Deep.procrep file to decide which format to expect. mdbcomp/rtti_access.m: Add functions to encode the data representations that this module also decodes. Conform to the changes above. mdbcomp/feedback.automatic_parallelism.m: Conform the changes above. mdbcomp/prim_data.m: Fix layout. compiler/layout.m: Update the compiler's representation of layout structures to conform to the change to runtime/mercury_stack_layout.h. compiler/layout_out.m: Output the new parts of module layout structures. compiler/opt_debug.m: Allow the debugging of code referring to the new parts of module layout structures. compiler/llds_out_file.m: Conform to the move to a single module layout structure. compiler/prog_rep_tables.m: This new module provided mechanisms for building the string table and the type table components of module layouts. The string table part is old (it is moved here from stack_layout.m); the type table part is new. Putting this code in a module of its own allows us to remove a circular dependency between prog_rep.m and stack_layout.m; instead, both now just depend on prog_rep_tables.m. compiler/ll_backend.m: Add the new module. compiler/notes/compiler_design.html: Describe the new module. compiler/prog_rep.m: When generating the representation of a module for deep profiling, include the information needed by the order independent state update analysis: the list of oisu pragmas in the module, if any, and information about the types of variables in selected procedures. To avoid having these additions increasing the size of the bytecode representation too much, convert some fixed 32 bit numbers in the bytecode to use variable sized numbers, which will usually be 8 or 16 bits. Do not use predicates from bytecode_gen.m to encode numbers, since there is nothing keeping these in sync with the code that reads them in mdbcomp/program_representation.m. Instead, use new predicates in program_representation.m itself. compiler/stack_layout.m: Generate the new parts of module layouts. Remove the code moved to prog_rep_tables.m. compiler/continuation_info.m: compiler/proc_gen.m: Make some more information available to stack_layout.m. compiler/prog_data.m: Fix some formatting. compiler/introduce_parallelism.m: Conform to the renaming of the var_table type. compiler/follow_code.m: Fix the bug that used to cause the failure of the hard_coded/mode_check_clauses test case in deep profiling grades. deep_profiler/program_representation_utils.m: Output the new parts of module and procedure representations, to allow the correctness of this change to be tested. deep_profiler/mdprof_create_feedback.m: If we cannot read the Deep.procrep file, print a single error message and exit, instead of continuing with an analysis that will generate a whole bunch of error messages, one for each attempt to access a procedure's representation. deep_profiler/mdprof_procrep.m: Give this program an option that specifies what file it is to look at; do not hardwire in "Deep.procrep" in the current directory. deep_profiler/report.m: Add a report type that just prints the representation of a module. It returns the same information as mdprof_procrep, but from within the deep profiler, which can be more convenient. deep_profiler/create_report.m: deep_profiler/display_report.m: Respectively create and display the new report type. deep_profiler/query.m: Recognize a query asking for the new report type. deep_profiler/autopar_calc_overlap.m: deep_profiler/autopar_find_best_par.m: deep_profiler/autopar_reports.m: deep_profiler/autopar_search_callgraph.m: deep_profiler/autopar_search_goals.m: deep_profiler/autopar_types.m: deep_profiler/branch_and_bound.m: deep_profiler/coverage.m: deep_profiler/display.m: deep_profiler/html_format.m: deep_profiler/mdprof_test.m: deep_profiler/measurements.m: deep_profiler/query.m: deep_profiler/read_profile.m: deep_profiler/recursion_patterns.m: deep_profiler/top_procs.m: deep_profiler/top_procs.m: Conform to the changes above. Fix layout. tests/debugger/declarative/dependency.exp2: Add this file as a possible expected output. It contains the new field added to module representations. |
||
|
|
30aafc69a0 |
Split up three big compiler modules: llds_out.m, hlds_out.m (5000+ lines each)
Estimated hours taken: 12 Branches: main Split up three big compiler modules: llds_out.m, hlds_out.m (5000+ lines each) and deep_profiling.m (3000+ lines). Put the predicates in the resulting smaller modules into cohesive groups where possible. A few of the predicates in the original modules were unused; this diff deletes them. There are no algorithmic changes. compiler/llds_out_code_addr.m: New module containing the part of llds_out.m that outputs code addresses and labels. compiler/llds_out_data.m: New module containing the part of llds_out.m that outputs lvals, rvals and their components. compiler/llds_out_global.m: New module containing the part of llds_out.m that generates global static C data structures. compiler/llds_out_instr.m: New module containing the part of llds_out.m that outputs instructions compiler/llds_out_file.m: New module containing the top level part of llds_out.m, which coordinates the generation of a whole C source file. compiler/llds_out_util.m: New module containing the utility parts of llds_out.m. compiler/llds_out.m: Replace everything in this file with just the includes of the submodules that now have all its previous contents. compiler/hlds_llds.m: Move a predicate here from llds_out.m, since it is a utility predicate operating on a type defined here. compiler/rtti_out.m: Move a predicate here from llds_out.m, since it is a predicate generating output from a rtti type. compiler/hlds_out_mode.m: The part of hlds_out.m that deals with writing out insts and modes. compiler/hlds_out_goal.m: The part of hlds_out.m that deals with writing out goals. compiler/hlds_out_pred.m: The part of hlds_out.m that deals with writing out predicates and procedures. compiler/hlds_out_module.m: The part of hlds_out.m that deals with writing out module-wide tables. compiler/hlds_out_util.m: Parts of hlds_out.m that don't fit in anywhere else. compiler/hlds_out.m: Replace everything in this file with just the includes of the submodules that now have all its previous contents. compiler/simplify.m: compiler/hlds_goal.m: Move some insts from simplify.m to hlds_goal.m to allow hlds_out_goal.m to use them also. compiler/coverage_profiling.m: The part of deep_profiling.m that deals with coverage profiling. compiler/deep_profiling.m: Remove the code moved to coverage_profiling.m, and export the utility predicates needed by coverage_profiling.m. Remove the things moved to prog_data.m and hlds_goal.m. Put the predicates into a more logical order. compiler/hlds_goal.m: Move some predicates here from deep_profiling.m, since they belong here. compiler/prog_data.m: Move a type from deep_profiling.m here, since it belongs here. compiler/add_pragma.m: Add a predicate from llds_out.m that is used only here. compiler/*.m: Conform to the changes above. |
||
|
|
f60a0ab285 |
Add a mechanism that can help debug the compiler itself, specifically
Estimated hours taken: 2 Branches: main Add a mechanism that can help debug the compiler itself, specifically (but not only) the code generator. I used this mechanism a while ago to locate a hard-to-find bug, and it may be useful again in the future. compiler/hlds_desc.m: A new module whose job is to write out goals in a form that is suitable for use in progress messages from compiler passes (the predicates in hlds_out.m write out far too much for this). compiler/hlds.m: compiler/notes/compiler_design.html: Add the new module. compiler/options.m: Add a developer-only option that selects the predicate whose code generation should be traced. compiler/code_gen.m: compiler/code_info.m: compiler/ite_gen.m: Print progress messages if the compiler is compiled with the right compile-time trace flag and the new option says we should. compiler/opt_debug.m: Change the interfaces of the procedures in this module slightly to make them usable in progress messages. compiler/frameopt.m: compiler/optimize.m: Conform to the changes to opt_debug. compiler/ll_backend.m: Fix comments. |
||
|
|
cc88711d63 |
Implement true multi-cons_id arm switches, i.e. switches in which we associate
Estimated hours taken: 40
Branches: main
Implement true multi-cons_id arm switches, i.e. switches in which we associate
more than one cons_id with a switch arm. Previously, for switches like this:
(
X = a,
goal1
;
( X = b
; X = c
),
goal2
)
we duplicated goal2. With this diff, goal2 won't be duplicated. We still
duplicate goals when that is necessary, i.e. in cases which the inner
disjunction contains code other than a functor test on the switched-on var,
like this:
(
X = a,
goal1
;
(
X = b,
goalb
;
X = c
goalc
),
goal2
)
For now, true multi-cons_id arm switches are supported only by the LLDS
backend. Supporting them on the MLDS backend is trickier, because some MLDS
target languages (e.g. Java) don't support the concept at all. So when
compiling to MLDS, we still duplicate the goal in switch detection (although
we could delay the duplication to just before code generation, if we wanted.)
compiler/options.m:
Add an internal option that tells switch detection whether to look for
multi-cons_id switch arms.
compiler/handle_options.m:
Set this option based on the back end.
Add a version of the "trans" dump level that doesn't print unification
details.
compiler/hlds_goal.m:
Extend the representation of switch cases to allow more than one
cons_id for a switch arm.
Add a type for representing switches that also includes tag information
(for use by the backends).
compiler/hlds_data.m:
For du types, record whether it is possible to speed up tests for one
cons_id (e.g. cons) by testing for the other (nil) and negating the
result. Recording this information once is faster than having
unify_gen.m trying to compute it from scratch for every single
tag test.
Add a type for representing a cons_id together with its tag.
compiler/hlds_out.m:
Print out the cheaper_tag_test information for types, and possibly
several cons_ids for each switch arm.
Add some utility predicates for describing switch arms in terms of
which cons_ids they are for.
Replace some booleans with purpose-specific types.
Make hlds_out honor is documentation, and not print out detailed
information about unifications (e.g. uniqueness and static allocation)
unless the right character ('u') is present in the control string.
compiler/add_type.m:
Fill in the information about cheaper tag tests when adding a du type.
compiler/switch_detection.m:
Extend the switch detection algorithm to detect multi-cons_id switch
arms.
When entering a switch arm, update the instmap to reflect that the
switched-on variable can now be bound only to the cons_ids that this
switch arm is for. We now need to do this, because if the arm contains
another switch on the same variable, computing the can_fail field of
that switch correctly requires us to know this information.
(Obviously, an arm for a single cons_id is unlikely to have switch on
the same variable, and for arms for several cons_ids, we previously
duplicated the arm and left the unification with the cons_id in each
copy, and this unification allowed the correct handling of any later
switches. However, the code of a multi-cons_id switch arm obviously
cannot have a unification with each cons_id in it, which is why
we now need to get the binding information from the switch itself.)
Replace some booleans with purpose-specific types, and give some
predicates better names.
compiler/instmap.m:
Provide predicates for recording that a switched-on variable has
one of several given cons_ids, for use at the starts of switch arms.
Give some predicates better names.
compiler/modes.m:
Provide predicates for updating the mode_info at the start of a
multi-cons_id switch arm.
compiler/det_report.m:
Handle multi-cons_id switch arms.
Update the instmap when entering each switch arm, since this is needed
to provide good (i.e. non-misleading) error messages when one switch on
a variable exists inside another switch on the same variable.
Since updating the instmap requires updating the module_info (since
the new inst may require a new entry in an inst table), thread the
det_info through as updateable state.
Replace some multi-clause predicate definitions with single clauses,
to make it easier to print the arguments in mdb.
Fix some misleading variable names.
compiler/det_analysis.m:
Update the instmap when entering each switch arm and thread the
det_info through as updateable state, since the predicates we call
in det_report.m require this.
compiler/det_util.m:
Handle multi-cons_id switch arms.
Rationalize the argument order of some access predicates.
compiler/switch_util.m:
Change the parts of this module that deal with string and tag switches
to optionally convert each arm to an arbitrary representation of the
arm. In the LLDS backend, the conversion process generated code for
the arm, and the arm's representation is the label at the start of
this code. This way, we can duplicate the label without duplicating
the code.
Add a new part of this module that associates each cons_id with its
tag, and (during the same pass) checks whether all the cons_ids are
integers, and if so what are min and max of these integers (needed
for dense switches). This scan is needed because the old way of making
this test had single-cons_id switch arms as one of its basic
assumptions, and doing it while adding tags to each case reduces
the number of traversals required.
Give better names to some predicates.
compiler/switch_case.m:
New module to handle the tasks associated with managing multi-cons_id
switch arms, including representing them for switch_util.m.
compiler/ll_backend.m:
Include the new module.
compiler/notes/compiler_design.html:
Note the new module.
compiler/llds.m:
Change the computed goto instruction to take a list of maybe labels
instead of a list of labels, with any missing labels meaning "not
reached".
compiler/string_switch.m:
compiler/tag_switch.m:
Reorganize the way these modules work. We can't generate the code of
each arm in place anymore, since it is now possible for more than one
cons_id to call for the execution of the same code. Instead, in
string_switch.m, we generate the codes of all the arms all at once,
and construct the hash index afterwards. (This approach simplifies
the code significantly.)
In tag switches (unlike string switches), we can get locality benefits
if the code testing for a cons_id is close to the code for that
cons_id, so we still try to put them next to each other when such
a locality benefit is available.
In both modules, the new approach uses a utility predicate in
switch_case.m to actually generate the code of each switch arm,
eliminating several copies the same code in the old versions of these
modules.
In tag_switch.m, don't create a local label that simply jumps to the
code address do_not_reached. Previously, we had to do this for
positions in jump tables that corresponded to cons_ids that the switch
variable could not be bound to. With the change to llds.m, we now
simply generate a "no" instead.
compiler/lookup_switch.m:
Get the info about int switch limits from our caller; don't compute it
here.
Give some variables better names.
compiler/dense_switch.m:
Generate the codes of the cases all at once, then assemble the table,
duplicate the labels as needed. This separation of concerns allows
significant simplifications.
Pack up all the information shared between the predicate that detects
whether a dense switch is appropriate and the predicate that actually
generates the dense switch.
Move some utility predicates to switch_util.
compiler/switch_gen.m:
Delete the code for tagging cons_ids, since that functionality is now
in switch_util.m.
The old version of this module could call the code generator to produce
(i.e. materialize) the switched-on variable repeatedly. We now produce
the variable once, and do the switch on the resulting rval.
compiler/unify_gen.m:
Use the information about cheaper tag tests in the type constructor's
entry in the HLDS type table, instead of trying to recompute it
every time.
Provide the predicates switch_gen.m now needs to perform tag tests
on rvals, as opposed to variables, and against possible more than one
cons_id.
Allow the caller to provide the tag corresponding to the cons_id(s)
in tag tests, since when we are generating code for switches, the
required computations have already been done.
Factor out some code to make all this possible.
Give better names to some predicates.
compiler/code_info.m:
Provide some utility predicates for the new code in other modules.
Give better names to some existing predicates.
compiler/hlds_code_util.m:
Rationalize the argument order of some predicates.
Replace some multi-clause predicate definitions with single clauses,
to make it easier to print the arguments in mdb.
compiler/accumulator.m:
compiler/add_heap_ops.m:
compiler/add_pragma.m:
compiler/add_trail_ops.m:
compiler/assertion.m:
compiler/build_mode_constraints.m:
compiler/check_typeclass.m:
compiler/closure_analysis.m:
compiler/code_util.m:
compiler/constraint.m:
compiler/cse_detection.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/delay_construct.m:
compiler/delay_partial_inst.m:
compiler/dep_par_conj.m:
compiler/distance_granularity.m:
compiler/dupproc.m:
compiler/equiv_type_hlds.m:
compiler/erl_code_gen.m:
compiler/exception_analysis.m:
compiler/export.m:
compiler/follow_code.m:
compiler/follow_vars.m:
compiler/foreign.m:
compiler/format_call.m:
compiler/frameopt.m:
compiler/goal_form.m:
compiler/goal_path.m:
compiler/goal_util.m:
compiler/granularity.m:
compiler/hhf.m:
compiler/higher_order.m:
compiler/implicit_parallelism.m:
compiler/inlining.m:
compiler/inst_check.m:
compiler/intermod.m:
compiler/interval.m:
compiler/lambda.m:
compiler/lambda.m:
compiler/lambda.m:
compiler/lco.m:
compiler/live_vars.m:
compiler/livemap.m:
compiler/liveness.m:
compiler/llds_out.m:
compiler/llds_to_x86_64.m:
compiler/loop_inv.m:
compiler/make_hlds_warn.m:
compiler/mark_static_terms.m:
compiler/middle_rec.m:
compiler/ml_tag_switch.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/mode_constraints.m:
compiler/mode_errors.m:
compiler/mode_util.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/pd_cost.m:
compiler/pd_into.m:
compiler/pd_util.m:
compiler/peephole.m:
compiler/polymorphism.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/purity.m:
compiler/quantification.m:
compiler/rbmm.actual_region_arguments.m:
compiler/rbmm.add_rbmm_goal_infos.m:
compiler/rbmm.condition_renaming.m:
compiler/rbmm.execution_paths.m:
compiler/rbmm.points_to_analysis.m:
compiler/rbmm.region_transformation.m:
compiler/recompilation.usage.m:
compiler/saved_vars.m:
compiler/simplify.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/store_alloc.m:
compiler/stratify.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/structure_reuse.indirect.m:
compiler/structure_reuse.lbu.m:
compiler/structure_reuse.lfu.m:
compiler/structure_reuse.versions.m:
compiler/structure_sharing.analysis.m:
compiler/table_gen.m:
compiler/tabling_analysis.m:
compiler/term_constr_build.m:
compiler/term_norm.m:
compiler/term_pass1.m:
compiler/term_traversal.m:
compiler/trailing_analysis.m:
compiler/transform_llds.m:
compiler/tupling.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/unify_proc.m:
compiler/unique_modes.m:
compiler/unneeded_code.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Make the changes necessary to conform to the changes above, principally
to handle multi-cons_id arm switches.
compiler/ml_string_switch.m:
Make the changes necessary to conform to the changes above, principally
to handle multi-cons_id arm switches.
Give some predicates better names.
compiler/dependency_graph.m:
Make the changes necessary to conform to the changes above, principally
to handle multi-cons_id arm switches. Change the order of arguments
of some predicates to make this easier.
compiler/bytecode.m:
compiler/bytecode_data.m:
compiler/bytecode_gen.m:
Make the changes necessary to conform to the changes above, principally
to handle multi-cons_id arm switches. (The bytecode interpreter
has not been updated.)
compiler/prog_rep.m:
mdbcomp/program_representation.m:
Change the byte sequence representation of goals to allow switch arms
with more than one cons_id. compiler/prog_rep.m now writes out the
updated representation, while mdbcomp/program_representation.m reads in
the updated representation.
deep_profiler/mdbprof_procrep.m:
Conform to the updated program representation.
tools/binary:
Fix a bug: if the -D option was given, the stage 2 directory wasn't
being initialized.
Abort if users try to give that option more than once.
compiler/Mercury.options:
Work around bug #32 in Mantis.
|
||
|
|
8ad3d82efb |
Add a mechanism for mapping between MVM registers and x86_64 registers
Estimated hours taken: 40
Branches: main
Add a mechanism for mapping between MVM registers and x86_64 registers
or fake reg array slots. This is needed by the x86_64 asm code generator.
At the momment the mapping is the same as that used by (non .par) grades
that use global register variables on the x86_64.
Modify the x86_64 code generator to emit additional instructions to
perform loads and store to the fake ref array when a virtual machine
registers is not mapped to a physical register.
compiler/x86_64_regs.m:
Defines a mapping of MVM registers to x86_64 registers.
compiler/x86_64_out.m:
Fixes some predicates to output asm codes to conform with the changes
in x86_64_instrs.m.
compiler/llds_to_x86_64.m:
Applies the register mapping during the code generation.
Add instructions to access values in the fake reg array.
(XXX this is still incomplete).
compiler/x86_64_instrs.m:
Adds discriminated union types and fixes some predicates to make the code
easier for modification.
compiler/mercury_compile.m:
Imports x86_64_regs and x86_64_out modules.
compiler/ll_backend.m:
Includes the x86_64_regs module.
Index: compiler/ll_backend.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
retrieving revision 1.19
diff -u -r1.19 ll_backend.m
--- compiler/ll_backend.m 5 Feb 2007 22:30:32 -0000 1.19
+++ compiler/ll_backend.m 9 Feb 2007 04:57:45 -0000
@@ -97,6 +97,7 @@
:- include_module llds_to_x86_64_out.
:- include_module x86_64_instrs.
:- include_module x86_64_out.
+:- include_module x86_64_regs.
:- implementation.
Index: compiler/llds_to_x86_64.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds_to_x86_64.m,v
retrieving revision 1.1
diff -u -r1.1 llds_to_x86_64.m
--- compiler/llds_to_x86_64.m 5 Feb 2007 22:30:32 -0000 1.1
+++ compiler/llds_to_x86_64.m 19 Feb 2007 06:10:47 -0000
@@ -10,7 +10,13 @@
% Main author: fhandoko.
%
% This module implements the LLDS->x86_64 asm code generator.
-%
+%
+% NOTE:
+% There are a number of placeholders. It appears as a string like this:
+% <<placeholder>>. The code generator places them as either x86_64_comment
+% or operand_label type. For example:
+% x86_64_comment("<<placeholder>>") or
+% operand_label("<<placeholder>>").
%-----------------------------------------------------------------------------%
:- module ll_backend.llds_to_x86_64.
@@ -37,6 +43,7 @@
:- import_module libs.compiler_util.
:- import_module ll_backend.llds_out.
:- import_module ll_backend.x86_64_out.
+:- import_module ll_backend.x86_64_regs.
:- import_module mdbcomp.prim_data.
:- import_module bool.
@@ -72,15 +79,17 @@
%
llds_to_x86_64_asm(_, CProcs, AsmProcs) :-
- transform_c_proc_list(CProcs, AsmProcs).
+ ll_backend.x86_64_regs.llds_reg_locn(RegLocnList),
+ RegMap = ll_backend.x86_64_regs.reg_map_init(RegLocnList),
+ transform_c_proc_list(RegMap, CProcs, AsmProcs).
% Transform a list of c procedures into a list of x86_64 procedures.
%
-:- pred transform_c_proc_list(list(c_procedure)::in,
+:- pred transform_c_proc_list(reg_map::in, list(c_procedure)::in,
list(x86_64_procedure)::out) is det.
-transform_c_proc_list([], []).
-transform_c_proc_list([CProc | CProcs], [AsmProc | AsmProcs]) :-
+transform_c_proc_list(_, [], []).
+transform_c_proc_list(RegMap, [CProc | CProcs], [AsmProc | AsmProcs]) :-
AsmProc0 = ll_backend.x86_64_instrs.init_x86_64_proc(CProc),
ProcInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
%
@@ -89,65 +98,64 @@
%
ProcStr = backend_libs.name_mangle.proc_label_to_c_string(
AsmProc0 ^ x86_64_proc_label, no),
- ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, "@function")),
+ ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, function)),
ProcInstr = ProcInstr0 ^ x86_64_inst := [ProcName],
- transform_c_instr_list(CProc ^ cproc_code, AsmInstr0),
+ transform_c_instr_list(RegMap, CProc ^ cproc_code, AsmInstr0),
list.append([ProcInstr], AsmInstr0, AsmInstr),
AsmProc = AsmProc0 ^ x86_64_code := AsmInstr,
- transform_c_proc_list(CProcs, AsmProcs).
+ transform_c_proc_list(RegMap, CProcs, AsmProcs).
% Transform a list of c instructions into a list of x86_64 instructions.
%
-:- pred transform_c_instr_list(list(instruction)::in,
+:- pred transform_c_instr_list(reg_map::in, list(instruction)::in,
list(x86_64_instruction)::out) is det.
-transform_c_instr_list([], []).
-transform_c_instr_list([CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
+transform_c_instr_list(_, [], []).
+transform_c_instr_list(RegMap, [CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
CInstr0 = llds_instr(CInstr1, Comment),
- instr_to_x86_64(CInstr1, AsmInstrList),
+ instr_to_x86_64(RegMap, CInstr1, RegMap1, AsmInstrList),
+ ll_backend.x86_64_regs.reg_map_reset_scratch_reg_info(RegMap1, RegMap2),
AsmInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
AsmInstr1 = AsmInstr0 ^ x86_64_inst := AsmInstrList,
AsmInstr = AsmInstr1 ^ x86_64_inst_comment := Comment,
- transform_c_instr_list(CInstr0s, AsmInstrs).
+ transform_c_instr_list(RegMap2, CInstr0s, AsmInstrs).
% Transform a block instruction of an llds instruction into a list of
% x86_64 instructions.
%
-:- pred transform_block_instr(list(instruction)::in, list(x86_64_instr)::out)
- is det.
+:- pred transform_block_instr(reg_map::in, list(instruction)::in,
+ list(x86_64_instr)::out) is det.
-transform_block_instr(CInstrs, Instrs) :-
- transform_block_instr_list(CInstrs, ListInstrs),
+transform_block_instr(RegMap, CInstrs, Instrs) :-
+ transform_block_instr_list(RegMap, CInstrs, ListInstrs),
list.condense(ListInstrs, Instrs).
-:- pred transform_block_instr_list(list(instruction)::in,
+:- pred transform_block_instr_list(reg_map::in, list(instruction)::in,
list(list(x86_64_instr))::out) is det.
-transform_block_instr_list([], []).
-transform_block_instr_list([CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
+transform_block_instr_list(_, [], []).
+transform_block_instr_list(RegMap, [CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
CInstr0 = llds_instr(CInstr, _),
- instr_to_x86_64(CInstr, Instr0),
- transform_block_instr_list(CInstr0s, Instr0s).
+ instr_to_x86_64(RegMap, CInstr, RegMap1, Instr0),
+ ll_backend.x86_64_regs.reg_map_reset_scratch_reg_info(RegMap1, RegMap2),
+ transform_block_instr_list(RegMap2, CInstr0s, Instr0s).
% Transform livevals of llds instruction into a list of x86_64 instructions.
%
-:- pred transform_livevals(list(lval)::in, list(x86_64_instr)::out) is det.
+:- pred transform_livevals(reg_map::in, list(lval)::in, list(x86_64_instr)::out)
+ is det.
-transform_livevals([], []).
-transform_livevals([Lval | Lvals], [Instr | Instrs]) :-
- transform_lval(Lval, Res0, Res1),
+transform_livevals(_, [], []).
+transform_livevals(RegMap, [Lval | Lvals], [Instr | Instrs]) :-
+ transform_lval(RegMap, Lval, RegMap1, Res0, Res1),
(
- Res0 = yes(LvalOp),
- Instr = x86_64_instr(mov(operand_label("<<livevals>>"), LvalOp)),
- transform_livevals(Lvals, Instrs)
+ Res0 = yes(LvalOp)
;
Res0 = no,
(
Res1 = yes(LvalInstrs),
( get_last_instr_opand(LvalInstrs, LastOp) ->
- Instr = x86_64_instr(mov(operand_label("<<livevals>>"),
- LastOp)),
- transform_livevals(Lvals, Instrs)
+ LvalOp = LastOp
;
unexpected(this_file, "transform_livevals: unexpected:"
++ " get_last_instr_opand failed")
@@ -157,22 +165,25 @@
unexpected(this_file, "transform_livevals: unexpected:"
++ " get_last_instr_opand failed")
)
- ).
+ ),
+ Instr = x86_64_instr(mov(operand_label("<<liveval>>"), LvalOp)),
+ transform_livevals(RegMap1, Lvals, Instrs).
% Given an llds instruction, transform it into equivalent x86_64
% instructions.
%
-:- pred instr_to_x86_64(instr::in, list(x86_64_instr)::out) is det.
+:- pred instr_to_x86_64(reg_map::in, instr::in, reg_map::out,
+ list(x86_64_instr)::out) is det.
-instr_to_x86_64(comment(Comment), [x86_64_comment(Comment)]).
-instr_to_x86_64(livevals(RegsAndStackLocs), Instrs) :-
+instr_to_x86_64(RegMap, comment(Comment), RegMap, [x86_64_comment(Comment)]).
+instr_to_x86_64(RegMap, livevals(RegsAndStackLocs), RegMap, Instrs) :-
set.to_sorted_list(RegsAndStackLocs, List),
- transform_livevals(List, Instrs).
-instr_to_x86_64(block(_, _, CInstrs), Instrs) :-
- transform_block_instr(CInstrs, Instrs).
-instr_to_x86_64(assign(Lval, Rval), Instrs) :-
- transform_lval(Lval, Res0, Res1),
- transform_rval(Rval, Res2, Res3),
+ transform_livevals(RegMap, List, Instrs).
+instr_to_x86_64(RegMap, block(_, _, CInstrs), RegMap, Instrs) :-
+ transform_block_instr(RegMap, CInstrs, Instrs).
+instr_to_x86_64(RegMap0, assign(Lval, Rval), RegMap, Instrs) :-
+ transform_lval(RegMap0, Lval, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval, RegMap, Res2, Res3),
(
Res0 = yes(LvalOp),
(
@@ -184,7 +195,7 @@
Res3 = yes(RvalInstrs),
( get_last_instr_opand(RvalInstrs, LastOp) ->
LastInstr = x86_64_instr(mov(LastOp, LvalOp)),
- list.append(RvalInstrs, [LastInstr], Instrs)
+ Instrs = RvalInstrs ++ [LastInstr]
;
unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
++ " get_last_instr_opand failed")
@@ -202,16 +213,15 @@
( get_last_instr_opand(LvalInstrs, LvalLastOp) ->
(
Res2 = yes(RvalOp),
- Instr0 = x86_64_instr(mov(RvalOp, LvalLastOp)),
- list.append(LvalInstrs, [Instr0], Instrs)
-
+ Instr1 = x86_64_instr(mov(RvalOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ [Instr1]
;
Res2 = no,
(
Res3 = yes(RvalInstrs),
( get_last_instr_opand(RvalInstrs, RvalLastOp) ->
- Instr0 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
- Instrs = LvalInstrs ++ [Instr0] ++ RvalInstrs
+ Instr1 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ RvalInstrs ++ [Instr1]
;
unexpected(this_file, "instr_to_x86_64: assign:"
++ " unexpected:get_last_instr_opand failed")
@@ -232,22 +242,42 @@
++ "Lval")
)
).
-instr_to_x86_64(llcall(Target0, Continuation0, _, _, _, _), Instrs) :-
+instr_to_x86_64(RegMap0, llcall(Target0, Continuation0, _, _, _, _), RegMap,
+ Instrs) :-
code_addr_type(Target0, Target1),
code_addr_type(Continuation0, Continuation1),
- Instr1 = x86_64_instr(mov(operand_label(Continuation1),
- operand_label("<<succip>>"))),
+ lval_reg_locn(RegMap0, succip, Op0, Instr0),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap0, RegMap),
+ (
+ Op0 = yes(Op)
+ ;
+ Op0 = no,
+ (
+ Instr0 = yes(Instr),
+ ( get_last_instr_opand(Instr, LastOpand) ->
+ Op = LastOpand
+ ;
+ unexpected(this_file, "instr_to_x86_64: llcall: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Instr0 = no,
+ unexpected(this_file, "instr_to_x86_64: llcall: unexpected:" ++
+ " lval_reg_locn failed")
+ )
+ ),
+ Instr1 = x86_64_instr(mov(operand_label(Continuation1), Op)),
Instr2 = x86_64_instr(jmp(operand_label(Target1))),
Instrs = [Instr1, Instr2].
-instr_to_x86_64(mkframe(_, _), [x86_64_comment("<<mkframe>>")]).
-instr_to_x86_64(label(Label), Instrs) :-
+instr_to_x86_64(RegMap, mkframe(_, _), RegMap, [x86_64_comment("<<mkframe>>")]).
+instr_to_x86_64(RegMap, label(Label), RegMap, Instrs) :-
LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
Instrs = [x86_64_label(LabelStr)].
-instr_to_x86_64(goto(CodeAddr), Instrs) :-
+instr_to_x86_64(RegMap, goto(CodeAddr), RegMap, Instrs) :-
code_addr_type(CodeAddr, Label),
Instrs = [x86_64_instr(jmp(operand_label(Label)))].
-instr_to_x86_64(computed_goto(Rval, Labels), Instrs) :-
- transform_rval(Rval, Res0, Res1),
+instr_to_x86_64(RegMap0, computed_goto(Rval, Labels), RegMap, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
(
Res0 = yes(RvalOp),
RvalInstrs = []
@@ -268,17 +298,19 @@
)
),
labels_to_string(Labels, "", LabelStr),
- TempReg = operand_reg(gp_reg(13)),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap1),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap1, RegMap),
+ TempReg = operand_reg(ScratchReg),
Instr0 = x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(LabelStr))),
TempReg)),
Instr1 = x86_64_instr(add(RvalOp, TempReg)),
Instr2 = x86_64_instr(jmp(TempReg)),
Instrs = RvalInstrs ++ [Instr0] ++ [Instr1] ++ [Instr2].
-instr_to_x86_64(arbitrary_c_code(_, _, _), Instrs) :-
+instr_to_x86_64(RegMap, arbitrary_c_code(_, _, _), RegMap, Instrs) :-
Instrs = [x86_64_comment("<<arbitrary_c_code>>")].
-instr_to_x86_64(if_val(Rval, CodeAddr), Instrs) :-
+instr_to_x86_64(RegMap0, if_val(Rval, CodeAddr), RegMap, Instrs) :-
code_addr_type(CodeAddr, Target),
- transform_rval(Rval, Res0, Res1),
+ transform_rval(RegMap0, Rval, RegMap, Res0, Res1),
(
Res0 = yes(RvalOp)
;
@@ -297,14 +329,17 @@
++ " Rval")
)
),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
Instrs = [x86_64_directive(x86_64_pseudo_if(RvalStr)), x86_64_instr(j(
operand_label(Target), e)), x86_64_directive(endif)].
-instr_to_x86_64(save_maxfr(_), [x86_64_comment("<<save_maxfr>>")]).
-instr_to_x86_64(restore_maxfr(_), [x86_64_comment("<<restore_maxfr>>")]).
-instr_to_x86_64(incr_hp(Lval, Tag0, Words0, Rval, _, _), Instrs) :-
- transform_rval(Rval, Res0, Res1),
- transform_lval(Lval, Res2, Res3),
+instr_to_x86_64(RegMap, save_maxfr(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<save_maxfr>>")].
+instr_to_x86_64(RegMap, restore_maxfr(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<restore_maxfr>>")].
+instr_to_x86_64(RegMap0, incr_hp(Lval, Tag0, Words0, Rval, _, _), RegMap,
+ Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
+ transform_lval(RegMap1, Lval, RegMap2, Res2, Res3),
(
Res0 = yes(RvalOp)
;
@@ -344,14 +379,17 @@
(
Words0 = yes(Words),
IncrVal = operand_imm(imm32(int32(Words))),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ScratchReg0 = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap3),
+ TempReg1 = operand_reg(ScratchReg0),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
- LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
- IncrAddInstr = x86_64_instr(add(IncrVal, TempReg)),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
+ IncrAddInstr = x86_64_instr(add(IncrVal, TempReg1)),
list.append([LoadAddr], [IncrAddInstr], IncrAddrInstrs)
;
Words0 = no,
+ RegMap3 = RegMap2,
IncrAddrInstrs = []
),
(
@@ -360,86 +398,141 @@
Tag0 = no,
Tag = 0
),
- TempReg = operand_reg(gp_reg(13)),
- ImmToReg = x86_64_instr(mov(RvalOp, TempReg)),
- SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg)),
- Instr0 = x86_64_instr(mov(TempReg, LvalOp)),
- Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr0].
-instr_to_x86_64(mark_hp(_), [x86_64_comment("<<mark_hp>>")]).
-instr_to_x86_64(restore_hp(_), [x86_64_comment("<<restore_hp>>")]).
-instr_to_x86_64(free_heap(_), [x86_64_comment("<<free_heap>>")]).
-instr_to_x86_64(store_ticket(_), [x86_64_comment("<<store_ticket>>")]).
-instr_to_x86_64(reset_ticket(_, _), [x86_64_comment("<<reset_ticket>>")]).
-instr_to_x86_64(prune_ticket, [x86_64_comment("<<prune_ticket>>")]).
-instr_to_x86_64(discard_ticket, [x86_64_comment("<<discard_ticket>>")]).
-instr_to_x86_64(mark_ticket_stack(_), [x86_64_comment("<<mark_ticket_stack>>")]).
-instr_to_x86_64(prune_tickets_to(_), [x86_64_comment("<<prune_tickets_to>>")]).
-instr_to_x86_64(incr_sp(NumSlots, ProcName, _), Instrs) :-
+ ScratchReg1 = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap3),
+ reg_map_remove_scratch_reg(RegMap3, RegMap),
+ TempReg2 = operand_reg(ScratchReg1),
+ ImmToReg = x86_64_instr(mov(RvalOp, TempReg2)),
+ SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg2)),
+ Instr1 = x86_64_instr(mov(TempReg2, LvalOp)),
+ Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr1].
+instr_to_x86_64(RegMap, mark_hp(_), RegMap, [x86_64_comment("<<mark_hp>>")]).
+instr_to_x86_64(RegMap, restore_hp(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<restore_hp>>")].
+instr_to_x86_64(RegMap, free_heap(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<free_heap>>")].
+instr_to_x86_64(RegMap, store_ticket(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<store_ticket>>")].
+instr_to_x86_64(RegMap, reset_ticket(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<reset_ticket>>")].
+instr_to_x86_64(RegMap, prune_ticket, RegMap, Instr) :-
+ Instr = [x86_64_comment("<<prune_ticket>>")].
+instr_to_x86_64(RegMap, discard_ticket, RegMap, Instr) :-
+ Instr = [x86_64_comment("<<discard_ticket>>")].
+instr_to_x86_64(RegMap, mark_ticket_stack(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<mark_ticket_stack>>")].
+instr_to_x86_64(RegMap, prune_tickets_to(_), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<prune_tickets_to>>")].
+instr_to_x86_64(RegMap, incr_sp(NumSlots, ProcName, _), RegMap, Instrs) :-
Instr1 = x86_64_comment("<<incr_sp>> " ++ ProcName),
Instr2 = x86_64_instr(enter(uint16(NumSlots), uint8(0))),
Instrs = [Instr1, Instr2].
-instr_to_x86_64(decr_sp(NumSlots), Instrs) :-
+instr_to_x86_64(RegMap0, decr_sp(NumSlots), RegMap, Instrs) :-
DecrOp = operand_imm(imm32(int32(NumSlots))),
- Instr = x86_64_instr(sub(DecrOp, operand_reg(gp_reg(13)))),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap0),
+ ll_backend.x86_64_regs.reg_map_remove_scratch_reg(RegMap0, RegMap),
+ Instr = x86_64_instr(sub(DecrOp, operand_reg(ScratchReg))),
list.append([x86_64_comment("<<decr_sp>> ")], [Instr], Instrs).
-instr_to_x86_64(decr_sp_and_return(NumSlots), Instrs) :-
+instr_to_x86_64(RegMap, decr_sp_and_return(NumSlots), RegMap, Instrs) :-
Instrs = [x86_64_comment("<<decr_sp_and_return>> " ++
string.int_to_string(NumSlots))].
-instr_to_x86_64(foreign_proc_code(_, _, _, _, _, _, _, _, _),
- [x86_64_comment("<<foreign_proc_code>>")]).
-instr_to_x86_64(init_sync_term(_, _), [x86_64_comment("<<init_sync_term>>")]).
-instr_to_x86_64(fork(_), [x86_64_comment("<<fork>>")]).
-instr_to_x86_64(join_and_continue(_, _), [x86_64_comment("<<join_and_continue>>")]).
-
+instr_to_x86_64(RegMap, foreign_proc_code(_, _, _, _, _, _, _, _, _), RegMap,
+ Instr) :-
+ Instr = [x86_64_comment("<<foreign_proc_code>>")].
+instr_to_x86_64(RegMap, init_sync_term(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<init_sync_term>>")].
+instr_to_x86_64(RegMap, fork(_), RegMap, [x86_64_comment("<<fork>>")]).
+instr_to_x86_64(RegMap, join_and_continue(_, _), RegMap, Instr) :-
+ Instr = [x86_64_comment("<<join_and_continue>>")].
% Transform lval into either an x86_64 operand or x86_64 instructions.
%
-:- pred transform_lval(lval::in, maybe(operand)::out,
+:- pred transform_lval(reg_map::in, lval::in, reg_map::out, maybe(operand)::out,
maybe(list(x86_64_instr))::out) is det.
-transform_lval(reg(CReg, CRegNum), Op, no) :-
- (
+transform_lval(RegMap0, reg(CReg, CRegNum), RegMap, Op, Instr) :-
+ (
CReg = reg_r,
- Op = yes(operand_reg(gp_reg(CRegNum)))
+ lval_reg_locn(RegMap, reg(CReg, CRegNum), Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap)
;
CReg = reg_f,
- Op = no
+ unexpected(this_file, "transform_lval: unexpected: llds reg_f")
).
-transform_lval(succip, yes(operand_label("<<succip>>")), no).
-transform_lval(maxfr, yes(operand_label("<<maxfr>>")), no).
-transform_lval(curfr, yes(operand_label("<<curfr>>")), no).
-transform_lval(hp, yes(operand_label("<<hp>>")), no).
-transform_lval(sp, yes(operand_label("<<sp>>")), no).
-transform_lval(parent_sp, yes(operand_label("<<parent_sp>>")), no).
-transform_lval(temp(CReg, CRegNum), Op, no) :-
- (
- CReg = reg_r,
- Op = yes(operand_reg(gp_reg(CRegNum)))
+transform_lval(RegMap0, succip, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, succip, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, maxfr, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, maxfr, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, curfr, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, curfr, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, hp, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, hp, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap0, sp, RegMap, Op, Instr) :-
+ lval_reg_locn(RegMap0, sp, Op, Instr),
+ reg_map_remove_scratch_reg(RegMap0, RegMap).
+transform_lval(RegMap, parent_sp, RegMap, Op, no) :-
+ Op = yes(operand_label("<<parent_sp>>")).
+transform_lval(RegMap, temp(CReg, CRegNum), RegMap1, Op, Instr) :-
+ transform_lval(RegMap, reg(CReg, CRegNum), RegMap1, Op, Instr).
+transform_lval(RegMap0, stackvar(Offset), RegMap, Op, Instr) :-
+ RegLocn = reg_map_lookup_reg_locn(RegMap, sp),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap0),
+ reg_map_remove_scratch_reg(RegMap0, RegMap),
+ (
+ RegLocn = actual(Reg),
+ Op = no,
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(
+ mem_abs(base_reg(Offset, Reg))), operand_reg(ScratchReg) ))])
;
- CReg = reg_f,
- Op = no
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "$" ++ "virtual_reg(" ++ string.int_to_string(SlotNum)
+ ++ ") + " ++ string.int_to_string(Offset),
+ Instr = yes([x86_64_instr(mov(
+ operand_label(FakeRegVal), operand_reg(ScratchReg)))])
).
-transform_lval(stackvar(Offset), Op, no) :-
- Op = yes(operand_label(string.int_to_string(Offset) ++ "(<<stackvar>>)")).
-transform_lval(parent_stackvar(_), yes(operand_label("<<parent_stackvar>>")), no).
-transform_lval(framevar(_), yes(operand_label("<<framevar>>")), no).
-transform_lval(succip_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(redoip_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(redofr_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(succfr_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(prevfr_slot(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(mem_ref(Rval), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_lval(global_var_ref(env_var_ref(Name)), yes(operand_label(Name)), no).
-transform_lval(lvar(_), yes(operand_label("<<lvar>>")), no).
-transform_lval(field(Tag0, Rval1, Rval2), no, Instrs) :-
- transform_rval(Rval1, Res0, Res1),
- transform_rval(Rval2, Res2, Res3),
+transform_lval(RegMap, parent_stackvar(_), RegMap, Op, no) :-
+ Op = yes(operand_label("<<parent_stackvar>>")).
+transform_lval(RegMap0, framevar(Offset), RegMap, Op, Instr) :-
+ ScratchReg= ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap),
+ reg_map_remove_scratch_reg(RegMap0, RegMap),
+ RegLocn = reg_map_lookup_reg_locn(RegMap, curfr),
+ % framevar(Int) refers to an offset Int relative to the current value of
+ % 'curfr'
+ (
+ RegLocn = actual(Reg),
+ Op = no,
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(
+ mem_abs(base_reg(Offset, Reg))), operand_reg(ScratchReg) ))])
+ ;
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "$" ++ "virtual_reg(" ++ string.int_to_string(SlotNum)
+ ++ ") + " ++ string.int_to_string(Offset),
+ Instr = yes([x86_64_instr(mov(
+ operand_label(FakeRegVal), operand_reg(ScratchReg)))])
+ ).
+transform_lval(RegMap0, succip_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, redoip_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, redofr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, succfr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, prevfr_slot(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap0, mem_ref(Rval), RegMap, Op, Instr) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, Instr).
+transform_lval(RegMap, global_var_ref(env_var_ref(Name)), RegMap, Op, no) :-
+ Op = yes(operand_label(Name)).
+transform_lval(RegMap, lvar(_), RegMap, yes(operand_label("<<lvar>>")), no).
+transform_lval(RegMap0, field(Tag0, Rval1, Rval2), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval2, RegMap2, Res2, Res3),
(
Res0 = yes(RvalOp1),
Instrs1 = []
@@ -478,8 +571,10 @@
unexpected(this_file, "lval_instrs: field: unexpected: Rval2")
)
),
- TempReg1 = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp1, RvalStr1),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap),
+ TempReg1 = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(RvalOp1, RvalStr1),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr1))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
FieldNum = x86_64_instr(add(RvalOp2, TempReg1)),
@@ -495,14 +590,14 @@
% Translates rval into its corresponding x86_64 operand.
%
-:- pred transform_rval(rval::in, maybe(operand)::out, maybe(list(x86_64_instr))
- ::out) is det.
+:- pred transform_rval(reg_map::in, rval::in, reg_map::out, maybe(operand)::out,
+ maybe(list(x86_64_instr)) ::out) is det.
-transform_rval(lval(Lval0), Op, Instrs) :-
- transform_lval(Lval0, Op, Instrs).
-transform_rval(var(_), yes(operand_label("<<var>>")), no).
-transform_rval(mkword(Tag, Rval), no, Instrs) :-
- transform_rval(Rval, Res0, Res1),
+transform_rval(RegMap0, lval(Lval0), RegMap, Op, Instrs) :-
+ transform_lval(RegMap0, Lval0, RegMap, Op, Instrs).
+transform_rval(RegMap, var(_), RegMap, yes(operand_label("<<var>>")), no).
+transform_rval(RegMap0, mkword(Tag, Rval), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap1, Res0, Res1),
(
Res0 = yes(RvalOp),
list.append([x86_64_comment("<<mkword>>")], [], Instr0)
@@ -522,27 +617,33 @@
unexpected(this_file, "transform_rval: mkword unexpected: Rval")
)
),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap1),
+ reg_map_remove_scratch_reg(RegMap1, RegMap),
+ TempReg = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(RvalOp, RvalStr),
MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
SetTag = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
Instrs = yes(Instr0 ++ [LoadAddr] ++ [SetTag]).
-transform_rval(const(llconst_true), yes(operand_label("<<llconst_true>>")), no).
-transform_rval(const(llconst_false), yes(operand_label("<<llconst_false>>")), no).
-transform_rval(const(llconst_int(Val)), yes(operand_imm(imm32(int32(Val)))), no).
-transform_rval(const(llconst_float(_)), yes(operand_label("<<llconst_float>>")), no).
-transform_rval(const(llconst_string(String)), no, yes(Op)) :-
+transform_rval(RegMap, const(llconst_true), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_true>>")).
+transform_rval(RegMap, const(llconst_false), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_false>>")).
+transform_rval(RegMap, const(llconst_int(Val)), RegMap, Op, no) :-
+ Op = yes(operand_imm(imm32(int32(Val)))).
+transform_rval(RegMap, const(llconst_float(_)), RegMap, Op, no) :-
+ Op = yes(operand_label("<<llconst_float>>")).
+transform_rval(RegMap, const(llconst_string(String)), RegMap, no, yes(Op)) :-
Op = [x86_64_directive(string([String]))].
-transform_rval(const(llconst_multi_string(_, _)), Op, no) :-
+transform_rval(RegMap, const(llconst_multi_string(_, _)), RegMap, Op, no) :-
Op = yes(operand_label("<<llconst_multi_string>>")).
-transform_rval(const(llconst_code_addr(CodeAddr)), Op, no) :-
+transform_rval(RegMap, const(llconst_code_addr(CodeAddr)), RegMap, Op, no) :-
code_addr_type(CodeAddr, CodeAddrType),
- Op = yes(operand_label("<<llconst_code_addr>>" ++ CodeAddrType)).
-transform_rval(const(llconst_data_addr(_, _)), Op, no) :-
+ Op = yes(operand_label(CodeAddrType)).
+transform_rval(RegMap, const(llconst_data_addr(_, _)), RegMap, Op, no) :-
Op = yes(operand_label("<<llconst_data_addr>>")).
-transform_rval(unop(Op, Rval), no, Instrs) :-
- transform_rval(Rval, Res0, Res1),
+transform_rval(RegMap0, unop(Op, Rval), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval, RegMap, Res0, Res1),
(
Res0 = yes(_),
unop_instrs(Op, Res0, no, Instrs0),
@@ -558,9 +659,9 @@
unexpected(this_file, "transform_rval: unop: unexpected: Rval")
)
).
-transform_rval(binop(Op, Rval1, Rval2), no, Instrs) :-
- transform_rval(Rval1, Res1, Res2),
- transform_rval(Rval2, Res3, Res4),
+transform_rval(RegMap0, binop(Op, Rval1, Rval2), RegMap, no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res1, Res2),
+ transform_rval(RegMap1, Rval2, RegMap, Res3, Res4),
(
Res1 = yes(Val1),
(
@@ -606,13 +707,14 @@
unexpected(this_file, "rval_instrs: binop: unexpected: Rval1")
)
).
-transform_rval(mem_addr(stackvar_ref(Rval)), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_rval(mem_addr(framevar_ref(Rval)), Op, no) :-
- transform_rval(Rval, Op, _).
-transform_rval(mem_addr(heap_ref(Rval1, Tag, Rval2)), no, Instrs) :-
- transform_rval(Rval1, Res0, Res1),
- transform_rval(Rval2, Res2, Res3),
+transform_rval(RegMap0, mem_addr(stackvar_ref(Rval)), RegMap, Op, no) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, _).
+transform_rval(RegMap0, mem_addr(framevar_ref(Rval)), RegMap, Op, no) :-
+ transform_rval(RegMap0, Rval, RegMap, Op, _).
+transform_rval(RegMap0, mem_addr(heap_ref(Rval1, Tag, Rval2)), RegMap,
+ no, Instrs) :-
+ transform_rval(RegMap0, Rval1, RegMap1, Res0, Res1),
+ transform_rval(RegMap1, Rval2, RegMap2, Res2, Res3),
(
Res0 = yes(Rval1Op),
(
@@ -672,14 +774,42 @@
++ " unexpected: Rval1")
)
),
- TempReg = operand_reg(gp_reg(13)),
- ll_backend.x86_64_out.operand_type(Rval1Op, Rval1Str),
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap2),
+ reg_map_remove_scratch_reg(RegMap2, RegMap),
+ TempReg = operand_reg(ScratchReg),
+ ll_backend.x86_64_out.operand_to_string(Rval1Op, Rval1Str),
MemRef = operand_mem_ref(mem_abs(base_expr(Rval1Str))),
LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
Instr0 = x86_64_instr(sub(Rval2Op, TempReg)),
Instr1 = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
Instrs = yes(Instrs0 ++ [LoadAddr] ++ [Instr0] ++ [Instr1]).
+
+ % Given an llds-lval, returns either an operand or instructions (actually,
+ % it only a single move instruction. It returns a list so that the calling
+ % predicate won't have to do any rearrangements for the return value). If
+ % lval is located in an actual register, returns the actual register which
+ % corresponds to that lval. Otherwise, move lval from the fake-reg array
+ % to a temporary register.
+ %
+:- pred lval_reg_locn(reg_map::in, lval::in, maybe(operand)::out,
+ maybe(list(x86_64_instr))::out) is det.
+
+lval_reg_locn(RegMap, Lval, Op, Instr) :-
+ RegLocn = reg_map_lookup_reg_locn(RegMap, Lval),
+ (
+ RegLocn = actual(Reg),
+ Op = yes(operand_reg(Reg)),
+ Instr = no
+ ;
+ RegLocn = virtual(SlotNum),
+ Op = no,
+ FakeRegVal = "fake_reg(" ++ string.int_to_string(SlotNum) ++ ")",
+ ScratchReg = ll_backend.x86_64_regs.reg_map_get_scratch_reg(RegMap),
+ Instr = yes([x86_64_instr(mov(operand_mem_ref(mem_abs(
+ base_expr(FakeRegVal))), operand_reg(ScratchReg)))])
+ ).
+
% x86_64 instructions for binary operation with either an operand or an
% expression (given as a list of x86_64 instructions) or a combination of
% both.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.429
diff -u -r1.429 mercury_compile.m
--- compiler/mercury_compile.m 9 Feb 2007 04:05:16 -0000 1.429
+++ compiler/mercury_compile.m 12 Feb 2007 22:47:47 -0000
@@ -127,6 +127,8 @@
:- import_module ll_backend.llds_to_x86_64.
:- import_module ll_backend.llds_to_x86_64_out.
:- import_module ll_backend.x86_64_instrs.
+:- import_module ll_backend.x86_64_out.
+:- import_module ll_backend.x86_64_regs.
% the MLDS back-end
:- import_module ml_backend.add_trail_ops. % HLDS -> HLDS
Index: compiler/x86_64_instrs.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_instrs.m,v
retrieving revision 1.2
diff -u -r1.2 x86_64_instrs.m
--- compiler/x86_64_instrs.m 5 Feb 2007 22:30:34 -0000 1.2
+++ compiler/x86_64_instrs.m 19 Feb 2007 05:57:50 -0000
@@ -11,6 +11,9 @@
%
% This module contains the representations of the x86_64 instructions.
%
+% NOTE:
+% Instructions that make use of segment registers and string operations
+% (such as compare_strings) have not been implemented.
%-----------------------------------------------------------------------------%
:- module ll_backend.x86_64_instrs.
@@ -146,6 +149,27 @@
; nle % Not Less or Equal (ZF = 0 and SF = OF).
; g. % Greater (ZF = 0 and SF = OF).
+ % Optional flags argument of .section pseudo_op.
+ %
+:- type pseudo_section_flag
+ ---> a % section is allocatable.
+ ; w % section is writable.
+ ; x % section is executable.
+ ; m % section is mergeable.
+ ; s. % section contains zero terminated string.
+
+ % An optional type of '.section' pseudo-op.
+ %
+:- type pseudo_section_type
+ ---> progbits % section contains data.
+ ; nobits. % section does not contain data.
+
+ % type_desc field of .section pseudo-op.
+ %
+:- type pseudo_section_type_desc
+ ---> function
+ ; object.
+
%-----------------------------------------------------------------------------%
%
% x86_64 pseudo-ops.
@@ -530,8 +554,8 @@
; section(
section_name :: string,
- section_flags :: maybe(string),
- section_type :: maybe(string),
+ section_flags :: maybe(list(pseudo_section_flag)),
+ section_type :: maybe(pseudo_section_type),
section_entsize :: maybe(int)
)
% ELF section stack manipulation directive.
@@ -618,7 +642,7 @@
; x86_64_pseudo_type(
type_name :: string,
- type_desc :: string
+ type_desc :: pseudo_section_type_desc
)
% Set the type of symbol'type_name' to be either a function or an
% object symbol.
@@ -666,8 +690,26 @@
% General purpose registers on the x86_64.
% Details on amd64-prog-man-vol1 manual p27.
%
-:- type gp_reg
- ---> gp_reg(int).
+
+:- type offset == int.
+
+:- type x86_64_reg
+ ---> rax
+ ; rbx
+ ; rcx
+ ; rdx
+ ; rbp
+ ; rsi
+ ; rdi
+ ; rsp
+ ; r8
+ ; r9
+ ; r10
+ ; r11
+ ; r12(offset) % offset(r12) in x86_64 = offset(sp) in llds.
+ ; r13
+ ; r14
+ ; r15.
% 64-bit instruction pointer register on the x86_64. Instruction pointer
% RIP is used as a base register for relative addressing. x86_64
@@ -719,7 +761,7 @@
:- type base_address
---> base_reg(
base_offset :: int,
- base_reg :: gp_reg
+ base_reg :: x86_64_reg
)
; base_expr(
@@ -729,7 +771,7 @@
% All operands for the x86_64 instructions.
%
:- type operand
- ---> operand_reg(gp_reg)
+ ---> operand_reg(x86_64_reg)
; operand_imm(imm_operand)
; operand_mem_ref(x86_64_mem_ref)
; operand_rel_offset(rel_offset)
@@ -751,7 +793,7 @@
% signed relative offset or a label.
%
:- type rmrol
- ---> rmrol_reg(gp_reg)
+ ---> rmrol_reg(x86_64_reg)
; rmrol_mem_ref(x86_64_mem_ref)
; rmrol_rel_offset(rel_offset)
; rmrol_label(
@@ -1277,6 +1319,12 @@
% Details on amd64-prog-man-vol3 manual p272.
%-----------------------------------------------------------------------------%
+
+ % Returns the number of x86_64 general-purpose registers.
+ %
+:- func num_x86_64_regs = int.
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
@@ -1291,4 +1339,8 @@
init_x86_64_instruction = x86_64_instr([], "").
+num_x86_64_regs = 16.
+
%-----------------------------------------------------------------------------%
+:- end_module ll_backend.x86_64_instrs.
+%----------------------------------------------------------------------------%
Index: compiler/x86_64_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_out.m,v
retrieving revision 1.3
diff -u -r1.3 x86_64_out.m
--- compiler/x86_64_out.m 8 Feb 2007 01:02:53 -0000 1.3
+++ compiler/x86_64_out.m 19 Feb 2007 06:06:56 -0000
@@ -13,6 +13,11 @@
% to string writer streams that are attached to the I/O state.
% (There's no particularly good reason for this latter restriction so
% it can safely be dropped if necessary.)
+%
+% NOTE:
+% The module calls unexpected/2 if there is an instruction which expects
+% a different type of operand (For example: an instruction expecting a
+% register operand but supplied with an immediate operand type).
%
%-----------------------------------------------------------------------------%
@@ -31,9 +36,7 @@
:- pred output_x86_64_instruction(Stream::in, x86_64_instruction::in,
io::di, io::uo) is det <= stream.writer(Stream, string, io).
- % XXX this is misnamed: it should be operand_to_string.
- %
-:- pred operand_type(operand::in, string::out) is det.
+:- pred operand_to_string(operand::in, string::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -41,6 +44,7 @@
:- implementation.
:- import_module libs.compiler_util.
+:- import_module ll_backend.x86_64_regs.
:- import_module bool.
:- import_module char.
@@ -233,13 +237,10 @@
Result0 = yes,
Type0 = yes(Type1)
->
- put(Stream, ",\"" ++ Flags1 ++ "\"", !IO),
- ( check_pseudo_section_type(Type1) ->
- put(Stream, "," ++ Type1, !IO)
- ;
- unexpected(this_file, "output_x86_64_pseudo_op: section:"
- ++ " check_section_type unexpected")
- )
+ pseudo_section_flags_to_string(Flags1, "", FlagsStr),
+ put(Stream, ",\"" ++ FlagsStr ++ "\"", !IO),
+ check_pseudo_section_type(Type1, Type1Str),
+ put(Stream, "," ++ Type1Str, !IO)
;
unexpected(this_file, "output_x86_64_pseudo_op: section:"
++ " check_section_flags_and_type unexpected")
@@ -291,12 +292,8 @@
output_x86_64_pseudo_op(Stream, title(Heading), !IO) :-
put(Stream, "\t.title\t" ++ Heading ++ "\n", !IO).
output_x86_64_pseudo_op(Stream, x86_64_pseudo_type(Name, Desc), !IO) :-
- ( check_pseudo_type_desc(Desc) ->
- put(Stream, "\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
- ;
- unexpected(this_file, "output_x86_64_pseudo_op: x86_64_pseudo_type:"
- ++ " unexpected: check_pseudo_type_desc failed")
- ).
+ check_pseudo_type_desc(Desc, DescType),
+ put(Stream, "\t.type\t" ++ Name ++ "," ++ DescType ++ "\n", !IO).
output_x86_64_pseudo_op(Stream, uleb128(ExprList), !IO) :-
output_pseudo_op_str_args(Stream, ".uleb128", ExprList, !IO).
output_x86_64_pseudo_op(Stream, val(Addr), !IO) :-
@@ -394,74 +391,96 @@
% Check if the FLAGS and TYPE argumentis of '.section' pseudo-op
% are valid.
%
-:- pred check_section_flags_and_type(string::in, maybe(string)::in,
- bool::out) is det.
+:- pred check_section_flags_and_type(list(pseudo_section_flag)::in,
+ maybe(pseudo_section_type)::in, bool::out) is det.
check_section_flags_and_type(Flags, Type0, Result) :-
- ( string.contains_char(Flags, 'M') ->
+ check_pseudo_section_m_flag(Flags, Result0),
+ (
+ Result0 = yes,
(
Type0 = yes(Type1),
- string.length(Type1) > 0
+ check_pseudo_section_type(Type1, _)
->
true
;
unexpected(this_file, "check_section_flags_and_type:"
- ++ " unexpected: flag")
+ ++ " unexpected: flag 'm' has to have 'type' arguments")
)
;
+ Result0 = no,
true
),
- string.to_char_list(Flags, CharList),
- check_pseudo_section_flags(CharList, Result0),
+ check_pseudo_section_flags(Flags, Result1),
(
- Result0 = yes,
+ Result1 = yes,
Result = yes
;
- Result0 = no,
+ Result1 = no,
Result = no
).
% Check if the FLAGS argument of '.section' pseudo-op is valid.
%
-:- pred check_pseudo_section_flags(list(char)::in, bool::out) is det.
+:- pred check_pseudo_section_flags(list(pseudo_section_flag)::in, bool::out)
+ is det.
check_pseudo_section_flags([], yes).
-check_pseudo_section_flags([Char | Chars], Result) :-
- ( string.contains_char(section_pseudo_op_flags, Char) ->
- check_pseudo_section_flags(Chars, Result)
- ;
- Result = no
- ).
+check_pseudo_section_flags([Flag | Flags], Result) :-
+ pseudo_section_flag(Flag, _),
+ check_pseudo_section_flags(Flags, Result).
- % The optional FLAGS argument of '.section' pseudo-op contains any
- % combination of:
- % 'a' - section is allocatable
- % 'w' - section is writable
- % 'x' - section is executable
- % 'M' - section is mergeable
- % 'S' - section contains zero terminated string
+ % Returns a string representation of optional flag arguments of
+ % .section pseudo instruction.
%
-:- func section_pseudo_op_flags = string.
+:- pred pseudo_section_flags_to_string(list(pseudo_section_flag)::in,
+ string::in, string::out) is det.
+
+pseudo_section_flags_to_string([], Result, Result).
+pseudo_section_flags_to_string([Flag | Flags], Result0, Result) :-
+ pseudo_section_flag(Flag, FlagString),
+ pseudo_section_flags_to_string(Flags, FlagString ++ Result0, Result).
+
+ % Returns a string representation of a .section pseudo-instruction flag.
+ %
+:- pred pseudo_section_flag(pseudo_section_flag::in, string::out) is det.
+
+pseudo_section_flag(a, "a").
+pseudo_section_flag(w, "w").
+pseudo_section_flag(x, "x").
+pseudo_section_flag(m, "m").
+pseudo_section_flag(s, "s").
-section_pseudo_op_flags = "awxMS".
+ % If a .section pseudo-instruction has 'm' flag, there has to be
+ % 'type' argument as its second argument.
+ %
+:- pred check_pseudo_section_m_flag(list(pseudo_section_flag)::in,
+ bool::out) is det.
+
+check_pseudo_section_m_flag([], no).
+check_pseudo_section_m_flag([Flag | Flags], Result) :-
+ pseudo_section_flag(Flag, FlagType),
+ ( FlagType = "m" ->
+ Result = yes
+ ;
+ check_pseudo_section_m_flag(Flags, Result)
+ ).
- % The optional type of '.section' pseudo-op may contain:
- % @progbits - section contains data
- % @nobits - section does not contain data
+ % Checks if .type argument of .section pseudo-instruction is valid.
%
-:- pred check_pseudo_section_type(string::in) is semidet.
+:- pred check_pseudo_section_type(pseudo_section_type::in, string::out)
+ is det.
-check_pseudo_section_type("@progbits").
-check_pseudo_section_type("@nobits").
+check_pseudo_section_type(progbits, "@progbits").
+check_pseudo_section_type(nobits, "@nobits").
- % Two valid values of 'type_desc' field in pseudo-op '.type':
- % @function
- % @object
+ % Checks if type_desc argument of .section pseudo-instruction is valid.
%
-:- pred check_pseudo_type_desc(string::in) is semidet.
+:- pred check_pseudo_type_desc(pseudo_section_type_desc::in, string::out)
+ is det.
-check_pseudo_type_desc("@function").
-check_pseudo_type_desc("@function").
+check_pseudo_type_desc(function, "@function").
+check_pseudo_type_desc(object, "@object").
:- func comment_length = int.
@@ -532,7 +551,7 @@
check_operand_not_immediate(Src, Result1),
(
Result1 = yes,
- operand_type(Src, SrcType),
+ operand_to_string(Src, SrcType),
check_operand_register(Dest, DestRes),
(
DestRes = yes,
@@ -546,7 +565,7 @@
++ " invalid condition third operand")
),
put(Stream, "\t" ++ Instr ++ "\t", !IO),
- operand_type(Dest, DestType),
+ operand_to_string(Dest, DestType),
put(Stream, SrcType ++ ", " ++ DestType ++ "\t", !IO)
;
DestRes = no,
@@ -562,7 +581,7 @@
check_operand_register(Op, Result),
(
Result = yes,
- operand_type(Op, RegType),
+ operand_to_string(Op, RegType),
put(Stream, "\tbswap\t" ++ RegType ++ "\t\t", !IO)
;
Result = no,
@@ -581,7 +600,7 @@
check_operand_not_immediate(Target, Result),
(
Result = yes,
- operand_type(Target, TargetType),
+ operand_to_string(Target, TargetType),
put(Stream, "\tcall\t" ++ TargetType ++ "\t\t", !IO)
;
Result = no,
@@ -617,8 +636,8 @@
check_operand_register(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tcmp\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -634,7 +653,7 @@
check_operand_not_mem_ref(Op, Result),
(
Result = no,
- operand_type(Op, OpType),
+ operand_to_string(Op, OpType),
put(Stream, "\tcmpxchg8b" ++ OpType, !IO)
;
Result = yes,
@@ -666,23 +685,23 @@
output_x86_64_inst(Stream, idiv(Operand), !IO) :-
output_instr_not_imm_dest(Stream, "idiv", Operand, no, !IO).
output_x86_64_inst(Stream, imul(Src, Dest, Mult), !IO) :-
- operand_type(Src, SrcType),
+ operand_to_string(Src, SrcType),
put(Stream, "\timul\t" ++ SrcType, !IO),
(
Dest = yes(DestRes),
check_operand_register(DestRes, Result1),
(
Result1 = yes,
- operand_type(DestRes, DestType)
+ operand_to_string(DestRes, DestType)
;
Result1 = no,
- TempReg = operand_reg(gp_reg(13)),
- operand_type(TempReg, DestType)
+ TempReg = operand_reg(get_scratch_reg),
+ operand_to_string(TempReg, DestType)
),
put(Stream, ", " ++ DestType, !IO),
(
Mult = yes(MultRes),
- operand_type(MultRes, Op3),
+ operand_to_string(MultRes, Op3),
put(Stream, ", " ++ Op3 ++ " ", !IO)
;
Mult = no,
@@ -699,7 +718,7 @@
output_x86_64_inst(Stream, jrcxz(RelOffset), !IO) :-
output_instr_8bit_rel_offset(Stream, "jrcxz", RelOffset, !IO).
output_x86_64_inst(Stream, jmp(Target), !IO) :-
- operand_type(Target, Op),
+ operand_to_string(Target, Op),
put(Stream, "\tjmp\t" ++ Op ++ "\t\t", !IO).
output_x86_64_inst(Stream, lea(Src, Dest), !IO) :-
check_operand_not_mem_ref(Src, Result1),
@@ -708,8 +727,8 @@
check_operand_register(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tlea\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -751,7 +770,7 @@
put(Stream, "\tpopfq\t", !IO).
output_x86_64_inst(Stream, push(Operand), !IO) :-
put(Stream, "\tpush\t", !IO),
- operand_type(Operand, OperandType),
+ operand_to_string(Operand, OperandType),
put(Stream, OperandType ++ "\t", !IO).
output_x86_64_inst(Stream, pushfq, !IO) :-
put(Stream, "\tpushfq\t", !IO).
@@ -762,8 +781,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\trc\t" ++ Cond, !IO),
put(Stream, Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
@@ -807,8 +826,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tro" ++ Dir ++ "\t", !IO),
put(Stream, Op1 ++ ", " ++ Op2 ++ "\t\t", !IO)
;
@@ -828,8 +847,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tsal\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -848,8 +867,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tshl\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -868,8 +887,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tsar\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -903,9 +922,9 @@
check_operand_register(Reg, Result3),
(
Result3 = yes,
- operand_type(Amnt, Op1),
- operand_type(Amnt, Op2),
- operand_type(Amnt, Op3),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Amnt, Op2),
+ operand_to_string(Amnt, Op3),
put(Stream, "\tshld\t" ++ Op1 ++ ", ", !IO),
put(Stream, Op2 ++ ", " ++ Op3 ++ "\t", !IO)
;
@@ -930,8 +949,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Amnt, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\tshr\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -953,9 +972,9 @@
check_operand_register(Reg, Result3),
(
Result3 = yes,
- operand_type(Amnt, Op1),
- operand_type(Amnt, Op2),
- operand_type(Amnt, Op3),
+ operand_to_string(Amnt, Op1),
+ operand_to_string(Amnt, Op2),
+ operand_to_string(Amnt, Op3),
put(Stream, "\tshrd\t" ++ Op1 ++ ", ", !IO),
put(Stream, Op2 ++ ", " ++ Op3 ++ "\t", !IO)
;
@@ -986,8 +1005,8 @@
check_operand_not_immediate(Src2, Result2),
(
Result2 = yes,
- operand_type(Src1, Op1),
- operand_type(Src2, Op2),
+ operand_to_string(Src1, Op1),
+ operand_to_string(Src2, Op2),
put(Stream, "\ttest\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1006,8 +1025,8 @@
check_operand_not_immediate(Dest, Result2),
(
Result2 = yes,
- operand_type(Src, Op1),
- operand_type(Dest, Op2),
+ operand_to_string(Src, Op1),
+ operand_to_string(Dest, Op2),
put(Stream, "\txadd\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1026,8 +1045,8 @@
check_operand_reg_or_mem(Src2, Result2),
(
Result2 = yes,
- operand_type(Src1, Op1),
- operand_type(Src2, Op2),
+ operand_to_string(Src1, Op1),
+ operand_to_string(Src2, Op2),
put(Stream, "\txchg\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
;
Result2 = no,
@@ -1062,26 +1081,46 @@
% Output a string representation of an immediate value.
%
-:- pred imm_op_type(imm_operand::in, string::out) is det.
+:- pred imm_op_to_string(imm_operand::in, string::out) is det.
-imm_op_type(imm8(int8(Val)), ImmVal) :-
+imm_op_to_string(imm8(int8(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-imm_op_type(imm16(int16(Val)), ImmVal) :-
+imm_op_to_string(imm16(int16(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-imm_op_type(imm32(int32(Val)), ImmVal) :-
+imm_op_to_string(imm32(int32(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
-:- func reg_type(gp_reg) = string.
+:- pred reg_to_string(x86_64_reg::in, string::out) is det.
-reg_type(gp_reg(RegNum)) = "%r" ++ string.int_to_string(RegNum).
+reg_to_string(rax, "%rax").
+reg_to_string(rbx, "%rbx").
+reg_to_string(rcx, "%rcx").
+reg_to_string(rdx, "%rdx").
+reg_to_string(rbp, "%rbp").
+reg_to_string(rsi, "%rsi").
+reg_to_string(rdi, "%rdi").
+reg_to_string(rsp, "%rsp").
+reg_to_string(r8, "%r8").
+reg_to_string(r9, "%r9").
+reg_to_string(r10, "%r10").
+reg_to_string(r11, "%11").
+reg_to_string(r12(Offset), RegStr) :-
+ ( Offset > 0 ->
+ RegStr = string.int_to_string(Offset) ++ "(%r12)"
+ ;
+ RegStr = "%r12"
+ ).
+reg_to_string(r13, "%r13").
+reg_to_string(r14, "%r14").
+reg_to_string(r15, "%r15").
% Output a string representation of a memory reference.
%
-:- pred mem_ref_type(x86_64_mem_ref::in, string::out) is det.
+:- pred mem_ref_to_string(x86_64_mem_ref::in, string::out) is det.
-mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
+mem_ref_to_string(mem_abs(DirectMemRef), MemRefVal) :-
base_address_type(DirectMemRef, MemRefVal).
-mem_ref_type(mem_rip(InstrPtr), MemRefVal) :-
+mem_ref_to_string(mem_rip(InstrPtr), MemRefVal) :-
instr_ptr_type(InstrPtr, MemRefVal).
% Output a string representation of a base address in a memory reference.
@@ -1089,11 +1128,12 @@
:- pred base_address_type(base_address::in, string::out) is det.
base_address_type(base_reg(Offset, Reg), BaseAddress) :-
+ reg_to_string(Reg, RegStr),
( Offset = 0 ->
- BaseAddress = "(" ++ reg_type(Reg) ++ ")"
+ BaseAddress = "(" ++ RegStr ++ ")"
;
BaseAddress = string.int_to_string(Offset) ++
- "(" ++ reg_type(Reg) ++ ")"
+ "(" ++ RegStr ++ ")"
).
base_address_type(base_expr(Expr), DispType) :-
DispType = "$" ++ Expr.
@@ -1117,9 +1157,9 @@
% Output a string representation of a relative offset.
%
-:- pred rel_offset_type(rel_offset::in, string::out) is det.
+:- pred rel_offset_to_string(rel_offset::in, string::out) is det.
-rel_offset_type(ro8(int8(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro8(int8(Val)), RelOffsetVal) :-
check_signed_int_size(8, Val, Result),
(
Result = yes,
@@ -1130,10 +1170,10 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro8(int8): unexpected:"
+ unexpected(this_file, "rel_offset_to_string: ro8(int8): unexpected:"
++ " check_signed_int_size failed")
).
-rel_offset_type(ro16(int16(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro16(int16(Val)), RelOffsetVal) :-
check_signed_int_size(16, Val, Result),
(
Result = yes,
@@ -1144,10 +1184,10 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro16(int16): unexpected"
+ unexpected(this_file, "rel_offset_to_string: ro16(int16): unexpected"
++ " check_signed_int_size failed")
).
-rel_offset_type(ro32(int32(Val)), RelOffsetVal) :-
+rel_offset_to_string(ro32(int32(Val)), RelOffsetVal) :-
check_signed_int_size(32, Val, Result),
(
Result = yes,
@@ -1158,20 +1198,20 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro32(int32): unexpected"
+ unexpected(this_file, "rel_offset_to_string: ro32(int32): unexpected"
++ " check_signed_int_size failed")
).
-operand_type(operand_reg(Reg), RegType) :-
- RegType = reg_type(Reg).
-operand_type(operand_imm(Imm), ImmVal) :-
- imm_op_type(Imm, ImmVal).
-operand_type(operand_mem_ref(MemRef), MemRefVal) :-
- mem_ref_type(MemRef, MemRefVal).
-operand_type(operand_rel_offset(RelOffset), RelOffsetType) :-
- rel_offset_type(RelOffset, RelOffsetType).
-operand_type(operand_label(Label), (Label)).
+operand_to_string(operand_reg(Reg), RegType) :-
+ reg_to_string(Reg, RegType).
+operand_to_string(operand_imm(Imm), ImmVal) :-
+ imm_op_to_string(Imm, ImmVal).
+operand_to_string(operand_mem_ref(MemRef), MemRefVal) :-
+ mem_ref_to_string(MemRef, MemRefVal).
+operand_to_string(operand_rel_offset(RelOffset), RelOffsetType) :-
+ rel_offset_to_string(RelOffset, RelOffsetType).
+operand_to_string(operand_label(Label), (Label)).
%-----------------------------------------------------------------------------%
%
@@ -1186,13 +1226,13 @@
is det <= stream.writer(Stream, string, io).
output_instr_not_imm_dest(Stream, Instr, Op1, Op2, !IO) :-
- operand_type(Op1, Op1Type),
+ operand_to_string(Op1, Op1Type),
(
Op2 = yes(Op2Result),
check_not_both_memory_ops(Op1, Op2Result, Result1),
(
Result1 = yes,
- operand_type(Op2Result, Op2Type),
+ operand_to_string(Op2Result, Op2Type),
check_operand_not_immediate(Op2Result, Result2),
(
Result2 = yes,
@@ -1225,7 +1265,7 @@
check_operand_rel_offset(RelOffset, Result1),
(
Result1 = yes,
- operand_type(RelOffset, RelOffsetType),
+ operand_to_string(RelOffset, RelOffsetType),
( string.to_int(RelOffsetType, Val) ->
check_signed_int_size(8, Val, Result2),
(
@@ -1255,11 +1295,11 @@
check_operand_not_immediate(Src, Result1),
(
Result1 = yes,
- operand_type(Src, Op1),
+ operand_to_string(Src, Op1),
check_operand_not_mem_ref(Idx, Result2),
(
Result2 = yes,
- operand_type(Idx, Op2),
+ operand_to_string(Idx, Op2),
( string.to_int(Op2, IdxInt) ->
check_signed_int_size(8, IdxInt, Result3),
(
@@ -1297,14 +1337,14 @@
instr_condition(Cond, CondRes),
put(Stream, "\t" ++ Instr, !IO),
put(Stream, CondRes ++ "\t", !IO),
- operand_type(Op1, Op1Type),
+ operand_to_string(Op1, Op1Type),
put(Stream, Op1Type, !IO),
(
Op2 = yes(Op2Res),
check_operand_register(Op2Res, Result3),
(
Result3 = yes,
- operand_type(Op2Res, Op2Type),
+ operand_to_string(Op2Res, Op2Type),
put(Stream, ", " ++ Op2Type, !IO)
;
Result3 = no,
@@ -1327,7 +1367,7 @@
check_rc_first_operand(Op, Result) :-
( Op = operand_imm(_) ->
- operand_type(Op, OpType),
+ operand_to_string(Op, OpType),
( string.to_int(OpType, OpInt) ->
check_unsigned_int_size(8, OpInt, Result1),
(
@@ -1393,7 +1433,7 @@
check_operand_unsigned_imm_or_reg(Operand, Result) :-
( Operand = operand_imm(Imm) ->
- imm_op_type(Imm, ImmType),
+ imm_op_to_string(Imm, ImmType),
( string.to_int(ImmType, ImmInt) ->
(
check_unsigned_int_size(32, ImmInt, Result1),
Index: compiler/x86_64_regs.m
===================================================================
RCS file: compiler/x86_64_regs.m
diff -N compiler/x86_64_regs.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/x86_64_regs.m 19 Feb 2007 06:05:32 -0000
@@ -0,0 +1,258 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: x86_64_regs.m.
+% Main author: fhandoko.
+%
+% llds.lval ===> reg_locn
+%
+% NOTE:
+% The first field of reg_map type is a list of available scratch registers.
+% Although the reg_map is updated everytime a scratch register is used in an
+% instruction (updated here means that the new reg_map is equivalent to the
+% old reg_map with the first element (the used scratch register) being
+% removed), it does not seem to work well. It seems to always get the first
+% scratch register. So, there are instructions in which the next instruction
+% overrides the value in a scratch register being used by a previous
+% instruction.
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.x86_64_regs.
+:- interface.
+
+:- import_module ll_backend.llds.
+:- import_module ll_backend.x86_64_instrs.
+
+:- import_module assoc_list.
+
+%----------------------------------------------------------------------------%
+
+ % This type stores information about the mapping from MVM registers
+ % to x86_64 registers. MVM registers will correspond to either
+ % (1) a physical x86_64 register
+ % or (2) a slot in the fake_reg array (see runtime/mercury_engine.h).
+ %
+:- type reg_map.
+
+ % This type represents the location of an MVM register on x86_64
+ % hardware. `actual/1' is a phyical x86_64 register. `virtual/1'
+ % is the slot in the fake reg array given by the argument.
+ %
+:- type reg_locn
+ ---> actual(x86_64_reg)
+ ; virtual(int). % Index into fake reg array.
+
+ % Create an association list of lvals and reg_lcons.
+ %
+:- pred llds_reg_locn(assoc_list(llds.lval, reg_locn)::out) is det.
+
+ % Create a reg_map given an association list of lvals and reg_locns.
+ % Throws an exception if an l-value in the association list does not
+ % correspond to a MVM register.
+ %
+:- func reg_map_init(assoc_list(llds.lval, reg_locn)) = reg_map.
+
+ % Given an LLDS lval that corresponds to a virtual machine register
+ % look up it's actual location according to the current register mapping.
+ % Throws an exception for l-values that do not correspond to virtual
+ % machine registers.
+ %
+:- func reg_map_lookup_reg_locn(reg_map, llds.lval) = reg_locn.
+
+ % Reset the contents of scratch registers. As a result, all scratch
+ % registers will be available.
+ %
+:- pred reg_map_reset_scratch_reg_info(reg_map::in, reg_map::out) is det.
+
+ % Given a reg_map, get the first available scratch register.
+ %
+:- func reg_map_get_scratch_reg(reg_map) = x86_64_reg.
+
+ % Get an x86_64_register.
+ %
+:- func get_scratch_reg = x86_64_reg.
+
+ % Remove the first index of scratch register list (which is the first
+ % field of reg_map).
+ %
+:- pred reg_map_remove_scratch_reg(reg_map::in, reg_map::out) is det.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module libs.compiler_util.
+
+:- import_module bool.
+:- import_module list.
+:- import_module map.
+:- import_module pair.
+:- import_module string.
+
+:- import_module io.
+
+%----------------------------------------------------------------------------%
+%
+% LLDS -> x86_64 register mapping.
+%
+
+:- type reg_map
+ ---> reg_map(
+ scratch_reg_info :: list(x86_64_reg),
+ % A list of available scratch registers.
+ map(llds.lval, reg_locn)
+ % Mapping lval to an actual or virtual register.
+ ).
+
+%----------------------------------------------------------------------------%
+
+llds_reg_locn([
+ sp - actual(r12(0)), % The top of non-det stack frame.
+ succip - actual(r13),
+ reg(reg_r, 1) - actual(r14),
+ reg(reg_r, 2) - actual(r15),
+ reg(reg_r, 3) - virtual(4),
+ hp - virtual(5),
+ reg(reg_r, 4) - virtual(6),
+ reg(reg_r, 5) - virtual(7),
+ curfr - virtual(8),
+ maxfr - virtual(9),
+ reg(reg_r, 6) - virtual(10),
+ reg(reg_r, 7) - virtual(11),
+ reg(reg_r, 8) - virtual(12),
+ reg(reg_r, 9) - virtual(13),
+ reg(reg_r, 10) - virtual(14),
+ reg(reg_r, 11) - virtual(15),
+ reg(reg_r, 12) - virtual(16),
+ reg(reg_r, 13) - virtual(17),
+ reg(reg_r, 14) - virtual(18),
+ reg(reg_r, 15) - virtual(19),
+ reg(reg_r, 16) - virtual(20),
+ reg(reg_r, 17) - virtual(21),
+ reg(reg_r, 18) - virtual(22),
+ reg(reg_r, 19) - virtual(23),
+ reg(reg_r, 20) - virtual(24),
+ reg(reg_r, 21) - virtual(25),
+ reg(reg_r, 22) - virtual(26),
+ reg(reg_r, 23) - virtual(27),
+ reg(reg_r, 24) - virtual(28),
+ reg(reg_r, 25) - virtual(29),
+ reg(reg_r, 26) - virtual(30),
+ reg(reg_r, 27) - virtual(31),
+ reg(reg_r, 28) - virtual(32),
+ reg(reg_r, 29) - virtual(33),
+ reg(reg_r, 30) - virtual(34),
+ reg(reg_r, 31) - virtual(35),
+ reg(reg_r, 32) - virtual(36)
+ ]).
+
+reg_map_init(AssocRegMap) = RegMap :-
+ map.init(Map0),
+ assoc_list.keys(AssocRegMap, ListOfKeys),
+ check_if_all_mvm_registers(ListOfKeys, Result),
+ (
+ Result = yes,
+ map.det_insert_from_assoc_list(Map0, AssocRegMap, Map1),
+ RegMap = reg_map(init_scratch_regs, Map1)
+ ;
+ Result = no,
+ unexpected(this_file, "reg_map_init: unexpected: non-MVM register"
+ ++ " found in the association list")
+ ).
+
+reg_map_lookup_reg_locn(Map, Lval) = RegLocn :-
+ Map = reg_map(_, RegMap),
+ (
+ ( Lval = parent_stackvar(_)
+ ; Lval = succip_slot(_)
+ ; Lval = redoip_slot(_)
+ ; Lval = redofr_slot(_)
+ ; Lval = succfr_slot(_)
+ ; Lval = prevfr_slot(_)
+ ; Lval = mem_ref(_)
+ ; Lval = global_var_ref(_)
+ )
+ ->
+ unexpected(this_file, "reg_map_lookup_reg_locn: unexpected: "
+ ++ "lval is not a virtual machine register")
+ ;
+ Lval = lvar(_)
+ ->
+ unexpected(this_file, "reg_map_lookup_reg_locn: unexpected: "
+ ++ "lvar/1 during x86_64 code generation")
+ ;
+ map.lookup(RegMap, Lval, RegLocn)
+ ).
+
+reg_map_reset_scratch_reg_info(RegMap0, RegMap) :-
+ ScratchRegs = init_scratch_regs,
+ RegMap = RegMap0 ^ scratch_reg_info := ScratchRegs.
+
+reg_map_get_scratch_reg(RegMap) = ScratchReg :-
+ ScratchRegs = RegMap ^ scratch_reg_info,
+ ( list.index0(ScratchRegs, first_list_idx, ScratchReg0) ->
+ ScratchReg = ScratchReg0
+ ;
+ unexpected(this_file, "reg_map_get_scratch_reg: unexpected:"
+ ++ " scratch registers exhausted")
+ ).
+
+reg_map_remove_scratch_reg(RegMap0, RegMap) :-
+ ScratchRegs0 = RegMap0 ^ scratch_reg_info,
+ ( list.drop(first_list_idx, ScratchRegs0, ScratchRegs1) ->
+ RegMap = RegMap0 ^ scratch_reg_info := ScratchRegs1
+ ;
+ unexpected(this_file, "reg_map_remove_scratch_reg: unexpected:"
+ ++ " scratch registers exhausted")
+ ).
+
+ % Check if all l-values in the association list correspond to MVM
+ % registers.
+ %
+:- pred check_if_all_mvm_registers(list(llds.lval)::in, bool::out) is det.
+
+check_if_all_mvm_registers([], yes).
+check_if_all_mvm_registers([Lval | Lvals], Result) :-
+ (
+ ( Lval = reg(reg_r, _)
+ ; Lval = succip
+ ; Lval = maxfr
+ ; Lval = curfr
+ ; Lval = hp
+ ; Lval = sp
+ )
+ ->
+ check_if_all_mvm_registers(Lvals, Result)
+ ;
+ Result = no
+ ).
+
+ % Initialize scratch registers to be used in an instruction.
+ %
+:- func init_scratch_regs = list(x86_64_reg).
+
+init_scratch_regs = [r9, r10, r11].
+
+get_scratch_reg = r9.
+
+ % Returns the index of the first element in the list.
+ %
+:- func first_list_idx = int.
+
+first_list_idx = 0.
+
+%----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "x86_64_regs.m".
+
+%----------------------------------------------------------------------------%
+:- end_module ll_backend.x86_64_regs.
+%----------------------------------------------------------------------------%
|
||
|
|
130b2b9cbd |
Updates the representation of several x86_64 instruction sets to make the
Estimated hours taken: 60
Branches: main
Updates the representation of several x86_64 instruction sets to make the
llds->x86_64 generation simpler. Also adds the llds->x86_64 asm generator
modules. There are still placeholders in several places in the modules.
The modules are not working version yet.
compiler/ll_backend.m:
Includes new llds->x86_64 modules.
compiler/llds_to_x86_64.m:
The llds->x86_64 asm generator module.
compiler/llds_to_x86_64_out.m:
Outputs instructions produced by llds->x86_64 asm generator.
compiler/mercury_compile.m:
Imports llds->x86_64 modules.
Calls predicates from llds->x86_64 asm generator module.
compiler/x86_64_instrs.m:
Fixes some x86_64 operands and instructions.
compiler/x86_64_out.m:
Fixes predicates to print out x86_64 instructions.
Index: compiler/ll_backend.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
retrieving revision 1.18
diff -u -r1.18 ll_backend.m
--- compiler/ll_backend.m 15 Jan 2007 22:49:41 -0000 1.18
+++ compiler/ll_backend.m 29 Jan 2007 00:45:30 -0000
@@ -93,6 +93,8 @@
:- include_module rtti_out.
% The LLDS->x86_64 asm phase.
+:- include_module llds_to_x86_64.
+:- include_module llds_to_x86_64_out.
:- include_module x86_64_instrs.
:- include_module x86_64_out.
Index: compiler/llds_to_x86_64.m
===================================================================
RCS file: compiler/llds_to_x86_64.m
diff -N compiler/llds_to_x86_64.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/llds_to_x86_64.m 5 Feb 2007 05:08:40 -0000
@@ -0,0 +1,911 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: llds_to_x86_64.m.
+% Main author: fhandoko.
+%
+% This module implements the LLDS->x86_64 asm code generator.
+%
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.llds_to_x86_64.
+:- interface.
+
+:- import_module hlds.hlds_module.
+:- import_module ll_backend.llds.
+:- import_module ll_backend.x86_64_instrs.
+
+:- import_module list.
+
+%----------------------------------------------------------------------------%
+
+:- pred llds_to_x86_64_asm(module_info::in, list(c_procedure)::in,
+ list(x86_64_procedure)::out) is det.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module backend_libs.builtin_ops.
+:- import_module backend_libs.name_mangle.
+:- import_module libs.compiler_util.
+:- import_module ll_backend.llds_out.
+:- import_module ll_backend.x86_64_out.
+:- import_module mdbcomp.prim_data.
+
+:- import_module bool.
+:- import_module int.
+:- import_module io.
+:- import_module maybe.
+:- import_module set.
+:- import_module string.
+
+%-----------------------------------------------------------------------------%
+%
+% binary operation type.
+%
+
+:- type binop
+ ---> binop_simple_opands(operand, operand)
+ % A binary operation with two simple operands, such as X + Y
+ % where X and Y are primitive values (ie. integers).
+ ; binop_simple_and_compound_opands(operand, list(x86_64_instr))
+ % A binary operation can consist of one simple operand at the
+ % left hand side and a compound operand at the right hand side.
+ % ie. X + Y where X can consist of further operations (such
+ % as Z + W, Z * W, etc) and Y is a primitive value.
+ ; binop_compound_and_simple_opands(list(x86_64_instr), operand)
+ % A binary operation can consist of a compound operand at the
+ % left hand side and a simple operand at the right hand side.
+ ; binop_compound_opands(list(x86_64_instr), list(x86_64_instr)).
+ % Both operands in the binary operation are compound operands.
+
+%----------------------------------------------------------------------------%
+%
+% llds to x86_64.
+%
+
+llds_to_x86_64_asm(_, CProcs, AsmProcs) :-
+ transform_c_proc_list(CProcs, AsmProcs).
+
+ % Transform a list of c procedures into a list of x86_64 procedures.
+ %
+:- pred transform_c_proc_list(list(c_procedure)::in,
+ list(x86_64_procedure)::out) is det.
+
+transform_c_proc_list([], []).
+transform_c_proc_list([CProc | CProcs], [AsmProc | AsmProcs]) :-
+ AsmProc0 = ll_backend.x86_64_instrs.init_x86_64_proc(CProc),
+ ProcInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
+ %
+ % Get the procedure's label and append it as an x86_64 instruction
+ % list before the output of the llds->x86_64 procedure transformation.
+ %
+ ProcStr = backend_libs.name_mangle.proc_label_to_c_string(
+ AsmProc0 ^ x86_64_proc_label, no),
+ ProcName = x86_64_directive(x86_64_pseudo_type(ProcStr, "@function")),
+ ProcInstr = ProcInstr0 ^ x86_64_inst := [ProcName],
+ transform_c_instr_list(CProc ^ cproc_code, AsmInstr0),
+ list.append([ProcInstr], AsmInstr0, AsmInstr),
+ AsmProc = AsmProc0 ^ x86_64_code := AsmInstr,
+ transform_c_proc_list(CProcs, AsmProcs).
+
+ % Transform a list of c instructions into a list of x86_64 instructions.
+ %
+:- pred transform_c_instr_list(list(instruction)::in,
+ list(x86_64_instruction)::out) is det.
+
+transform_c_instr_list([], []).
+transform_c_instr_list([CInstr0 | CInstr0s], [AsmInstr | AsmInstrs]) :-
+ CInstr0 = llds_instr(CInstr1, Comment),
+ instr_to_x86_64(CInstr1, AsmInstrList),
+ AsmInstr0 = ll_backend.x86_64_instrs.init_x86_64_instruction,
+ AsmInstr1 = AsmInstr0 ^ x86_64_inst := AsmInstrList,
+ AsmInstr = AsmInstr1 ^ x86_64_inst_comment := Comment,
+ transform_c_instr_list(CInstr0s, AsmInstrs).
+
+ % Transform a block instruction of an llds instruction into a list of
+ % x86_64 instructions.
+ %
+:- pred transform_block_instr(list(instruction)::in, list(x86_64_instr)::out)
+ is det.
+
+transform_block_instr(CInstrs, Instrs) :-
+ transform_block_instr_list(CInstrs, ListInstrs),
+ list.condense(ListInstrs, Instrs).
+
+:- pred transform_block_instr_list(list(instruction)::in,
+ list(list(x86_64_instr))::out) is det.
+
+transform_block_instr_list([], []).
+transform_block_instr_list([CInstr0 | CInstr0s], [Instr0 | Instr0s]) :-
+ CInstr0 = llds_instr(CInstr, _),
+ instr_to_x86_64(CInstr, Instr0),
+ transform_block_instr_list(CInstr0s, Instr0s).
+
+ % Transform livevals of llds instruction into a list of x86_64 instructions.
+ %
+:- pred transform_livevals(list(lval)::in, list(x86_64_instr)::out) is det.
+
+transform_livevals([], []).
+transform_livevals([Lval | Lvals], [Instr | Instrs]) :-
+ transform_lval(Lval, Res0, Res1),
+ (
+ Res0 = yes(LvalOp),
+ Instr = x86_64_instr(mov(operand_label("<<livevals>>"), LvalOp)),
+ transform_livevals(Lvals, Instrs)
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(LvalInstrs),
+ ( get_last_instr_opand(LvalInstrs, LastOp) ->
+ Instr = x86_64_instr(mov(operand_label("<<livevals>>"),
+ LastOp)),
+ transform_livevals(Lvals, Instrs)
+ ;
+ unexpected(this_file, "transform_livevals: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "transform_livevals: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ).
+
+ % Given an llds instruction, transform it into equivalent x86_64
+ % instructions.
+ %
+:- pred instr_to_x86_64(instr::in, list(x86_64_instr)::out) is det.
+
+instr_to_x86_64(comment(Comment), [x86_64_comment(Comment)]).
+instr_to_x86_64(livevals(RegsAndStackLocs), Instrs) :-
+ set.to_sorted_list(RegsAndStackLocs, List),
+ transform_livevals(List, Instrs).
+instr_to_x86_64(block(_, _, CInstrs), Instrs) :-
+ transform_block_instr(CInstrs, Instrs).
+instr_to_x86_64(assign(Lval, Rval), Instrs) :-
+ transform_lval(Lval, Res0, Res1),
+ transform_rval(Rval, Res2, Res3),
+ (
+ Res0 = yes(LvalOp),
+ (
+ Res2 = yes(RvalOp),
+ Instrs = [x86_64_instr(mov(RvalOp, LvalOp))]
+ ;
+ Res2 = no,
+ (
+ Res3 = yes(RvalInstrs),
+ ( get_last_instr_opand(RvalInstrs, LastOp) ->
+ LastInstr = x86_64_instr(mov(LastOp, LvalOp)),
+ list.append(RvalInstrs, [LastInstr], Instrs)
+ ;
+ unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res3 = no,
+ unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
+ ++ " Rval")
+ )
+ )
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(LvalInstrs),
+ ( get_last_instr_opand(LvalInstrs, LvalLastOp) ->
+ (
+ Res2 = yes(RvalOp),
+ Instr0 = x86_64_instr(mov(RvalOp, LvalLastOp)),
+ list.append(LvalInstrs, [Instr0], Instrs)
+
+ ;
+ Res2 = no,
+ (
+ Res3 = yes(RvalInstrs),
+ ( get_last_instr_opand(RvalInstrs, RvalLastOp) ->
+ Instr0 = x86_64_instr(mov(RvalLastOp, LvalLastOp)),
+ Instrs = LvalInstrs ++ [Instr0] ++ RvalInstrs
+ ;
+ unexpected(this_file, "instr_to_x86_64: assign:"
+ ++ " unexpected:get_last_instr_opand failed")
+ )
+ ;
+ Res3 = no,
+ unexpected(this_file, "instr_to_x86_64: assign:"
+ ++ " unexpected: Rval")
+ )
+ )
+ ;
+ unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "instr_to_x86_64: assign: unexpected:"
+ ++ "Lval")
+ )
+ ).
+instr_to_x86_64(llcall(Target0, Continuation0, _, _, _, _), Instrs) :-
+ code_addr_type(Target0, Target1),
+ code_addr_type(Continuation0, Continuation1),
+ Instr1 = x86_64_instr(mov(operand_label(Continuation1),
+ operand_label("<<succip>>"))),
+ Instr2 = x86_64_instr(jmp(operand_label(Target1))),
+ Instrs = [Instr1, Instr2].
+instr_to_x86_64(mkframe(_, _), [x86_64_comment("<<mkframe>>")]).
+instr_to_x86_64(label(Label), Instrs) :-
+ LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
+ Instrs = [x86_64_label(LabelStr)].
+instr_to_x86_64(goto(CodeAddr), Instrs) :-
+ code_addr_type(CodeAddr, Label),
+ Instrs = [x86_64_instr(jmp(operand_label(Label)))].
+instr_to_x86_64(computed_goto(Rval, Labels), Instrs) :-
+ transform_rval(Rval, Res0, Res1),
+ (
+ Res0 = yes(RvalOp),
+ RvalInstrs = []
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(RvalInstrs),
+ ( get_last_instr_opand(RvalInstrs, RvalOp0) ->
+ RvalOp = RvalOp0
+ ;
+ unexpected(this_file, "instr_to_x86_64: computed_goto:"
+ ++ " unexpected: get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "instr_to_x86_64: computed_goto: unexpected:"
+ ++ " Rval")
+ )
+ ),
+ labels_to_string(Labels, "", LabelStr),
+ TempReg = operand_reg(gp_reg(13)),
+ Instr0 = x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(LabelStr))),
+ TempReg)),
+ Instr1 = x86_64_instr(add(RvalOp, TempReg)),
+ Instr2 = x86_64_instr(jmp(TempReg)),
+ Instrs = RvalInstrs ++ [Instr0] ++ [Instr1] ++ [Instr2].
+instr_to_x86_64(arbitrary_c_code(_, _, _), Instrs) :-
+ Instrs = [x86_64_comment("<<arbitrary_c_code>>")].
+instr_to_x86_64(if_val(Rval, CodeAddr), Instrs) :-
+ code_addr_type(CodeAddr, Target),
+ transform_rval(Rval, Res0, Res1),
+ (
+ Res0 = yes(RvalOp)
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(RvalInstrs),
+ ( get_last_instr_opand(RvalInstrs, LastOp) ->
+ RvalOp = LastOp
+ ;
+ unexpected(this_file, "instr_to_x86_64: if_val: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "instr_to_x86_64: if_val: unexpected:"
+ ++ " Rval")
+ )
+ ),
+ ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ Instrs = [x86_64_directive(x86_64_pseudo_if(RvalStr)), x86_64_instr(j(
+ operand_label(Target), e)), x86_64_directive(endif)].
+instr_to_x86_64(save_maxfr(_), [x86_64_comment("<<save_maxfr>>")]).
+instr_to_x86_64(restore_maxfr(_), [x86_64_comment("<<restore_maxfr>>")]).
+instr_to_x86_64(incr_hp(Lval, Tag0, Words0, Rval, _, _), Instrs) :-
+ transform_rval(Rval, Res0, Res1),
+ transform_lval(Lval, Res2, Res3),
+ (
+ Res0 = yes(RvalOp)
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(RvalInstrs),
+ ( get_last_instr_opand(RvalInstrs, RvalLastOp) ->
+ RvalOp = RvalLastOp
+ ;
+ unexpected(this_file, "instr_to_x86_64: incr_hp: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "instr_to_x86_64: incr_hp: unexpected:"
+ ++ " Rval")
+ )
+ ),
+ (
+ Res2 = yes(LvalOp)
+ ;
+ Res2 = no,
+ (
+ Res3 = yes(LvalInstrs),
+ ( get_last_instr_opand(LvalInstrs, LvalLastOp) ->
+ LvalOp = LvalLastOp
+ ;
+ unexpected(this_file, "instr_to_x86_64: incr_hp: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res3 = no,
+ unexpected(this_file, "instr_to_x86_64: incr_hp: unexpected:"
+ ++ " Lval")
+ )
+ ),
+ (
+ Words0 = yes(Words),
+ IncrVal = operand_imm(imm32(int32(Words))),
+ TempReg = operand_reg(gp_reg(13)),
+ ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
+ IncrAddInstr = x86_64_instr(add(IncrVal, TempReg)),
+ list.append([LoadAddr], [IncrAddInstr], IncrAddrInstrs)
+ ;
+ Words0 = no,
+ IncrAddrInstrs = []
+ ),
+ (
+ Tag0 = yes(Tag)
+ ;
+ Tag0 = no,
+ Tag = 0
+ ),
+ TempReg = operand_reg(gp_reg(13)),
+ ImmToReg = x86_64_instr(mov(RvalOp, TempReg)),
+ SetTag = x86_64_instr(or(operand_imm(imm32(int32(Tag))), TempReg)),
+ Instr0 = x86_64_instr(mov(TempReg, LvalOp)),
+ Instrs = IncrAddrInstrs ++ [ImmToReg] ++ [SetTag] ++ [Instr0].
+instr_to_x86_64(mark_hp(_), [x86_64_comment("<<mark_hp>>")]).
+instr_to_x86_64(restore_hp(_), [x86_64_comment("<<restore_hp>>")]).
+instr_to_x86_64(free_heap(_), [x86_64_comment("<<free_heap>>")]).
+instr_to_x86_64(store_ticket(_), [x86_64_comment("<<store_ticket>>")]).
+instr_to_x86_64(reset_ticket(_, _), [x86_64_comment("<<reset_ticket>>")]).
+instr_to_x86_64(prune_ticket, [x86_64_comment("<<prune_ticket>>")]).
+instr_to_x86_64(discard_ticket, [x86_64_comment("<<discard_ticket>>")]).
+instr_to_x86_64(mark_ticket_stack(_), [x86_64_comment("<<mark_ticket_stack>>")]).
+instr_to_x86_64(prune_tickets_to(_), [x86_64_comment("<<prune_tickets_to>>")]).
+instr_to_x86_64(incr_sp(NumSlots, ProcName, _), Instrs) :-
+ Instr1 = x86_64_comment("<<incr_sp>> " ++ ProcName),
+ Instr2 = x86_64_instr(enter(uint16(NumSlots), uint8(0))),
+ Instrs = [Instr1, Instr2].
+instr_to_x86_64(decr_sp(NumSlots), Instrs) :-
+ DecrOp = operand_imm(imm32(int32(NumSlots))),
+ Instr = x86_64_instr(sub(DecrOp, operand_reg(gp_reg(13)))),
+ list.append([x86_64_comment("<<decr_sp>> ")], [Instr], Instrs).
+instr_to_x86_64(decr_sp_and_return(NumSlots), Instrs) :-
+ Instrs = [x86_64_comment("<<decr_sp_and_return>> " ++
+ string.int_to_string(NumSlots))].
+instr_to_x86_64(foreign_proc_code(_, _, _, _, _, _, _, _, _),
+ [x86_64_comment("<<foreign_proc_code>>")]).
+instr_to_x86_64(init_sync_term(_, _), [x86_64_comment("<<init_sync_term>>")]).
+instr_to_x86_64(fork(_), [x86_64_comment("<<fork>>")]).
+instr_to_x86_64(join_and_continue(_, _), [x86_64_comment("<<join_and_continue>>")]).
+
+
+ % Transform lval into either an x86_64 operand or x86_64 instructions.
+ %
+:- pred transform_lval(lval::in, maybe(operand)::out,
+ maybe(list(x86_64_instr))::out) is det.
+
+transform_lval(reg(CReg, CRegNum), Op, no) :-
+ (
+ CReg = reg_r,
+ Op = yes(operand_reg(gp_reg(CRegNum)))
+ ;
+ CReg = reg_f,
+ Op = no
+ ).
+transform_lval(succip, yes(operand_label("<<succip>>")), no).
+transform_lval(maxfr, yes(operand_label("<<maxfr>>")), no).
+transform_lval(curfr, yes(operand_label("<<curfr>>")), no).
+transform_lval(hp, yes(operand_label("<<hp>>")), no).
+transform_lval(sp, yes(operand_label("<<sp>>")), no).
+transform_lval(parent_sp, yes(operand_label("<<parent_sp>>")), no).
+transform_lval(temp(CReg, CRegNum), Op, no) :-
+ (
+ CReg = reg_r,
+ Op = yes(operand_reg(gp_reg(CRegNum)))
+ ;
+ CReg = reg_f,
+ Op = no
+ ).
+transform_lval(stackvar(Offset), Op, no) :-
+ Op = yes(operand_label(string.int_to_string(Offset) ++ "(<<stackvar>>)")).
+transform_lval(parent_stackvar(_), yes(operand_label("<<parent_stackvar>>")), no).
+transform_lval(framevar(_), yes(operand_label("<<framevar>>")), no).
+transform_lval(succip_slot(Rval), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_lval(redoip_slot(Rval), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_lval(redofr_slot(Rval), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_lval(succfr_slot(Rval), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_lval(prevfr_slot(Rval), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_lval(mem_ref(Rval), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_lval(global_var_ref(env_var_ref(Name)), yes(operand_label(Name)), no).
+transform_lval(lvar(_), yes(operand_label("<<lvar>>")), no).
+transform_lval(field(Tag0, Rval1, Rval2), no, Instrs) :-
+ transform_rval(Rval1, Res0, Res1),
+ transform_rval(Rval2, Res2, Res3),
+ (
+ Res0 = yes(RvalOp1),
+ Instrs1 = []
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(RvalInstrs1),
+ ( get_last_instr_opand(RvalInstrs1, LastOp1) ->
+ RvalOp1 = LastOp1,
+ Instrs1 = RvalInstrs1
+ ;
+ unexpected(this_file, "lval_instrs: field: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "lval_instrs: field: unexpected: Rval1")
+ )
+ ),
+ (
+ Res2 = yes(RvalOp2),
+ Instrs2 = []
+ ;
+ Res2 = no,
+ (
+ Res3 = yes(RvalInstrs2),
+ ( get_last_instr_opand(RvalInstrs2, LastOp2) ->
+ RvalOp2 = LastOp2,
+ Instrs2 = RvalInstrs2
+ ;
+ unexpected(this_file, "lval_instrs: field: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res3 = no,
+ unexpected(this_file, "lval_instrs: field: unexpected: Rval2")
+ )
+ ),
+ TempReg1 = operand_reg(gp_reg(13)),
+ ll_backend.x86_64_out.operand_type(RvalOp1, RvalStr1),
+ MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr1))),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg1)),
+ FieldNum = x86_64_instr(add(RvalOp2, TempReg1)),
+ Instrs3 = Instrs1 ++ Instrs2 ++ [x86_64_comment("<<field>>")] ++ [LoadAddr],
+ (
+ Tag0 = yes(Tag),
+ Mrbody = x86_64_instr(sub(operand_imm(imm32(int32(Tag))), TempReg1)),
+ Instrs = yes(Instrs3 ++ [Mrbody] ++ [FieldNum])
+ ;
+ Tag0 = no,
+ Instrs = yes(Instrs3 ++ [FieldNum])
+ ).
+
+ % Translates rval into its corresponding x86_64 operand.
+ %
+:- pred transform_rval(rval::in, maybe(operand)::out, maybe(list(x86_64_instr))
+ ::out) is det.
+
+transform_rval(lval(Lval0), Op, Instrs) :-
+ transform_lval(Lval0, Op, Instrs).
+transform_rval(var(_), yes(operand_label("<<var>>")), no).
+transform_rval(mkword(Tag, Rval), no, Instrs) :-
+ transform_rval(Rval, Res0, Res1),
+ (
+ Res0 = yes(RvalOp),
+ list.append([x86_64_comment("<<mkword>>")], [], Instr0)
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(RvalInstrs),
+ ( get_last_instr_opand(RvalInstrs, LastOp) ->
+ RvalOp = LastOp,
+ list.append(RvalInstrs, [x86_64_comment("<<mkword>>")], Instr0)
+ ;
+ unexpected(this_file, "transform_rval: mkword: unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "transform_rval: mkword unexpected: Rval")
+ )
+ ),
+ TempReg = operand_reg(gp_reg(13)),
+ ll_backend.x86_64_out.operand_type(RvalOp, RvalStr),
+ MemRef = operand_mem_ref(mem_abs(base_expr(RvalStr))),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
+ SetTag = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
+ Instrs = yes(Instr0 ++ [LoadAddr] ++ [SetTag]).
+transform_rval(const(llconst_true), yes(operand_label("<<llconst_true>>")), no).
+transform_rval(const(llconst_false), yes(operand_label("<<llconst_false>>")), no).
+transform_rval(const(llconst_int(Val)), yes(operand_imm(imm32(int32(Val)))), no).
+transform_rval(const(llconst_float(_)), yes(operand_label("<<llconst_float>>")), no).
+transform_rval(const(llconst_string(String)), no, yes(Op)) :-
+ Op = [x86_64_directive(string([String]))].
+transform_rval(const(llconst_multi_string(_, _)), Op, no) :-
+ Op = yes(operand_label("<<llconst_multi_string>>")).
+transform_rval(const(llconst_code_addr(CodeAddr)), Op, no) :-
+ code_addr_type(CodeAddr, CodeAddrType),
+ Op = yes(operand_label("<<llconst_code_addr>>" ++ CodeAddrType)).
+transform_rval(const(llconst_data_addr(_, _)), Op, no) :-
+ Op = yes(operand_label("<<llconst_data_addr>>")).
+transform_rval(unop(Op, Rval), no, Instrs) :-
+ transform_rval(Rval, Res0, Res1),
+ (
+ Res0 = yes(_),
+ unop_instrs(Op, Res0, no, Instrs0),
+ Instrs = yes(Instrs0)
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(_),
+ unop_instrs(Op, no, Res1, Instrs0),
+ Instrs = yes(Instrs0)
+ ;
+ Res1 = no,
+ unexpected(this_file, "transform_rval: unop: unexpected: Rval")
+ )
+ ).
+transform_rval(binop(Op, Rval1, Rval2), no, Instrs) :-
+ transform_rval(Rval1, Res1, Res2),
+ transform_rval(Rval2, Res3, Res4),
+ (
+ Res1 = yes(Val1),
+ (
+ Res3 = yes(Val2),
+ binop_instrs(binop_simple_opands(Val1, Val2), Op, Instrs0),
+ Instrs = yes(Instrs0)
+ ;
+ Res3 = no,
+ (
+ Res4 = yes(RvalInstr2),
+ binop_instrs(binop_simple_and_compound_opands(Val1, RvalInstr2),
+ Op, Instrs0),
+ Instrs = yes(Instrs0)
+ ;
+ Res4 = no,
+ Instrs = no
+ )
+ )
+ ;
+ Res1 = no,
+ (
+ Res2 = yes(RvalInstr1),
+ (
+ Res3 = yes(Val2),
+ binop_instrs(binop_compound_and_simple_opands(RvalInstr1, Val2),
+ Op, Instrs0),
+ Instrs = yes(Instrs0)
+ ;
+ Res3 = no,
+ (
+ Res4 = yes(RvalInstr2),
+ binop_instrs(binop_compound_opands(RvalInstr1, RvalInstr2),
+ Op, Instrs0),
+ Instrs = yes(Instrs0)
+ ;
+ Res4 = no,
+ unexpected(this_file, "rval_instrs: binop: unexpected:"
+ ++ " Rval2")
+ )
+ )
+ ;
+ Res2 = no,
+ unexpected(this_file, "rval_instrs: binop: unexpected: Rval1")
+ )
+ ).
+transform_rval(mem_addr(stackvar_ref(Rval)), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_rval(mem_addr(framevar_ref(Rval)), Op, no) :-
+ transform_rval(Rval, Op, _).
+transform_rval(mem_addr(heap_ref(Rval1, Tag, Rval2)), no, Instrs) :-
+ transform_rval(Rval1, Res0, Res1),
+ transform_rval(Rval2, Res2, Res3),
+ (
+ Res0 = yes(Rval1Op),
+ (
+ Res2 = yes(Rval2Op),
+ Instrs0 = []
+ ;
+ Res2 = no,
+ (
+ Res3 = yes(Rval2Instr),
+ Instrs0 = Rval2Instr,
+ ( get_last_instr_opand(Rval2Instr, LastOp) ->
+ Rval2Op = LastOp
+ ;
+ unexpected(this_file, "transform_rval: mem_addr(heap_ref):"
+ ++ " unexpected: get_last_instr_opand failed")
+ )
+ ;
+ Res3 = no,
+ unexpected(this_file, "transform_rval: mem_addr(heap_ref):"
+ ++ " unexpected: Rval2")
+ )
+ )
+ ;
+ Res0 = no,
+ (
+ Res1 = yes(Rval1Instr),
+ ( get_last_instr_opand(Rval1Instr, LastOp) ->
+ Rval1Op = LastOp,
+ (
+ Res2 = yes(Rval2Op),
+ Instrs0 = Rval1Instr
+ ;
+ Res2 = no,
+ (
+ Res3 = yes(Rval2Instr),
+ ( get_last_instr_opand(Rval2Instr, LastOp) ->
+ Rval2Op = LastOp,
+ list.append(Rval1Instr, Rval2Instr, Instrs0)
+ ;
+ unexpected(this_file, "transform_rval:"
+ ++ " mem_addr(heap_ref): unexpected:"
+ ++ " get_last_instr_opand failed")
+ )
+ ;
+ Res3 = no,
+ unexpected(this_file, "transform_rval:"
+ ++ " mem_addr(heap_ref): unexpected: Rval2")
+ )
+ )
+ ;
+ unexpected(this_file, "transform_rval: mem_addr(heap_ref):"
+ ++ " unexpected: get_last_instr_opand failed")
+ )
+ ;
+ Res1 = no,
+ unexpected(this_file, "transform_rval: mem_addr(heap_ref)"
+ ++ " unexpected: Rval1")
+ )
+ ),
+ TempReg = operand_reg(gp_reg(13)),
+ ll_backend.x86_64_out.operand_type(Rval1Op, Rval1Str),
+ MemRef = operand_mem_ref(mem_abs(base_expr(Rval1Str))),
+ LoadAddr = x86_64_instr(lea(MemRef, TempReg)),
+ Instr0 = x86_64_instr(sub(Rval2Op, TempReg)),
+ Instr1 = x86_64_instr(add(operand_imm(imm32(int32(Tag))), TempReg)),
+ Instrs = yes(Instrs0 ++ [LoadAddr] ++ [Instr0] ++ [Instr1]).
+
+ % x86_64 instructions for binary operation with either an operand or an
+ % expression (given as a list of x86_64 instructions) or a combination of
+ % both.
+ %
+:- pred binop_instrs(binop::in, binary_op::in, list(x86_64_instr)::out) is det.
+
+binop_instrs(binop_simple_opands(Op1, Op2), Op, Instrs) :-
+ binop_instr(Op, Op1, Op2, Instrs).
+binop_instrs(binop_simple_and_compound_opands(Op1, InstrsOp), Op, Instrs) :-
+ ( get_last_instr_opand(InstrsOp, LastOp) ->
+ binop_instr(Op, Op1, LastOp, Instrs0),
+ list.append(InstrsOp, Instrs0, Instrs)
+ ;
+ unexpected(this_file, "binop_instrs: binop_simple_and_compound_opands"
+ ++ " unexpected: get_last_instr_opand failed")
+ ).
+binop_instrs(binop_compound_and_simple_opands(InstrsOp, Op2), Op, Instrs) :-
+ ( get_last_instr_opand(InstrsOp, LastOp) ->
+ binop_instr(Op, LastOp, Op2, Instrs0),
+ list.append(InstrsOp, Instrs0, Instrs)
+ ;
+ unexpected(this_file, "binop_instrs: binop_compound_and_simple_opands:"
+ ++ " unexpected: get_last_instr_opand failed")
+ ).
+binop_instrs(binop_compound_opands(InstrsOp1, InstrsOp2), Op, Instrs) :-
+ (
+ get_last_instr_opand(InstrsOp1, LastOp1),
+ get_last_instr_opand(InstrsOp2, LastOp2)
+ ->
+ binop_instr(Op, LastOp1, LastOp2, Instrs0),
+ Instrs = InstrsOp1 ++ InstrsOp2 ++ Instrs0
+ ;
+ unexpected(this_file, "binop_instrs: binop_compound_opands: unexpected:"
+ ++ " get_last_instr_opand failed")
+ ).
+
+ % Equivalent x86_64 instructions for a unary operation. A unary operation
+ % may consist of an operand or an expression (as a list of x86_64
+ % instructions).
+ %
+:- pred unop_instrs(backend_libs.builtin_ops.unary_op::in, maybe(operand)::in,
+ maybe(list(x86_64_instr))::in, list(x86_64_instr)::out) is det.
+
+unop_instrs(mktag, _, _, [x86_64_comment("<<mktag>>")]).
+unop_instrs(tag, _, _, [x86_64_comment("<<tag>>")]).
+unop_instrs(unmktag, _, _, [x86_64_comment("<<unmktag>>")]).
+unop_instrs(strip_tag, _, _, [x86_64_comment("<<strip_tag>>")]).
+unop_instrs(mkbody, _, _, [x86_64_comment("<<mkbody>>")]).
+unop_instrs(unmkbody, _, _, [x86_64_comment("<<unmkbody>>")]).
+unop_instrs(hash_string, _, _, [x86_64_comment("<<hash_string>>")]).
+unop_instrs(bitwise_complement, Op, Instrs0, Instrs) :-
+ (
+ Op = yes(OpRes),
+ Instrs = [x86_64_instr(x86_64_instr_not(OpRes))]
+ ;
+ Op = no,
+ (
+ Instrs0 = yes(InsRes),
+ ( get_last_instr_opand(InsRes, LastOp) ->
+ list.append(InsRes, [x86_64_instr(x86_64_instr_not(LastOp))],
+ Instrs)
+ ;
+ unexpected(this_file, "unop_instrs: bitwise_complement:"
+ ++ " unexpected: get_last_instr_opand failed")
+ )
+ ;
+ Instrs0 = no,
+ unexpected(this_file, "unop_instrs: bitwise_complement:"
+ ++ " unexpected: instruction operand Instrs0")
+ )
+ ).
+unop_instrs(logical_not, _, _, [x86_64_comment("<<logical_not>>")]).
+
+ % Equivalent x86_64 instructions for a binary operation.
+ %
+:- pred binop_instr(backend_libs.builtin_ops.binary_op::in, operand::in,
+ operand::in, list(x86_64_instr)::out) is det.
+
+binop_instr(int_add, Op1, Op2, [x86_64_instr(add(Op1, Op2))]).
+binop_instr(int_sub, Op1, Op2, [x86_64_instr(sub(Op1, Op2))]).
+binop_instr(int_mul, Op1, Op2, [x86_64_instr(imul(Op1, yes(Op2), no))]).
+binop_instr(int_mod, _, _, [x86_64_comment("<<int_mod>>")]).
+binop_instr(int_div, Op1, Op2, Instrs) :-
+ LoadDividend = x86_64_instr(mov(Op2, operand_label("<<int_div>>"))),
+ list.cons(LoadDividend, [x86_64_instr(idiv(Op1))], Instrs).
+binop_instr(unchecked_left_shift, Op1, Op2, [x86_64_instr(shl(Op1, Op2))]).
+binop_instr(unchecked_right_shift, Op1, Op2, [x86_64_instr(shr(Op1, Op2))]).
+binop_instr(bitwise_and, Op1, Op2, [x86_64_instr(and(Op1, Op2))]).
+binop_instr(bitwise_or, _, _, [x86_64_comment("<<bitwise_or>>")]).
+binop_instr(bitwise_xor, Op1, Op2, [x86_64_instr(xor(Op1, Op2))]).
+binop_instr(logical_and, _, _, [x86_64_comment("<<logical_and>>")]).
+binop_instr(logical_or, _, _, [x86_64_comment("<<logical_or>>")]).
+binop_instr(eq, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(ne, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(body, _, _, [x86_64_comment("<<body>>")]).
+binop_instr(array_index(_), _, _, [x86_64_comment("<<array_index>>")]).
+binop_instr(str_eq, _, _, [x86_64_comment("<<str_eq>>")]).
+binop_instr(str_ne, _, _, [x86_64_comment("<<str_ne>>")]).
+binop_instr(str_lt, _, _, [x86_64_comment("<<str_lt>>")]).
+binop_instr(str_gt, _, _, [x86_64_comment("<<str_gt>>")]).
+binop_instr(str_le, _, _, [x86_64_comment("<<str_le>>")]).
+binop_instr(str_ge, _, _, [x86_64_comment("<<str_ge>>")]).
+binop_instr(int_lt, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(int_gt, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(int_le, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(int_ge, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(unsigned_le, Op1, Op2, [x86_64_instr(cmp(Op1, Op2))]).
+binop_instr(float_plus, _, _, [x86_64_comment("<<float_plus>>")]).
+binop_instr(float_minus, _, _, [x86_64_comment("<<float_minus>>")]).
+binop_instr(float_times, _, _, [x86_64_comment("<<float_times>>")]).
+binop_instr(float_divide, _, _, [x86_64_comment("<<float_divide>>")]).
+binop_instr(float_eq, _, _, [x86_64_comment("<<float_eq>>")]).
+binop_instr(float_ne, _, _, [x86_64_comment("<<float_ne>>")]).
+binop_instr(float_lt, _, _, [x86_64_comment("<<float_lt>>")]).
+binop_instr(float_gt, _, _, [x86_64_comment("<<float_gt>>")]).
+binop_instr(float_le, _, _, [x86_64_comment("<<float_le>>")]).
+binop_instr(float_ge, _, _, [x86_64_comment("<<float_ge>>")]).
+
+ % Get a string representation of code address types.
+ %
+:- pred code_addr_type(code_addr::in, string::out) is det.
+
+code_addr_type(code_label(Label), CodeAddr) :-
+ CodeAddr = "$" ++ ll_backend.llds_out.label_to_c_string(Label, no).
+code_addr_type(code_imported_proc(ProcLabel), CodeAddr) :-
+ CodeAddr = "$" ++
+ backend_libs.name_mangle.proc_label_to_c_string(ProcLabel, no).
+code_addr_type(code_succip, CodeAddr) :-
+ CodeAddr = "<<code_succip>>".
+code_addr_type(do_succeed(_), CodeAddr) :-
+ CodeAddr = "<<do_succeed>>".
+code_addr_type(do_redo, CodeAddr) :-
+ CodeAddr = "<<do_redo>>".
+code_addr_type(do_fail, CodeAddr) :-
+ CodeAddr = "<<do_fail>>".
+code_addr_type(do_trace_redo_fail_shallow, CodeAddr) :-
+ CodeAddr = "<<do_trace_redo_fail_shallow>>".
+code_addr_type(do_trace_redo_fail_deep, CodeAddr) :-
+ CodeAddr = "<<do_trace_redo_fail_deep>>".
+code_addr_type(do_call_closure(_), CodeAddr) :-
+ CodeAddr = "<<do_call_closure>>".
+code_addr_type(do_call_class_method(_), CodeAddr) :-
+ CodeAddr = "<<do_call_class_method>>".
+code_addr_type(do_not_reached, CodeAddr) :-
+ CodeAddr = "<<do_not_reached>>".
+
+ % Given a list of x86_64 instructions, figure out the operand of the last
+ % instruction in the list.
+ %
+:- pred get_last_instr_opand(list(x86_64_instr)::in, operand::out) is semidet.
+
+get_last_instr_opand(Instrs, Op) :-
+ list.last_det(Instrs, LastInstr),
+ (
+ LastInstr = x86_64_comment(Comment),
+ Op = operand_label(Comment)
+ ;
+ LastInstr = x86_64_label(Label),
+ Op = operand_label(Label)
+ ;
+ LastInstr = x86_64_instr(Instr),
+ last_instr_dest(Instr, Op)
+ ;
+ LastInstr = x86_64_directive(_),
+ Op = operand_label("<<directive>>")
+ ).
+
+ % Destination operand of an x86_64_instruction.
+ %
+:- pred last_instr_dest(x86_64_inst::in, operand::out) is semidet.
+
+last_instr_dest(adc(_, Dest), Dest).
+last_instr_dest(add(_, Dest), Dest).
+last_instr_dest(and(_, Dest), Dest).
+last_instr_dest(bs(_, Dest, _), Dest).
+last_instr_dest(bswap(Dest), Dest).
+last_instr_dest(cmov(_, Dest, _), Dest).
+last_instr_dest(cmp(_, Dest), Dest).
+last_instr_dest(cmpxchg(_, Dest), Dest).
+last_instr_dest(cmpxchg8b(Dest), Dest).
+last_instr_dest(dec(Dest), Dest).
+last_instr_dest(div(Dest), Dest).
+last_instr_dest(idiv(Dest), Dest).
+last_instr_dest(imul(_, yes(Dest), _), Dest).
+last_instr_dest(inc(Dest), Dest).
+last_instr_dest(jrcxz(Dest), Dest).
+last_instr_dest(jmp(Dest), Dest).
+last_instr_dest(lea(_, Dest), Dest).
+last_instr_dest(loop(Dest), Dest).
+last_instr_dest(loope(Dest), Dest).
+last_instr_dest(loopne(Dest), Dest).
+last_instr_dest(loopnz(Dest), Dest).
+last_instr_dest(loopz(Dest), Dest).
+last_instr_dest(mov(_, Dest), Dest).
+last_instr_dest(mul(Dest), Dest).
+last_instr_dest(x86_64_instr_not(Dest), Dest).
+last_instr_dest(or(_, Dest), Dest).
+last_instr_dest(pop(Dest), Dest).
+last_instr_dest(push(Dest), Dest).
+last_instr_dest(rc(_, Dest, _), Dest).
+last_instr_dest(ro(_, Dest, _), Dest).
+last_instr_dest(sal(_, Dest), Dest).
+last_instr_dest(shl(_, Dest), Dest).
+last_instr_dest(sar(_, Dest), Dest).
+last_instr_dest(sbb(_, Dest), Dest).
+last_instr_dest(set(Dest, _), Dest).
+last_instr_dest(shr(_, Dest), Dest).
+last_instr_dest(sub(_, Dest), Dest).
+last_instr_dest(xadd(_, Dest), Dest).
+last_instr_dest(xor(_, Dest), Dest).
+
+ % Get a string representation of llds labels.
+ %
+:- pred labels_to_string(list(label)::in, string::in, string::out) is det.
+
+labels_to_string([], Str, Str).
+labels_to_string([Label | Labels], Str0, Str) :-
+ LabelStr = ll_backend.llds_out.label_to_c_string(Label, no),
+ labels_to_string(Labels, Str0 ++ LabelStr, Str).
+
+%----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "llds_to_x86_64.m".
+
+%----------------------------------------------------------------------------%
+:- end_module llds_to_x86_64.
+%----------------------------------------------------------------------------%
Index: compiler/llds_to_x86_64_out.m
===================================================================
RCS file: compiler/llds_to_x86_64_out.m
diff -N compiler/llds_to_x86_64_out.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/llds_to_x86_64_out.m 2 Feb 2007 02:20:46 -0000
@@ -0,0 +1,58 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: llds_to_x86_64_out.m.
+% Main author: fhandoko.
+%
+% This module defines the routines for printing out instructions produced by
+% llds->x86_64 asm generator.
+%
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.llds_to_x86_64_out.
+:- interface.
+
+:- import_module ll_backend.x86_64_instrs.
+
+:- import_module io.
+:- import_module list.
+
+%-----------------------------------------------------------------------------%
+
+:- pred output_x86_64_asm(list(x86_64_procedure)::in, io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module ll_backend.llds_to_x86_64.
+:- import_module ll_backend.x86_64_out.
+
+output_x86_64_asm(AsmProcs, !IO) :-
+ output_asm_proc_list(AsmProcs, !IO).
+
+
+:- pred output_asm_proc_list(list(x86_64_procedure)::in, io::di, io::uo) is det.
+
+output_asm_proc_list([], !IO).
+output_asm_proc_list([AsmProc | AsmProcs], !IO) :-
+ output_asm_instr_list(AsmProc ^ x86_64_code, !IO),
+ output_asm_proc_list(AsmProcs, !IO).
+
+:- pred output_asm_instr_list(list(x86_64_instruction)::in, io::di, io::uo)
+ is det.
+
+output_asm_instr_list([], !IO).
+output_asm_instr_list([AsmInstr | AsmInstrs], !IO) :-
+ output_x86_64_instruction(AsmInstr, !IO),
+ output_asm_instr_list(AsmInstrs, !IO).
+
+%----------------------------------------------------------------------------%
+:- end_module llds_to_x86_64_out.
+%----------------------------------------------------------------------------%
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.426
diff -u -r1.426 mercury_compile.m
--- compiler/mercury_compile.m 23 Jan 2007 03:45:34 -0000 1.426
+++ compiler/mercury_compile.m 31 Jan 2007 23:46:04 -0000
@@ -122,6 +122,12 @@
:- import_module bytecode_backend.bytecode_gen.
:- import_module bytecode_backend.bytecode.
+ % The x86_64 asm back-end.
+ %
+:- import_module ll_backend.llds_to_x86_64.
+:- import_module ll_backend.llds_to_x86_64_out.
+:- import_module ll_backend.x86_64_instrs.
+
% the MLDS back-end
:- import_module ml_backend.add_trail_ops. % HLDS -> HLDS
:- import_module ml_backend.add_heap_ops. % HLDS -> HLDS
@@ -1639,12 +1645,16 @@
)
;
Target = target_x86_64,
- backend_pass(!HLDS, GlobalData, LLDS, !DumpInfo, !IO),
+% backend_pass(!HLDS, GlobalData, LLDS, !DumpInfo, !IO),
+ backend_pass(!HLDS, _, LLDS, !DumpInfo, !IO),
% XXX Eventually we will call the LLDS->x86_64 asm code
% generator here and then output the assembler. At the moment
% we just output the LLDS as C code.
- output_pass(!.HLDS, GlobalData, LLDS, ModuleName,
- _CompileErrors, _, !IO),
+ llds_to_x86_64_asm(!.HLDS, LLDS, X86_64_Asm),
+ output_x86_64_asm(X86_64_Asm, !IO),
+ % need to output x86_64_Asm
+ %output_pass(!.HLDS, GlobalData, LLDS, ModuleName,
+ % _CompileErrors, _, !IO),
FactTableBaseFiles = []
),
recompilation.usage.write_usage_file(!.HLDS, NestedSubModules,
Index: compiler/x86_64_instrs.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_instrs.m,v
retrieving revision 1.1
diff -u -r1.1 x86_64_instrs.m
--- compiler/x86_64_instrs.m 15 Jan 2007 22:49:41 -0000 1.1
+++ compiler/x86_64_instrs.m 5 Feb 2007 05:11:15 -0000
@@ -16,24 +16,79 @@
:- module ll_backend.x86_64_instrs.
:- interface.
+:- import_module hlds.hlds_pred.
+:- import_module hlds.code_model.
+:- import_module ll_backend.llds.
+:- import_module mdbcomp.prim_data.
+
+:- import_module counter.
:- import_module list.
:- import_module maybe.
+:- import_module set.
+
+%-----------------------------------------------------------------------------%
+
+ % We turn a llds.c_file into this.
+ %
+:- type x86_64_module
+ ---> x86_64_module(
+ x86_64_modulename :: module_name,
+ % The name of this x86_64 module.
+ x86_64_procs :: list(list(x86_64_procedure))
+ % The code.
+ ).
+
+:- func init_x86_64_module(module_name) = x86_64_module.
+
+:- func init_x86_64_proc(c_procedure) = x86_64_procedure.
+
+:- func init_x86_64_instruction = x86_64_instruction.
+
+%-----------------------------------------------------------------------------%
+
+ % We turn an llds.c_procedure into one of these.
+ % XXX Do we really need to replicate all these fields from the llds?
+ %
+:- type x86_64_procedure
+ ---> x86_64_procedure(
+ x86_64_name :: string,
+ % Predicate name.
+ x86_64_arity :: int,
+ % Original arity.
+ x86_64_id :: pred_proc_id,
+ % The pred_proc_id of this code.
+ x86_64_code_model :: code_model,
+ % The code model of the procedure.
+ x86_64_code :: list(x86_64_instruction),
+ % The code for this procedure.
+ x86_64_proc_label :: proc_label,
+ % Proc_label of this procedure.
+ x86_64_label_nums :: counter,
+ x86_64_may_alter_rtti :: may_alter_rtti,
+ % The compiler is allowed to perform
+ % optimizations on this procedure
+ % that could alter RTTI information
+ % (e.g. the set of variables live at
+ % a label) only if this field is set
+ % to `may_alter_rtti'.
+ x86_64_c_global_vars :: set(string)
+ ).
%-----------------------------------------------------------------------------%
:- type x86_64_instruction
---> x86_64_instr(
- x86_64_instr_name :: x86_64_op,
- x86_64_comment :: string
+ x86_64_inst :: list(x86_64_instr),
+ x86_64_inst_comment :: string
).
:- type label_name == string.
:- type x86_64_instr
- ---> comment(string)
- ; label(label_name)
- ; directives(list(pseudo_op))
- ; instrs(list(x86_64_instruction)).
+ ---> x86_64_comment(string)
+ ; x86_64_label(label_name)
+ ; x86_64_directive(pseudo_op)
+ ; x86_64_instr(x86_64_inst).
%-----------------------------------------------------------------------------%
@@ -49,6 +104,47 @@
:- type uint16 ---> uint16(int). % In bottom 16 bits.
:- type uint32 ---> uint32(int). % In bottom 32 bits.
+%-----------------------------------------------------------------------------%
+
+ % Conditional direction.
+ %
+:- type direction
+ ---> f % Forward.
+ ; r. % Reverse.
+
+ % Condition of flags register.
+ %
+:- type condition
+ ---> o % Overflow (OF = 1).
+ ; no % Not Overflow (OF = 0).
+ ; b % Below (CF = 1).
+ ; c % Carry (CF = 1).
+ ; nae % Not Above or Equal (CF = 1).
+ ; nb % Not Below (CF = 0).
+ ; nc % Not Carry (CF = 0).
+ ; ae % Above or Equal (CF = 0).
+ ; z % Zero (ZF = 1).
+ ; e % Equal (ZF = 1).
+ ; nz % Not Zero (ZF = 0).
+ ; ne % Not Equal (ZF = 0).
+ ; be % Below or Equal (CF = 1 or ZF = 1).
+ ; na % Not Above (CF = 1 or ZF = 1).
+ ; nbe % Not Below or Equal (CF = 0 or ZF = 0).
+ ; a % Above (CF = 0 or ZF = 0).
+ ; s % Sign (SF = 1).
+ ; ns % Not Sign (SF = 0).
+ ; p % Parity (PF = 1).
+ ; pe % Parity even (PF = 1).
+ ; np % Not parity (PF = 0).
+ ; po % Parity odd (PF = 0).
+ ; l % Less (SF <> OF).
+ ; nge % Not Greater or Equal (SF <> OF).
+ ; nl % Not Less (SF = OF).
+ ; ge % Greater or Equal (SF = OF).
+ ; le % Less or Equal (ZF = 1 or SF <> OF).
+ ; ng % Not Greater (ZF = 1 or SF <> OF).
+ ; nle % Not Less or Equal (ZF = 0 and SF = OF).
+ ; g. % Greater (ZF = 0 and SF = OF).
%-----------------------------------------------------------------------------%
%
@@ -136,7 +232,7 @@
; eject
% Force a page break.
- ; else_
+ ; x86_64_pseudo_else
% As in 'if-then-else' conditional expression.
; elseif
@@ -239,7 +335,7 @@
; ident
% To place tags in object files.
- ; if_(
+ ; x86_64_pseudo_if(
if_expr :: string
)
% Mark the beginning of a conditional section.
@@ -520,7 +616,7 @@
)
% Use 'title_heading' as the title when generating assembly listing.
- ; type_(
+ ; x86_64_pseudo_type(
type_name :: string,
type_desc :: string
)
@@ -571,22 +667,7 @@
% Details on amd64-prog-man-vol1 manual p27.
%
:- type gp_reg
- ---> rax
- ; rbx
- ; rcx
- ; rdx
- ; rbp
- ; rsi
- ; rdi
- ; rsp
- ; r8
- ; r9
- ; r10
- ; r11
- ; r12
- ; r13
- ; r14
- ; r15.
+ ---> gp_reg(int).
% 64-bit instruction pointer register on the x86_64. Instruction pointer
% RIP is used as a base register for relative addressing. x86_64
@@ -622,7 +703,7 @@
% or an instruction-relative address.
% Details on amd64-prog-man-vol1 p19.
%
-:- type mem_ref
+:- type x86_64_mem_ref
---> mem_abs(
mem_abs_address :: base_address
)
@@ -650,35 +731,14 @@
:- type operand
---> operand_reg(gp_reg)
; operand_imm(imm_operand)
- ; operand_mem_ref(mem_ref).
-
+ ; operand_mem_ref(x86_64_mem_ref)
+ ; operand_rel_offset(rel_offset)
+ ; operand_label(string).
%
% Subtypes of the operand type.
% XXX maybe we should use inst-subtyping for these?
%
-
- % x86_64_instruction's operand is either the content a general-purpose
- % register or the content of a memory reference.
- %
-:- type reg_or_mem_ref_op
- ---> rmro_reg(gp_reg)
- ; rmro_mem_ref(mem_ref).
-
- % x86_64_instruction's operand is either the contents of a general-purpose
- % register or the value of an immediate operand.
- %
-:- type reg_or_imm_op
- ---> rio_reg(gp_reg)
- ; rio_imm(imm_operand).
-
- % x86_64_instruction's operand is either the content of CL register (the
- % bottom 16 bits of RCX register) or an 8-bit immediate value.
- %
-:- type cl_reg_or_imm_op
- ---> crio_reg_cl(gp_reg)
- ; crio_imm8(int8).
-
% x86_64 instruction's operand is an offset relative to the instruction
% pointer.
%
@@ -692,7 +752,7 @@
%
:- type rmrol
---> rmrol_reg(gp_reg)
- ; rmrol_mem_ref(mem_ref)
+ ; rmrol_mem_ref(x86_64_mem_ref)
; rmrol_rel_offset(rel_offset)
; rmrol_label(
rmrol_label_name :: string
@@ -706,83 +766,101 @@
% We use At&T style instructions where the source comes before the
% destination.
%
-:- type x86_64_op
+:- type x86_64_inst
---> adc(
adc_src :: operand,
- adc_dst :: reg_or_mem_ref_op
+ % immediate, register or memory location
+ adc_dst :: operand
+ % register or memory location
)
% Add with carry. Add 'adc_src' to 'adc_dst' + carry flag (CF).
+ % Cannot add two memory operands.
% Details on amd64-prog-man-vol3 manual p65.
; add(
add_src :: operand,
- add_dst :: reg_or_mem_ref_op
+ % immediate, register or memory location
+ add_dst :: operand
+ % register or memory location
)
% Signed or unsigned add. Add 'adc_src' to 'adc_dst'.
+ % Cannot add two memory operands.
% Details on amd64-prog-man-vol3 manual p67.
; and(
and_src :: operand,
- and_dst :: reg_or_mem_ref_op
+ % immediate, register or memory location
+ and_dst :: operand
+ % register or memory location
)
% Performs a bitwise AND operation on both operands.
+ % Cannot and two memory operands.
% Details on amd64-prog-man-vol3 manual p69.
- ; bsf(
- bsf_src :: reg_or_mem_ref_op,
- bsf_dst :: gp_reg
- )
- % Bit scan forward. Searches the value in 'bsf_src' for the least
- % significant set bit.
- % Details on amd64-prog-man-vol3 manual p74.
-
- ; bsr(
- bsr_src :: reg_or_mem_ref_op,
- bsr_dst :: gp_reg
- )
- % Bit scan reverse. Searches the value in 'bsf_src' for the most
- % significant set bit.
- % Details on amd64-prog-man-vol3 manual p75.
+ ; bs(
+ bs_src :: operand,
+ % register or memory location
+ bs_dst :: operand,
+ % register
+ bs_cond :: direction
+ % "F" for forward, "R" for reverse"
+ )
+ % Bit scan. Searches the value in 'bs_src' for the least
+ % significant set bit if 'bs_cond' is "F". Searches
+ % for the most significant set bit if 'bs_cond' is "R".
+ % Details on amd64-prog-man-vol3 manual p(74-75).
- ; bswap(gp_reg)
- % Byte swap. Reverses the byte order of the specified 'gp_reg'.
+ ; bswap(
+ bswap_reg :: operand
+ )
+ % Byte swap. Reverses the byte order of the specified 'operand'.
% Details on amd64-prog-man-vol3 manual p76.
; bt(
- bt_src :: reg_or_mem_ref_op,
- bt_idx :: reg_or_imm_op
+ bt_src :: operand,
+ % register or memory reference
+ bt_idx :: operand
+ % register or 8-bit immediate value
)
% Bit test. Copies a bit specified by 'bt_idx' from a bit string in
% 'bt_src' to the carry flag (CF) or RFLAGS register.
% Details on amd64-prog-man-vol3 manual p77.
; btc(
- btc_src :: reg_or_mem_ref_op,
- btc_idx :: reg_or_imm_op
+ btc_src :: operand,
+ % register or memory reference
+ btc_idx :: operand
+ % register or 8-bit immediate value
)
% Bit test and complement. Complements 'btc_src' after performing
% 'bt' operation.
% Details on amd64-prog-man-vol3 manual p79.
; btr(
- btr_src :: reg_or_mem_ref_op,
- btr_idx :: reg_or_imm_op
+ btr_src :: operand,
+ % register or memory reference
+ btr_idx :: operand
+ % register or 8-bit immediate value
)
% Bit test and reverse. Clears 'btr_src' to 0 after performing 'bt'
% operation.
% Details on amd64-prog-man-vol3 manual p81.
; bts(
- bts_src :: reg_or_mem_ref_op,
- bts_idx :: reg_or_imm_op
+ bts_src :: operand,
+ % register or memory reference
+ bts_idx :: operand
+ % register or 8-bit immediate value
)
% Bit test and set. Sets 'bts_src' to 1 after performing 'bt'
% operation.
% Details on amd64-prog-man-vol3 manual p83.
- ; call(rmrol)
- % Call with target specified by 'rmrol': register, memory location,
- % relative offset or a label.
+ ; call(
+ call_target :: operand
+ % label, register, memory reference or rel offset
+ )
+ % Call with target specified by call_target
% Details on amd64-prog-man-vol3 manual p85.
; cbw
@@ -821,241 +899,54 @@
% Complements the carry flag bit (CF) bit in the rFLAGS register.
% Details on amd64-prog-man-vol3 manual p100.
- ; cmovo(
- cmovo_src :: reg_or_mem_ref_op,
- cmovo_dest :: gp_reg
- )
- % Moves if overflow (OF = 1).
- % Details on amd64-prog-man-vol3 manual p101.
-
- ; cmovno(
- cmovno_src :: reg_or_mem_ref_op,
- cmovno_dest :: gp_reg
- )
- % Moves if not overflow (OF = 0).
- % Details on amd64-prog-man-vol3 manual p101.
-
- ; cmovb(
- cmovb_src :: reg_or_mem_ref_op,
- cmovb_dest :: gp_reg
- )
- % Moves if below (CF = 1).
- % Details on amd64-prog-man-vol3 manual p101.
-
- ; cmovc(
- cmovc_src :: reg_or_mem_ref_op,
- cmovc_dest :: gp_reg
- )
- % Moves if carry (CF = 1).
- % Details on amd64-prog-man-vol3 manual p101.
-
- ; cmovnae(
- cmovnae_src :: reg_or_mem_ref_op,
- cmovnae_dest :: gp_reg
- )
- % Moves if not above or equal (CF = 1).
- % Details on amd64-prog-man-vol3 manual p101.
-
- ; cmovnb(
- cmovnb_src :: reg_or_mem_ref_op,
- cmovnb_dest :: gp_reg
- )
- % Moves if not below (CF = 0).
- % Details on amd64-prog-man-vol3 manual p101.
-
- ; cmovnc(
- cmovnc_src :: reg_or_mem_ref_op,
- cmovnc_dest :: gp_reg
- )
- % Moves if not carry (CF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovae(
- cmovae_src :: reg_or_mem_ref_op,
- cmovae_dest :: gp_reg
- )
- % Moves if above or equal (CF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovz(
- cmovz_src :: reg_or_mem_ref_op,
- cmovz_dest :: gp_reg
- )
- % Moves if zero (ZF = 1).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmove(
- cmove_src :: reg_or_mem_ref_op,
- cmove_dest :: gp_reg
- )
- % Moves if equal (ZF = 1).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovnz(
- cmovnz_src :: reg_or_mem_ref_op,
- cmovnz_dest :: gp_reg
- )
- % Moves if not zero (ZF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovne(
- cmovne_src :: reg_or_mem_ref_op,
- cmovne_dest :: gp_reg
- )
- % Moves if not equal (ZF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovbe(
- cmovbe_src :: reg_or_mem_ref_op,
- cmovbe_dest :: gp_reg
- )
- % Moves if below or equal (CF = 1 or ZF = 1).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovna(
- cmovna_src :: reg_or_mem_ref_op,
- cmovna_dest :: gp_reg
- )
- % Moves if not above (CF = 1 or ZF = 1).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovnbe(
- cmovnbe_src :: reg_or_mem_ref_op,
- cmovnbe_dest :: gp_reg
- )
- % Moves if not below or equal (CF = 0 or ZF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmova(
- cmova_src :: reg_or_mem_ref_op,
- cmova_dest :: gp_reg
- )
- % Moves if above (CF = 1 or ZF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovs(
- cmovs_src :: reg_or_mem_ref_op,
- cmovs_dest :: gp_reg
- )
- % Moves if sign (SF = 1).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovns(
- cmovns_src :: reg_or_mem_ref_op,
- cmovns_dest :: gp_reg
- )
- % Moves if not sign (SF = 0).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovp(
- cmovp_src :: reg_or_mem_ref_op,
- cmovp_dest :: gp_reg
- )
- % Moves if parity (PF = 1).
- % Details on amd64-prog-man-vol3 manual p102.
-
- ; cmovpe(
- cmovpe_src :: reg_or_mem_ref_op,
- cmovpe_dest :: gp_reg
- )
- % Moves if parity even (PF = 1).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovnp(
- cmovnp_src :: reg_or_mem_ref_op,
- cmovnp_dest :: gp_reg
- )
- % Moves if not parity (PF = 0).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovpo(
- cmovpo_src :: reg_or_mem_ref_op,
- cmovpo_dest :: gp_reg
- )
- % Moves if parity odd (PF = 0).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovl(
- cmovl_src :: reg_or_mem_ref_op,
- cmovl_dest :: gp_reg
- )
- % Moves if less (SF <> OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovnge(
- cmovnge_src :: reg_or_mem_ref_op,
- cmovnge_dest :: gp_reg
- )
- % Moves if not greater or equal (SF <> OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovnl(
- cmovnl_src :: reg_or_mem_ref_op,
- cmovnl_dest :: gp_reg
- )
- % Moves if not less (SF = OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovge(
- cmovge_src :: reg_or_mem_ref_op,
- cmovge_dest :: gp_reg
- )
- % Moves if greater or equal (SF = OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovle(
- cmovle_src :: reg_or_mem_ref_op,
- cmovle_dest :: gp_reg
- )
- % Moves if less or equal (ZF = 1 or SF <> OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovng(
- cmovng_src :: reg_or_mem_ref_op,
- cmovng_dest :: gp_reg
- )
- % Moves if not greater (ZF = 1 or SF <> OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovnle(
- cmovnle_src :: reg_or_mem_ref_op,
- cmovnle_dest :: gp_reg
- )
- % Moves if not less or equal (ZF = 0 or SF = OF).
- % Details on amd64-prog-man-vol3 manual p103.
-
- ; cmovg(
- cmovg_src :: reg_or_mem_ref_op,
- cmovg_dest :: gp_reg
+ ; cmov(
+ cmov_src :: operand,
+ % memory or register
+ cmov_dest :: operand,
+ % register
+ cmov_cmp_op :: condition
)
- % Moves if greater (ZF = 0 or SF = OF).
- % Details on amd64-prog-man-vol3 manual p103.
+ % Moves with comparison operation defined in 'cmov_cmp_op'.
+ % Details on amd64-prog-man-vol3 manual p(101-103).
; cmp(
cmp_src :: operand,
- cmp_dest :: reg_or_mem_ref_op
+ % register, memory location or immediate value
+ cmp_dest :: operand
+ % register or memory location
)
% Compares 'cmp_src' with 'cmp_dest'.
% Details on amd64-prog-man-vol3 manual p105.
; cmpxchg(
- cmpxchg_cmp :: reg_or_mem_ref_op,
- cmpxchg_xchg :: gp_reg
+ cmpxchg_src :: operand,
+ % register or memory location
+ cmpxchg_dest :: operand
+ % register
)
- % Compares the value in RAX with the value in 'cmpxchg_cmp'.
- % If equal, copies the value in 'cmpxchg_xchg' to 'cmpxchg_cmp'.
+ % Compares the value in RAX with the value in 'cmpxchg_dest'.
+ % If equal, copies the value in 'cmpxchg_src' to 'cmpxchg_dest'.
% Details on amd64-prog-man-vol3 manual p111.
- ; cmpxchg8b(mem_ref)
+ ; cmpxchg8b(
+ cmpxchg8b_mem :: operand
+ % memory reference
+ )
% Compares the value in EDX:EAX with the value in 'mem_ref'.
% Details on amd64-prog-man-vol3 manual p113.
- ; dec(reg_or_mem_ref_op)
- % Decrements the contents of 'reg_or_mem_ref_op'.
+ ; dec(
+ dec_op :: operand
+ % register or memory reference
+ )
+ % Decrements the contents of 'dec_op'.
% Details on amd64-prog-man-vol3 manual p120.
- ; div(reg_or_mem_ref_op)
- % Unsigned divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
+ ; div(
+ div_op :: operand
+ % register or memory reference
+ )
+ % Unsigned divide RDX:RAX by the value in 'div_op'.
% Details on amd64-prog-man-vol3 manual p122.
; enter(
@@ -1067,166 +958,57 @@
% 'enter_nesting_level'(0 to 31).
% Details on amd64-prog-man-vol3 manual p124.
- ; idiv(reg_or_mem_ref_op)
- % Signed divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
+ ; idiv(
+ idiv_op :: operand
+ % register or memory reference
+ )
+ % Signed divide RDX:RAX by the value in 'operand'.
% Details on amd64-prog-man-vol3 manual p126.
- ; imul(reg_or_mem_ref_op)
- % Signed multiply RAX by the value in 'reg_or_mem_ref_op'.
- % Details on amd64-prog-man-vol3 manual p128.
-
; imul(
- imul1_src :: reg_or_mem_ref_op,
- imul1_dest :: gp_reg
+ imul_src :: operand,
+ % register, memory location, immediate value
+ imul_dest :: maybe(operand),
+ % register
+ imul_multiplicand :: maybe(operand)
+ )
+ % Signed multiply 'imul_src' by 'imul_dest' (if specified).
+ % Otherwise multiply 'imul_src' by the value in RAX register.
+ % Details on amd64-prog-man-vol3 manual p(128-129).
+
+ ; inc(
+ inc_op :: operand
+ % register or memory location
)
- % Signed multiply 'imul1_src' by 'imul1_dest'.
- % Details on amd64-prog-man-vol3 manual p129.
+ % Increments the contents of 'inc_op'.
+ % Details on amd64-prog-man-vol3 manual p133.
- ; imul(
- imul2_src :: reg_or_mem_ref_op,
- imul2_multiplicand :: imm_operand,
- imul2_dest :: gp_reg
+ ; j(
+ j_target :: operand,
+ % relative offset
+ j_condition :: condition
)
- % Signed multiply 'imul2_src' by 'imul2_multiplicand'.
- % Details on amd64-prog-man-vol3 manual p129.
+ % Conditional jump.
+ % Details on amd64-prog-man-vol3 manual p(147-149).
- ; inc(reg_or_mem_ref_op)
- % Increments the contents of 'reg_or_mem_ref_op'.
- % Details on amd64-prog-man-vol3 manual p133.
-
- ; jo(rel_offset)
- % Jumps if overflow (OF = 1).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jno(rel_offset)
- % Jumps if not overflow (OF = 0).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jb(rel_offset)
- % Jumps if below (CF = 1).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jc(rel_offset)
- % Jumps if carry (CF = 1).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jnae(rel_offset)
- % Jumps if not above or equal (CF = 1).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jnb(rel_offset)
- % Jumps if not below (CF = 0).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jnc(rel_offset)
- % Jumps if not carry (CF = 0).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jae(rel_offset)
- % Jumps if above or equal (CF = 0).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jz(rel_offset)
- % Jumps if zero (ZF = 1).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; je(rel_offset)
- % Jumps if equal (ZF = 1).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jnz(rel_offset)
- % Jumps if not zero (ZF = 0).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jne(rel_offset)
- % Jumps if not equal (ZF = 0).
- % Details on amd64-prog-man-vol3 manual p147.
-
- ; jbe(rel_offset)
- % Jumps if below or equal (CF = 1 or ZF = 1).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jna(rel_offset)
- % Jumps if not above (CF = 1 or ZF = 1).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jnbe(rel_offset)
- % Jumps if not below or equal (CF = 0 or ZF = 0).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; ja(rel_offset)
- % Jumps if above (CF = 0 or ZF = 0).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; js(rel_offset)
- % Jumps if sign (SF = 1).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jns(rel_offset)
- % Jumps if not sign (SF = 0).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jp(rel_offset)
- % Jumps if parity (PF = 1).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jpe(rel_offset)
- % Jumps if parity even (PF = 1).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jnp(rel_offset)
- % Jumps if not parity (PF = 0).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jpo(rel_offset)
- % Jumps if parity odd (PF = 0).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jl(rel_offset)
- % Jumps if less (SF <> OF).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jnge(rel_offset)
- % Jumps if not greater or equal (SF <> OF).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jnl(rel_offset)
- % Jumps if not less (SF = OF).
- % Details on amd64-prog-man-vol3 manual p148.
-
- ; jge(rel_offset)
- % Jumps if greater or equal (SF = OF).
- % Details on amd64-prog-man-vol3 manual p149.
-
- ; jle(rel_offset)
- % Jumps if less or equal (ZF = 1 or SF <> OF).
- % Details on amd64-prog-man-vol3 manual p149.
-
- ; jng(rel_offset)
- % Jumps if not greater (ZF = 1 or SF <> OF).
- % Details on amd64-prog-man-vol3 manual p149.
-
- ; jnle(rel_offset)
- % Jumps if not less or equal (ZF = 0 and SF = OF).
- % Details on amd64-prog-man-vol3 manual p149.
-
- ; jg(rel_offset)
- % Jumps if greater (ZF = 0 and SF = OF).
- % Details on amd64-prog-man-vol3 manual p149.
-
- ; jrcxz(rel_offset)
- % Jumps to the target instruction located at the specified 8-bit
- % relative offset if RCX is zero.
+ ; jrcxz(
+ jrcxz_8bit_off :: operand
+ )
+ % Jumps to the target instruction located at 'jrcxz_8bit_off'
+ % if RCX is zero.
% Details on amd64-prog-man-vol3 manual p150.
- ; jmp(rmrol)
- % Jumps with target specified in 'rmrol': register, memory location,
- % relative offset or label.
+ ; jmp(
+ jmp_op :: operand
+ )
+ % Jumps with target specified in 'jmp_op'
% Details on amd64-prog-man-vol3 manual p152.
; lea(
- lea_src :: mem_ref,
- lea_dest :: gp_reg
+ lea_src :: operand,
+ % memory location
+ lea_dest :: operand
+ % register
)
% Stores effective address 'lea_src' into 'lea_dest'.
% Details on amd64-prog-man-vol3 manual p163.
@@ -1236,74 +1018,93 @@
% Details on amd64-prog-man-vol3 manual p164.
; loop(
- loop_rel_8bit :: rel_offset
+ loop_rel_8bit :: operand
)
% Decrements RCX then jump if RCX is not zero
% Details on amd64-prog-man-vol3 manual p169.
; loope(
- loope_rel_8bit :: rel_offset
+ loope_rel_8bit :: operand
)
% Decrements RCX then jump if RCX is not zero and ZF = 1.
% Details on amd64-prog-man-vol3 manual p169.
; loopne(
- loopne_rel_8bit :: rel_offset
+ loopne_rel_8bit :: operand
)
% Decrements RCX then jump if RCX is not zero and ZF = 0.
% Details on amd64-prog-man-vol3 manual p169.
; loopnz(
- loopnz_rel_8bit :: rel_offset
+ loopnz_rel_8bit :: operand
)
% Decrements RCX then jump if RCX is not zero and ZF = 0.
% Details on amd64-prog-man-vol3 manual p170.
; loopz(
- loopz_rel_8bit :: rel_offset
+ loopz_rel_8bit :: operand
)
% Decrements RCX then jump if RCX is not zero and ZF = 1.
% Details on amd64-prog-man-vol3 manual p170.
; mov(
mov_src :: operand,
- mov_dest :: reg_or_mem_ref_op
+ % register, memory location or immediate value
+ mov_dest :: operand
+ % register or memory location
)
- % Copies 'mov_src' to 'mov_dest'.
+ % Copies 'mov_src' to 'mov_dest'. 'mov_dest' cannot be immediate op.
% Details on amd64-prog-man-vol3 manual p173.
- ; mul(reg_or_mem_ref_op)
- % Unsigned multiply 'reg_or_mem_ref_op' by RAX.
+ ; mul(
+ mul_op :: operand
+ % register or memory location
+ )
+ % Unsigned multiply 'mul_op' by RAX.
% Details on amd64-prog-man-vol3 manual p190.
- ; neg(reg_or_mem_ref_op)
- % Performs a two's complement negation of 'reg_or_mem_ref_op'.
+ ; neg(
+ neg_op :: operand
+ % register or memory location
+ )
+ % Performs a two's complement negation of 'operand'.
% Details on amd64-prog-man-vol3 manual p192.
; nop
% Increments RIP to point to next instruction.
% Details on amd64-prog-man-vol3 manual p194.
- ; not_(reg_or_mem_ref_op)
- % Performs one's complement negation (NOT) of 'reg_or_mem_ref_op'.
+ ; x86_64_instr_not(
+ not_op :: operand
+ % register or memory location
+ )
+ % Performs one's complement negation (NOT) of 'operand'.
% Details on amd64-prog-man-vol3 manual p195.
; or(
or_src :: operand,
- or_dest :: reg_or_mem_ref_op
+ % register, memory location or immediate value
+ or_dest :: operand
+ % register or memory location
)
% Performs a logical OR on the bits in 'or_src' and 'or_dest'.
% Details on amd64-prog-man-vol3 manual p196.
- ; pop(reg_or_mem_ref_op)
- % Pops the stack into 'reg_or_mem_ref_op'.
+ ; pop(
+ pop_op :: operand
+ % register or memory location.
+ )
+ % Pops the stack into 'operand'.
% Details on amd64-prog-man-vol3 manual p204.
; popfq
% Pops a quadword from the stack to the RFLAGS register.
% Details on amd64-prog-man-vol3 manual p208.
- ; push(operand)
+ ; push(
+ push_op :: operand
+ % register, memory location or immediate value
+ )
% Pushes the content of operand onto the stack.
% Details on amd64-prog-man-vol3 manual p215.
@@ -1311,273 +1112,112 @@
% Pushes the RFLAGS quadword onto the stack.
% Details on amd64-prog-man-vol3 manual p218.
- ; ret
- % Near return to the calling procedure.
- % Details on amd64-prog-man-vol3 manual p224.
-
- ; rcl(
- rcl_amount :: cl_reg_or_imm_op,
- rcl_dest :: reg_or_mem_ref_op
- )
- % Rotate bits in 'rcl_dest' to the left and through the carry flag
- % by the number of bit positions as specified in 'rcl_amount'.
- % Details on amd64-prog-man-vol3 manual p220.
-
- ; rcr(
- rcr_amount :: cl_reg_or_imm_op,
- rcr_dest :: reg_or_mem_ref_op
- )
- % Rotate bits in 'rcr_dest' to the right and through the carry flag
- % by the number of bit positions as specified in 'rcr_amount'.
- % Details on amd64-prog-man-vol3 manual p222.
+ ; rc(
+ rc_amount :: operand,
+ % unsigned immediate value or register
+ rc_dest :: operand,
+ % register or memory location
+ rc_cond :: string
+ % "R" for right, "L" for left
+ )
+ % Rotate bits in 'rc_dest' according to 'rc_cond' direction
+ % and through the carry flag by the number of bit positions as
+ % specified in 'rc_amount'.
+ % Details on amd64-prog-man-vol3 manual p(220-222).
- ; ret(uint16)
+ ; ret(
+ ret_op :: maybe(uint16)
+ )
% Near return to the calling procedure, then pop the specified
- % number of bytes from stack.
+ % number of bytes from stack (if specified).
% Details on amd64-prog-man-vol3 manual p224.
- ; rol(
- rol_amount :: cl_reg_or_imm_op,
- rol_dest :: reg_or_mem_ref_op
- )
- % Rotates the bits of 'rol_dest' left by 'rol_amount' bits.
- % Details on amd64-prog-man-vol3 manual p230.
-
- ; ror(
- ror_amount :: cl_reg_or_imm_op,
- ror_dest :: reg_or_mem_ref_op
- )
- % Rotates the bits of 'ror_dest' right by 'ror_amount bits'.
- % Details on amd64-prog-man-vol3 manual p232.
+ ; ro(
+ ro_amount :: operand,
+ % unsigned immediate value or a register
+ ro_dest :: operand,
+ % register or memory location
+ ro_dir :: string
+ % "L" for left, "R" for right
+ )
+ % Rotates the bits of 'rol_dest' to the 'ro_dir' direction by
+ % 'rol_amount' bits.
+ % Details on amd64-prog-man-vol3 manual p(230-232).
; sal(
- sal_amount :: cl_reg_or_imm_op,
- sal_dest :: reg_or_mem_ref_op
+ sal_amount :: operand,
+ % unsigned immediate value or register
+ sal_dest :: operand
+ % register or memory location
)
% Shift 'sal_dest' left by 'sal_amount'.
% Details on amd64-prog-man-vol3 manual p235.
; shl(
- shl_amount :: cl_reg_or_imm_op,
- shl_dest :: reg_or_mem_ref_op
+ shl_amount :: operand,
+ % unsigned immediate value or register
+ shl_dest :: operand
+ % register or memory location
)
- % Shift 'shl_dest' left by 'shl_amount'.
+ % Alias to 'sal'.
% Details on amd64-prog-man-vol3 manual p235.
; sar(
- sar_amount :: cl_reg_or_imm_op,
- sar_dest :: reg_or_mem_ref_op
+ sar_amount :: operand,
+ % unsigned immediate value or register
+ sar_dest :: operand
+ % register or memory location
)
% Shift 'sar_dest' right by 'sar_amount'.
% Details on amd64-prog-man-vol3 manual p238.
; sbb(
sbb_src :: operand,
- sbb_dest :: reg_or_mem_ref_op
+ % immediate value, register or memory location
+ sbb_dest :: operand
+ % register or memory location
)
% Subtracts 'sbb_src' from 'sbb_dest' with borrow.
% Details on amd64-prog-man-vol3 manual p241.
- ; seto(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If overflow
- % (OF = 1), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setno(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not overflow
- % (OF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setb(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is below
- % (CF = 1), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setc(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is carry
- % (CF = 1), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setnae(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is not above
- % or equal (CF = 1), set the value in the specified register or an
- % 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setnb(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is not below
- % (CF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setnc(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is not carry
- % (CF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setae(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is above or
- % equal (CF = 0), set the value in the specified register or an
- % 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setz(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If zero (ZF = 1),
- % set the value in the specified register or an 8-bit memory
- % reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; sete(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If equal (ZF = 1),
- % set the value in the specified register or an 8-bit memory
- % reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setnz(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not zero
- % (ZF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setne(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not equal
- % (ZF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p246.
-
- ; setbe(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If below or equal
- % (CF = 1 or ZF = 1), set the value in the specified register or
- % an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setna(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not above
- % (CF = 1 or ZF = 1), set the value in the specified register or
- % an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setnbe(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not below or
- % equal (CF = 0 and ZF = 0), set the value in the specified
- % register or an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; seta(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If above
- % (CF = 0 and ZF = 0), set the value in the specified
- % register or an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; sets(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is sign,
- % (SF = 1), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setns(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is not sign,
- % (SF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setp(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If flag is parity
- % (PF = 1), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setpe(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If parity even,
- % (PF = 1), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setnp(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not parity,
- % (PF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setpo(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If parity odd,
- % (PF = 0), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setl(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If less (SF <> OF),
- % set the value in the specified register or an 8-bit memory
- % reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setnge(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not greater or
- % equal (SF <> OF), set the value in the specified register or an
- % 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setnl(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not less
- % (SF = OF), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setge(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If greater or equal
- % (SF = OF), set the value in the specified register or an 8-bit
- % memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setle(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If less or equal
- % (ZF = 1 or SF <> OF), set the value in the specified register or
- % an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setng(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not greater
- % (ZF = 1 or SF <> OF), set the value in the specified register or
- % an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setnle(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If not less or equal
- % (ZF = 0 and SF = OF), set the value in the specified register or
- % an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
-
- ; setg(reg_or_mem_ref_op)
- % Check the status flag in the RFLAGS register. If greater
- % (ZF = 0 and SF = OF), set the value in the specified register or
- % an 8-bit memory reference to 1.
- % Details on amd64-prog-man-vol3 manual p247.
+ ; set(
+ set_dest :: operand,
+ % register or memory location
+ set_cond :: condition
+ )
+ % Check the status flag in the RFLAGS register. Set the value in
+ % the specified register/8-bit memory reference in 'set_dest' to 1
+ % according to the 'set_cond'.
+ % Details on amd64-prog-man-vol3 manual p(246-247).
; shld(
- shld_amount :: cl_reg_or_imm_op,
- shld_dest1 :: reg_or_mem_ref_op,
- shld_dest2 :: gp_reg
+ shld_amount :: operand,
+ % register or immediate value
+ shld_dest1 :: operand,
+ % register or memory location
+ shld_dest2 :: operand
+ % register
)
% Shift 'shld_dest1' to the left by 'shld_amount' and shift in a bit
% pattern in 'shld_dest2' from the right.
% Details on amd64-prog-man-vol3 manual p251.
; shr(
- shr_amount :: cl_reg_or_imm_op,
- shr_dest :: reg_or_mem_ref_op
+ shr_amount :: operand,
+ % register or immediate value
+ shr_dest :: operand
+ % register or memory location
)
% Shift 'shr_dest' right by 'shr_amount'.
% Details on amd64-prog-man-vol3 manual p253.
; shrd(
- shrd_amount :: cl_reg_or_imm_op,
- shrd_dest1 :: reg_or_mem_ref_op,
- shrd_dest2 :: gp_reg
+ shrd_amount :: operand,
+ % register or immediate value
+ shrd_dest1 :: operand,
+ % register or memory location
+ shrd_dest2 :: operand
+ % register
)
% Shift 'shrd_dest1' to the right by 'shrd_amount' and shift in
% a bit pattern in 'shrd_dest2' from the left.
@@ -1593,39 +1233,62 @@
; sub(
sub_src :: operand,
- sub_dest :: reg_or_mem_ref_op
+ % imm value, register or memory location
+ sub_dest :: operand
+ % register or memory location
)
% Subtracts 'sub_src' from 'sub_dest'.
% Details on amd64-prog-man-vol3 manual p261.
; test(
- test_src1 :: reg_or_mem_ref_op,
- test_src2 :: reg_or_imm_op
+ test_src1 :: operand,
+ % imm value or register
+ test_src2 :: operand
+ % register or memory location
)
% Performs a bitwise AND on 'test_src1' and 'test_src2'.
% Details on amd64-prog-man-vol3 manual p264.
; xadd(
- xadd_src :: gp_reg,
- xadd_dest :: reg_or_mem_ref_op
+ xadd_src :: operand,
+ % register
+ xadd_dest :: operand
+ % register or memory location
)
% Exchanges the contents of 'xadd_src' with 'xadd_dest', load
% their sum into 'xadd_dest'.
% Details on amd64-prog-man-vol3 manual p266.
; xchg(
- xchg_src1 :: reg_or_mem_ref_op,
- xchg_src2 :: reg_or_mem_ref_op
+ xchg_src1 :: operand,
+ % register or memory location
+ xchg_src2 :: operand
+ % register or memory location
)
% Exchanges the contents of 'xchg_src1' and 'xchg_src2'.
% Details on amd64-prog-man-vol3 manual p268.
; xor(
xor_src :: operand,
- xor_dest :: reg_or_mem_ref_op
+ xor_dest :: operand
).
% Performs a bitwise XOR on 'xor_src' with 'xor_dest' and stores
% the result in xor_dest.
% Details on amd64-prog-man-vol3 manual p272.
%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+init_x86_64_module(CModule) = x86_64_module(CModule, []).
+
+init_x86_64_proc(CProc) =
+ x86_64_procedure(CProc ^ cproc_name, CProc ^ cproc_orig_arity,
+ CProc ^ cproc_id, CProc ^ cproc_code_model, [],
+ CProc ^ cproc_proc_label, CProc ^ cproc_label_nums,
+ CProc ^ cproc_may_alter_rtti, CProc ^ cproc_c_global_vars).
+
+init_x86_64_instruction = x86_64_instr([], "").
+
+%-----------------------------------------------------------------------------%
Index: compiler/x86_64_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/x86_64_out.m,v
retrieving revision 1.1
diff -u -r1.1 x86_64_out.m
--- compiler/x86_64_out.m 15 Jan 2007 22:49:41 -0000 1.1
+++ compiler/x86_64_out.m 5 Feb 2007 05:14:49 -0000
@@ -22,11 +22,10 @@
%-----------------------------------------------------------------------------%
-:- pred output_x86_64_instrs(x86_64_instr::in, io::di, io::uo) is det.
+:- pred output_x86_64_instruction(x86_64_instruction::in,
+ io::di, io::uo) is det.
- % XXX This is just for testing purposes.
- %
-% :- pred pretend_main(io::di, io::uo) is det.
+:- pred operand_type(operand::in, string::out) is det.
%-----------------------------------------------------------------------------%
@@ -43,105 +42,6 @@
:- import_module type_desc.
%-----------------------------------------------------------------------------%
-
- % XXX This is just for testing purposes.
- %
-% pretend_main(!IO) :-
-% Comment1 = comment("This is a comment"),
-% Label1 = label(".L1"),
-% PseudoOps1 = [
-% abort,
-% align(6, no, yes(2)),
-% align(7, yes(12), no),
-% align(8, no, no),
-% ascii([".LI", ".L2"]),
-% comm(".L3", 8, no),
-% section(".data", no, no, no)
-% ],
-% Instrs1 = [
-% x86_64_instr(adc(operand_reg(rax),
-% rmro_reg(rbx)
-% ), ""),
-% x86_64_instr(add(operand_imm(imm8(int8(0x178))),
-% rmro_mem_ref(mem_abs(base_reg(0, r8)))
-% ), ""),
-% x86_64_instr(and(operand_reg(rdx),
-% rmro_mem_ref(mem_abs(base_reg(2, rdx)))
-% ), ""),
-% x86_64_instr(bsf(rmro_reg(r8), r15), ""),
-% x86_64_instr(bsr(rmro_reg(rcx), rax), ""),
-% x86_64_instr(bswap(r10), ""),
-% x86_64_instr(bt(rmro_mem_ref(mem_rip(rip_expr(".L1"))),
-% rio_reg(rsi)), ""),
-% x86_64_instr(btc(rmro_reg(rdi), rio_imm(imm16(int16(0x1822)))), ""),
-% x86_64_instr(btr(rmro_reg(rbp),
-% rio_imm(imm32(int32(0x182199)))), ""),
-% x86_64_instr(call(rmrol_rel_offset(ro8(int8(127)))), "comment"),
-% x86_64_instr(cmovo(rmro_mem_ref(mem_rip(rip_constant(int32(2)))),
-% r11), ""),
-% x86_64_instr(mov(operand_imm(imm32(int32(10))), rmro_reg(rbx)), ""),
-% x86_64_instr(or(operand_mem_ref(mem_rip(rip_constant(int32(2)))),
-% rmro_reg(rcx)), ""),
-% x86_64_instr(push(operand_mem_ref(mem_abs(base_expr(".L2")))), ""),
-% x86_64_instr(rol(crio_reg_cl(rcx), rmro_reg(rax)), ""),
-% x86_64_instr(ror(crio_imm8(int8(20)), rmro_mem_ref(mem_rip(
-% rip_expr(".L2")) )), ""),
-% x86_64_instr(sbb(operand_mem_ref(mem_rip(rip_expr(".L1"))),
-% rmro_reg(r11)), "")
-% ],
-%
-% Label2 = label(".L2"),
-% PseudoOps2 = [
-% section(".rodata", yes("aMS"), yes("@progbits"), yes(1)),
-% p2align(1,no,yes(7)),
-% type_("Type", "@function")
-% ],
-% Instrs2 = [
-% x86_64_instr(loop(ro8(int8(19))), "another comment"),
-% x86_64_instr(xor(operand_imm(imm32(int32(19))),
-% rmro_mem_ref(mem_rip(rip_expr(".L4")))
-% ), "comment"),
-% x86_64_instr(jo(ro8(int8(22))), "comment again"),
-% x86_64_instr(div(rmro_reg(rdx)), "comment div"),
-% x86_64_instr(jmp(rmrol_label(".L2")), "comment jmp"),
-% x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(".L3"))),
-% rmro_reg(rbx)), "")
-% ],
-%
-% Instructions = [
-% comment(""), label(""), directives([file("x86_64_out.m")]),
-% instrs([]),
-% Comment1, Label1, directives(PseudoOps1), instrs(Instrs1),
-% comment("Comment"), Label2, directives(PseudoOps2),
-% instrs(Instrs2)
-% ],
-% list.foldl(output_x86_64_instrs, Instructions, !IO).
-
-%-----------------------------------------------------------------------------%
-
- % Output x86_64 instructions including comments, labels and pseudo-ops.
- %
-output_x86_64_instrs(comment(Comment), !IO) :-
- ( string.length(Comment) > 0 ->
- io.write_string("# " ++ Comment ++ "\n", !IO)
- ;
- true
- ).
-output_x86_64_instrs(label(LabelName), !IO) :-
- ( string.length(LabelName) > 0 ->
- io.write_string(LabelName ++ ":\n", !IO)
- ;
- true
- ).
-output_x86_64_instrs(directives(PseudoOps), !IO) :-
- list.foldl(output_x86_64_pseudo_op, PseudoOps, !IO).
-output_x86_64_instrs(instrs(Instrs), !IO) :-
- ( list.length(Instrs) > 0 ->
- output_x86_64_instr_and_comment(Instrs, !IO)
- ;
- true
- ).
-
%-----------------------------------------------------------------------------%
%
% Output x86_64 pseudo-op.
@@ -191,7 +91,7 @@
output_pseudo_op_float_args(".double", NumList, !IO).
output_x86_64_pseudo_op(eject, !IO) :-
io.write_string("\t.eject\n", !IO).
-output_x86_64_pseudo_op(else_, !IO) :-
+output_x86_64_pseudo_op(x86_64_pseudo_else, !IO) :-
io.write_string("\t.else\n", !IO).
output_x86_64_pseudo_op(elseif, !IO) :-
io.write_string("\t.elseif\n", !IO).
@@ -235,7 +135,7 @@
output_pseudo_op_str_args(".hword", ExprList, !IO).
output_x86_64_pseudo_op(ident, !IO) :-
io.write_string("\t.ident\n", !IO).
-output_x86_64_pseudo_op(if_(Expr), !IO) :-
+output_x86_64_pseudo_op(x86_64_pseudo_if(Expr), !IO) :-
io.write_string("\t.if\t" ++ Expr ++ "\n", !IO).
output_x86_64_pseudo_op(ifdef(Symbol), !IO) :-
io.write_string("\t.ifdef\t" ++ Symbol ++ "\n", !IO).
@@ -324,12 +224,12 @@
( check_pseudo_section_type(Type1) ->
io.write_string("," ++ Type1, !IO)
;
- unexpected(this_file, "output_x86_64_pseudo_op: section:
- check_section_type unexpected")
+ unexpected(this_file, "output_x86_64_pseudo_op: section:"
+ ++ " check_section_type unexpected")
)
;
- unexpected(this_file, "output_x86_64_pseudo_op: section:
- check_section_flags_and_type unexpected")
+ unexpected(this_file, "output_x86_64_pseudo_op: section:"
+ ++ " check_section_flags_and_type unexpected")
)
;
Flags0 = no
@@ -377,11 +277,12 @@
io.write_string("\n", !IO).
output_x86_64_pseudo_op(title(Heading), !IO) :-
io.write_string("\t.title\t" ++ Heading ++ "\n", !IO).
-output_x86_64_pseudo_op(type_(Name, Desc), !IO) :-
+output_x86_64_pseudo_op(x86_64_pseudo_type(Name, Desc), !IO) :-
( check_pseudo_type_desc(Desc) ->
io.write_string("\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
;
- unexpected(this_file, "output_x86_64_pseudo_op: type_ unexpected")
+ unexpected(this_file, "output_x86_64_pseudo_op: x86_64_pseudo_type:"
+ ++ " unexpected: check_pseudo_type_desc failed")
).
output_x86_64_pseudo_op(uleb128(ExprList), !IO) :-
output_pseudo_op_str_args(".uleb128", ExprList, !IO).
@@ -463,7 +364,7 @@
pseudo_op_str_args_while([], !IO).
pseudo_op_str_args_while([Arg | Args], !IO) :-
- io.write_string(Arg, !IO),
+ io.write_string(string.word_wrap("\"" ++ Arg ++ "\"", comment_length), !IO),
(
Args = [],
pseudo_op_str_args_while(Args, !IO)
@@ -472,7 +373,7 @@
io.write_string(",", !IO),
pseudo_op_str_args_while(Args, !IO)
).
-
+
% Check if FLAGS and TYPE argument of '.section' pseudo-op is valid
%
:- pred check_section_flags_and_type(string::in, maybe(string)::in,
@@ -486,8 +387,8 @@
->
true
;
- unexpected(this_file, "check_section_flags_and_type:
- flag unexpected")
+ unexpected(this_file, "check_section_flags_and_type:"
+ ++ " unexpected: flag")
)
;
true
@@ -544,139 +445,184 @@
check_pseudo_type_desc("@function").
check_pseudo_type_desc("@function").
+:- func comment_length = int.
+
+comment_length = 68.
+
%-----------------------------------------------------------------------------%
%
% Output x86_64 instructions.
%
-:- pred output_x86_64_instr_and_comment(list(x86_64_instruction)::in, io::di,
- io::uo) is det.
+ % Output x86_64 instruction and x86_64_comment.
+ %
+output_x86_64_instruction(x86_64_instr(Instr, Comment), !IO) :-
+ output_x86_64_comment(Comment, !IO),
+ output_x86_64_instr_list(Instr, !IO),
+ io.write_string("\n", !IO).
+
+:- pred output_x86_64_instr_list(list(x86_64_instr)::in, io::di, io::uo) is det.
+
+output_x86_64_instr_list(Instrs, !IO) :-
+ list.foldl(output_x86_64_instr, Instrs, !IO).
+
+:- pred output_x86_64_instr(x86_64_instr::in, io::di, io::uo) is det.
+
+output_x86_64_instr(x86_64_comment(Comment), !IO) :-
+ ( string.length(Comment) > 0 ->
+ io.write_string("\t# ", !IO),
+ ( string.length(Comment) > comment_length ->
+ string.split(Comment, comment_length, Comment1, Comment2),
+ io.write_string(string.word_wrap(Comment1, comment_length), !IO),
+ io.write_string("\n", !IO),
+ output_x86_64_instr(x86_64_comment(Comment2), !IO)
+ ;
+ io.write_string(string.word_wrap(Comment, comment_length), !IO)
+ )
+ ;
+ true
+ ).
+output_x86_64_instr(x86_64_label(LabelName), !IO) :-
+ ( string.length(LabelName) > 0 ->
+ io.write_string("\n" ++ LabelName ++ ":", !IO)
+ ;
+ true
+ ).
+output_x86_64_instr(x86_64_directive(PseudoOp), !IO) :-
+ output_x86_64_pseudo_op(PseudoOp, !IO).
+output_x86_64_instr(x86_64_instr(Instr), !IO) :-
+ output_x86_64_inst(Instr, !IO),
+ io.write_string("\n", !IO).
-output_x86_64_instr_and_comment([], !IO).
-output_x86_64_instr_and_comment([Instr | Instrs], !IO) :-
- Instr = x86_64_instr(InstrName, Comment),
- output_x86_64_instr(InstrName, !IO),
- output_comment(Comment, !IO),
- output_x86_64_instr_and_comment(Instrs, !IO).
- % Output x86_64 instruction and its operands (if any).
+ % Output a single x86_64 instruction and its operands (if any).
%
-:- pred output_x86_64_instr(x86_64_op::in, io::di, io::uo) is det.
+:- pred output_x86_64_inst(x86_64_inst::in, io::di, io::uo) is det.
-output_x86_64_instr(adc(Src, Dest), !IO) :-
- instr_with_op_and_rmro("adc", Src, Dest, !IO).
-output_x86_64_instr(add(Src, Dest), !IO) :-
- instr_with_op_and_rmro("add", Src, Dest, !IO).
-output_x86_64_instr(and(Src, Dest), !IO) :-
- instr_with_op_and_rmro("and", Src, Dest, !IO).
-output_x86_64_instr(bsf(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("bsf", Src, Dest, !IO).
-output_x86_64_instr(bsr(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("bsr", Src, Dest, !IO).
-output_x86_64_instr(bswap(Reg), !IO) :-
- io.write_string("\tbswap\t", !IO),
- reg_type(Reg, RegType),
- io.write_string(RegType ++ "\t", !IO).
-output_x86_64_instr(bt(Src, Idx), !IO) :-
- instr_with_rmro_and_rio("bt", Src, Idx, !IO).
-output_x86_64_instr(btc(Src, Idx), !IO) :-
- instr_with_rmro_and_rio("btc", Src, Idx, !IO).
-output_x86_64_instr(btr(Src, Idx), !IO) :-
- instr_with_rmro_and_rio("btr", Src, Idx, !IO).
-output_x86_64_instr(bts(Src, Idx), !IO) :-
- instr_with_rmro_and_rio("bts", Src, Idx, !IO).
-output_x86_64_instr(call(TargetLocation), !IO) :-
- instr_with_rmrol("call", TargetLocation, !IO).
-output_x86_64_instr(cbw, !IO) :-
+output_x86_64_inst(adc(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("adc", Src, yes(Dest), !IO).
+output_x86_64_inst(add(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("add", Src, yes(Dest), !IO).
+output_x86_64_inst(and(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("and", Src, yes(Dest), !IO).
+output_x86_64_inst(bs(Src, Dest, Cond), !IO) :-
+ check_operand_not_immediate(Src, Result1),
+ (
+ Result1 = yes,
+ operand_type(Src, SrcType),
+ check_operand_register(Dest, DestRes),
+ (
+ DestRes = yes,
+ ( Cond = f ->
+ Instr = "bsf"
+ ;
+ Cond = r ->
+ Instr = "bsr"
+ ;
+ unexpected(this_file, "output_x86_64_inst: bs: unexpected:"
+ ++ " invalid condition third operand")
+ ),
+ io.write_string("\t" ++ Instr ++ "\t", !IO),
+ operand_type(Dest, DestType),
+ io.write_string(SrcType ++ ", " ++ DestType ++ "\t", !IO)
+ ;
+ DestRes = no,
+ unexpected(this_file, "output_x86_64_instr: bs: unexpected:"
+ ++ " second operand is not a register")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: bsf: unexpected: first"
+ ++ " operand is an immediate value")
+ ).
+output_x86_64_inst(bswap(Op), !IO) :-
+ check_operand_register(Op, Result),
+ (
+ Result = yes,
+ operand_type(Op, RegType),
+ io.write_string("\tbswap\t" ++ RegType ++ "\t\t", !IO)
+ ;
+ Result = no,
+ unexpected(this_file, "output_x86_64_instr: bswap: unexpected: operand"
+ ++ " is not a register")
+ ).
+output_x86_64_inst(bt(Src, Idx), !IO) :-
+ output_bit_test_instr("bt", Src, Idx, !IO).
+output_x86_64_inst(btc(Src, Idx), !IO) :-
+ output_bit_test_instr("btc", Src, Idx, !IO).
+output_x86_64_inst(btr(Src, Idx), !IO) :-
+ output_bit_test_instr("btr", Src, Idx, !IO).
+output_x86_64_inst(bts(Src, Idx), !IO) :-
+ output_bit_test_instr("bts", Src, Idx, !IO).
+output_x86_64_inst(call(Target), !IO) :-
+ check_operand_not_immediate(Target, Result),
+ (
+ Result = yes,
+ operand_type(Target, TargetType),
+ io.write_string("\tcall\t" ++ TargetType ++ "\t\t", !IO)
+ ;
+ Result = no,
+ unexpected(this_file, "output_x86_64_instr: call: unexpected:"
+ ++ " invalid target operand")
+ ).
+output_x86_64_inst(cbw, !IO) :-
io.write_string("\tcbw\t", !IO).
-output_x86_64_instr(cwde, !IO) :-
+output_x86_64_inst(cwde, !IO) :-
io.write_string("\tcwde\t", !IO).
-output_x86_64_instr(cdqe, !IO) :-
+output_x86_64_inst(cdqe, !IO) :-
io.write_string("\tcdqe\t", !IO).
-output_x86_64_instr(cwd, !IO) :-
+output_x86_64_inst(cwd, !IO) :-
io.write_string("\tcwd\t", !IO).
-output_x86_64_instr(cdq, !IO) :-
+output_x86_64_inst(cdq, !IO) :-
io.write_string("\tcdq\t", !IO).
-output_x86_64_instr(cqo, !IO) :-
+output_x86_64_inst(cqo, !IO) :-
io.write_string("\tcqo\t", !IO).
-output_x86_64_instr(clc, !IO) :-
+output_x86_64_inst(clc, !IO) :-
io.write_string("\tclc\t", !IO).
-output_x86_64_instr(cld, !IO) :-
+output_x86_64_inst(cld, !IO) :-
io.write_string("\tcld\t", !IO).
-output_x86_64_instr(cmc, !IO) :-
+output_x86_64_inst(cmc, !IO) :-
io.write_string("\tcmc\t", !IO).
-output_x86_64_instr(cmovo(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovo", Src, Dest, !IO).
-output_x86_64_instr(cmovno(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovno", Src, Dest, !IO).
-output_x86_64_instr(cmovb(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovb", Src, Dest, !IO).
-output_x86_64_instr(cmovc(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovc", Src, Dest, !IO).
-output_x86_64_instr(cmovnae(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnae", Src, Dest, !IO).
-output_x86_64_instr(cmovnb(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnb", Src, Dest, !IO).
-output_x86_64_instr(cmovnc(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnc", Src, Dest, !IO).
-output_x86_64_instr(cmovae(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovae", Src, Dest, !IO).
-output_x86_64_instr(cmovz(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovz", Src, Dest, !IO).
-output_x86_64_instr(cmove(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmove", Src, Dest, !IO).
-output_x86_64_instr(cmovnz(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnz", Src, Dest, !IO).
-output_x86_64_instr(cmovne(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovne", Src, Dest, !IO).
-output_x86_64_instr(cmovbe(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovbe", Src, Dest, !IO).
-output_x86_64_instr(cmovna(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovna", Src, Dest, !IO).
-output_x86_64_instr(cmovnbe(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnbe", Src, Dest, !IO).
-output_x86_64_instr(cmova(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmova", Src, Dest, !IO).
-output_x86_64_instr(cmovs(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovs", Src, Dest, !IO).
-output_x86_64_instr(cmovns(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovns", Src, Dest, !IO).
-output_x86_64_instr(cmovp(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovp", Src, Dest, !IO).
-output_x86_64_instr(cmovpe(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovpe", Src, Dest, !IO).
-output_x86_64_instr(cmovnp(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnp", Src, Dest, !IO).
-output_x86_64_instr(cmovpo(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovpo", Src, Dest, !IO).
-output_x86_64_instr(cmovl(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovl", Src, Dest, !IO).
-output_x86_64_instr(cmovnge(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnge", Src, Dest, !IO).
-output_x86_64_instr(cmovnl(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnl", Src, Dest, !IO).
-output_x86_64_instr(cmovge(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovge", Src, Dest, !IO).
-output_x86_64_instr(cmovle(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovle", Src, Dest, !IO).
-output_x86_64_instr(cmovng(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovng", Src, Dest, !IO).
-output_x86_64_instr(cmovnle(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovnle", Src, Dest, !IO).
-output_x86_64_instr(cmovg(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("cmovg", Src, Dest, !IO).
-output_x86_64_instr(cmp(Src, Dest), !IO) :-
- instr_with_op_and_rmro("cmp", Src, Dest, !IO).
-output_x86_64_instr(cmpxchg(Cmp, Xchg), !IO) :-
- instr_with_rmro_and_reg("cmpxchg", Cmp, Xchg, !IO).
-output_x86_64_instr(cmpxchg8b(MemRef), !IO) :-
- mem_ref_type(MemRef, MemRefType),
- io.write_string("\tcmpxchg8b" ++ MemRefType, !IO).
-output_x86_64_instr(dec(RegOrMemRef), !IO) :-
- instr_with_rmro("dec", RegOrMemRef, !IO).
-output_x86_64_instr(div(RegOrMemRef), !IO) :-
- instr_with_rmro("div", RegOrMemRef, !IO).
-output_x86_64_instr(enter(StackSize, NestingLevel), !IO) :-
+output_x86_64_inst(cmov(Src, Dest, Cond), !IO) :-
+ output_instr_with_condition("cmov", Src, yes(Dest), Cond, !IO).
+output_x86_64_inst(cmp(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("cmp", Src, yes(Dest), !IO).
+output_x86_64_inst(cmpxchg(Src, Dest), !IO) :-
+ check_operand_not_immediate(Src, Result1),
+ (
+ Result1 = yes,
+ check_operand_register(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Src, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tcmp\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: xmpxchg: unexpected:"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: xmpxchg: unexpected:"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(cmpxchg8b(Op), !IO) :-
+ check_operand_not_mem_ref(Op, Result),
+ (
+ Result = no,
+ operand_type(Op, OpType),
+ io.write_string("\tcmpxchg8b" ++ OpType, !IO)
+ ;
+ Result = yes,
+ unexpected(this_file, "output_x86_64_instr: cmpxchg8b: unexpected:"
+ ++ "invalid operand")
+ ).
+output_x86_64_inst(dec(Operand), !IO) :-
+ output_instr_not_imm_dest("dec", Operand, no, !IO).
+output_x86_64_inst(div(Operand), !IO) :-
+ output_instr_not_imm_dest("div", Operand, no, !IO).
+output_x86_64_inst(enter(StackSize, NestingLevel), !IO) :-
StackSize = uint16(Size),
NestingLevel = uint8(Level),
check_unsigned_int_size(16, Size, Result0),
@@ -691,238 +637,392 @@
io.write_int(Level, !IO),
io.write_string("\t", !IO)
;
- unexpected(this_file, "output_x86_64_instr: enter unexpected")
+ unexpected(this_file, "output_x86_64_instr: enter: unexpected:"
+ ++ " check_unsigned_int_size failed")
).
-output_x86_64_instr(idiv(RegOrMemRef), !IO) :-
- instr_with_rmro("idiv", RegOrMemRef, !IO).
-output_x86_64_instr(imul(RegOrMemRef), !IO) :-
- instr_with_rmro("idiv", RegOrMemRef, !IO).
-output_x86_64_instr(imul(Src, Dest), !IO) :-
- instr_with_rmro_and_reg("imul", Src, Dest, !IO).
-output_x86_64_instr(imul(RegOrMemRefOp, Imm, Reg), !IO) :-
- io.write_string("\timul\t", !IO),
- rmro_type(RegOrMemRefOp, Type),
- io.write_string(Type ++ ", ", !IO),
- imm_op_type(Imm, ImmVal),
- io.write_string(ImmVal ++ ", ", !IO),
- reg_type(Reg, RegType),
- io.write_string(RegType ++ "\t", !IO).
-output_x86_64_instr(inc(RegOrMemRef), !IO) :-
- instr_with_rmro("inc", RegOrMemRef, !IO).
-output_x86_64_instr(jo(RelOffset), !IO) :-
- instr_with_rel_offset_op("jo", RelOffset, !IO).
-output_x86_64_instr(jno(RelOffset), !IO) :-
- instr_with_rel_offset_op("jno", RelOffset, !IO).
-output_x86_64_instr(jb(RelOffset), !IO) :-
- instr_with_rel_offset_op("jb", RelOffset, !IO).
-output_x86_64_instr(jc(RelOffset), !IO) :-
- instr_with_rel_offset_op("jc", RelOffset, !IO).
-output_x86_64_instr(jnae(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnae", RelOffset, !IO).
-output_x86_64_instr(jnb(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnb", RelOffset, !IO).
-output_x86_64_instr(jnc(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnc", RelOffset, !IO).
-output_x86_64_instr(jae(RelOffset), !IO) :-
- instr_with_rel_offset_op("jae", RelOffset, !IO).
-output_x86_64_instr(jz(RelOffset), !IO) :-
- instr_with_rel_offset_op("jz", RelOffset, !IO).
-output_x86_64_instr(je(RelOffset), !IO) :-
- instr_with_rel_offset_op("je", RelOffset, !IO).
-output_x86_64_instr(jnz(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnz", RelOffset, !IO).
-output_x86_64_instr(jne(RelOffset), !IO) :-
- instr_with_rel_offset_op("jne", RelOffset, !IO).
-output_x86_64_instr(jbe(RelOffset), !IO) :-
- instr_with_rel_offset_op("jbe", RelOffset, !IO).
-output_x86_64_instr(jna(RelOffset), !IO) :-
- instr_with_rel_offset_op("jna", RelOffset, !IO).
-output_x86_64_instr(jnbe(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnbe", RelOffset, !IO).
-output_x86_64_instr(ja(RelOffset), !IO) :-
- instr_with_rel_offset_op("ja", RelOffset, !IO).
-output_x86_64_instr(js(RelOffset), !IO) :-
- instr_with_rel_offset_op("js", RelOffset, !IO).
-output_x86_64_instr(jns(RelOffset), !IO) :-
- instr_with_rel_offset_op("jns", RelOffset, !IO).
-output_x86_64_instr(jp(RelOffset), !IO) :-
- instr_with_rel_offset_op("jp", RelOffset, !IO).
-output_x86_64_instr(jpe(RelOffset), !IO) :-
- instr_with_rel_offset_op("jpe", RelOffset, !IO).
-output_x86_64_instr(jnp(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnp", RelOffset, !IO).
-output_x86_64_instr(jpo(RelOffset), !IO) :-
- instr_with_rel_offset_op("jpo", RelOffset, !IO).
-output_x86_64_instr(jl(RelOffset), !IO) :-
- instr_with_rel_offset_op("jl", RelOffset, !IO).
-output_x86_64_instr(jnge(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnge", RelOffset, !IO).
-output_x86_64_instr(jnl(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnl", RelOffset, !IO).
-output_x86_64_instr(jge(RelOffset), !IO) :-
- instr_with_rel_offset_op("jge", RelOffset, !IO).
-output_x86_64_instr(jle(RelOffset), !IO) :-
- instr_with_rel_offset_op("jle", RelOffset, !IO).
-output_x86_64_instr(jng(RelOffset), !IO) :-
- instr_with_rel_offset_op("jng", RelOffset, !IO).
-output_x86_64_instr(jnle(RelOffset), !IO) :-
- instr_with_rel_offset_op("jnle", RelOffset, !IO).
-output_x86_64_instr(jg(RelOffset), !IO) :-
- instr_with_rel_offset_op("jg", RelOffset, !IO).
-output_x86_64_instr(jrcxz(RelOffset), !IO) :-
- instr_with_8bit_rel_offset_op("jrcxz", RelOffset, !IO).
-output_x86_64_instr(jmp(Target), !IO) :-
- instr_with_rmrol("jmp", Target, !IO).
-output_x86_64_instr(lea(Src, Dest), !IO) :-
- instr_with_mem_ref_and_reg_op("lea", Src, Dest, !IO).
-output_x86_64_instr(leave, !IO) :-
+output_x86_64_inst(idiv(Operand), !IO) :-
+ output_instr_not_imm_dest("idiv", Operand, no, !IO).
+output_x86_64_inst(imul(Src, Dest, Mult), !IO) :-
+ operand_type(Src, SrcType),
+ io.write_string("\timul\t" ++ SrcType, !IO),
+ (
+ Dest = yes(DestRes),
+ check_operand_register(DestRes, Result1),
+ (
+ Result1 = yes,
+ operand_type(DestRes, DestType)
+ ;
+ Result1 = no,
+ TempReg = operand_reg(gp_reg(13)),
+ operand_type(TempReg, DestType)
+ ),
+ io.write_string(", " ++ DestType, !IO),
+ (
+ Mult = yes(MultRes),
+ operand_type(MultRes, Op3),
+ io.write_string(", " ++ Op3 ++ " ", !IO)
+ ;
+ Mult = no,
+ io.write_string("\t", !IO)
+ )
+ ;
+ Dest = no,
+ io.write_string("\t\t", !IO)
+ ).
+output_x86_64_inst(inc(Operand), !IO) :-
+ output_instr_not_imm_dest("inc", Operand, no, !IO).
+output_x86_64_inst(j(Offset, Cond), !IO) :-
+ output_instr_with_condition("j", Offset, no, Cond, !IO).
+output_x86_64_inst(jrcxz(RelOffset), !IO) :-
+ output_instr_8bit_rel_offset("jrcxz", RelOffset, !IO).
+output_x86_64_inst(jmp(Target), !IO) :-
+ operand_type(Target, Op),
+ io.write_string("\tjmp\t" ++ Op ++ "\t\t", !IO).
+output_x86_64_inst(lea(Src, Dest), !IO) :-
+ check_operand_not_mem_ref(Src, Result1),
+ (
+ Result1 = no,
+ check_operand_register(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Src, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tlea\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_inst: lea: unexpected:"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = yes,
+ unexpected(this_file, "output_x86_64_inst: lea: unexpected:"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(leave, !IO) :-
io.write_string("\tleave\t", !IO).
-output_x86_64_instr(loop(RelOffset), !IO) :-
- instr_with_8bit_rel_offset_op("loop", RelOffset, !IO).
-output_x86_64_instr(loope(RelOffset), !IO) :-
- instr_with_8bit_rel_offset_op("loope", RelOffset, !IO).
-output_x86_64_instr(loopne(RelOffset), !IO) :-
- instr_with_8bit_rel_offset_op("loopne", RelOffset, !IO).
-output_x86_64_instr(loopnz(RelOffset), !IO) :-
- instr_with_8bit_rel_offset_op("loopnz", RelOffset, !IO).
-output_x86_64_instr(loopz(RelOffset), !IO) :-
- instr_with_8bit_rel_offset_op("loopz", RelOffset, !IO).
-output_x86_64_instr(mov(Source, Dest), !IO) :-
- instr_with_op_and_rmro("mov", Source, Dest, !IO).
-output_x86_64_instr(mul(RegOrMemRef), !IO) :-
- instr_with_rmro("mul", RegOrMemRef, !IO).
-output_x86_64_instr(neg(RegOrMemRef), !IO) :-
- instr_with_rmro("neg", RegOrMemRef, !IO).
-output_x86_64_instr(nop, !IO) :-
+output_x86_64_inst(loop(RelOffset), !IO) :-
+ output_instr_8bit_rel_offset("loop", RelOffset, !IO).
+output_x86_64_inst(loope(RelOffset), !IO) :-
+ output_instr_8bit_rel_offset("loope", RelOffset, !IO).
+output_x86_64_inst(loopne(RelOffset), !IO) :-
+ output_instr_8bit_rel_offset("loopne", RelOffset, !IO).
+output_x86_64_inst(loopnz(RelOffset), !IO) :-
+ output_instr_8bit_rel_offset("loopnz", RelOffset, !IO).
+output_x86_64_inst(loopz(RelOffset), !IO) :-
+ output_instr_8bit_rel_offset("loopz", RelOffset, !IO).
+output_x86_64_inst(mov(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("mov", Src, yes(Dest), !IO).
+output_x86_64_inst(mul(Operand), !IO) :-
+ output_instr_not_imm_dest("mul", Operand, no, !IO).
+output_x86_64_inst(neg(Operand), !IO) :-
+ output_instr_not_imm_dest("neg", Operand, no, !IO).
+output_x86_64_inst(nop, !IO) :-
io.write_string("nop", !IO).
-output_x86_64_instr(not_(RegOrMemRef), !IO) :-
- instr_with_rmro("not", RegOrMemRef, !IO).
-output_x86_64_instr(or(Src, Dest), !IO) :-
- instr_with_op_and_rmro("or", Src, Dest, !IO).
-output_x86_64_instr(pop(RegOrMemRefOp), !IO) :-
- instr_with_rmro("pop", RegOrMemRefOp, !IO).
-output_x86_64_instr(popfq, !IO) :-
+output_x86_64_inst(x86_64_instr_not(Operand), !IO) :-
+ output_instr_not_imm_dest("not", Operand, no, !IO).
+output_x86_64_inst(or(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("or", Src, yes(Dest), !IO).
+output_x86_64_inst(pop(Operand), !IO) :-
+ output_instr_not_imm_dest("pop", Operand, no, !IO).
+output_x86_64_inst(popfq, !IO) :-
io.write_string("\tpopfq\t", !IO).
-output_x86_64_instr(push(Operand), !IO) :-
+output_x86_64_inst(push(Operand), !IO) :-
io.write_string("\tpush\t", !IO),
operand_type(Operand, OperandType),
io.write_string(OperandType ++ "\t", !IO).
-output_x86_64_instr(pushfq, !IO) :-
+output_x86_64_inst(pushfq, !IO) :-
io.write_string("\tpushfq\t", !IO).
-output_x86_64_instr(rcl(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("rcl", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(rcr(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("rcr", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(ret, !IO) :-
- io.write_string("\tret\t", !IO).
-output_x86_64_instr(ret(uint16(NumBytes)), !IO) :-
- check_unsigned_int_size(16, NumBytes, Result),
+output_x86_64_inst(rc(Amnt, Dest, Cond), !IO) :-
+ check_rc_first_operand(Amnt, Result1),
(
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\trc\t" ++ Cond, !IO),
+ io.write_string(Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: rc: unexpected"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: rc: unexpected"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(ret(Op), !IO) :-
+ (
+ Op = yes(OpRes),
+ OpRes = uint16(NumBytes)
+ ->
+ check_unsigned_int_size(16, NumBytes, Result),
+ (
+ Result = yes,
+ io.write_string("\tret\t", !IO),
+ io.write_int(NumBytes, !IO),
+ io.write_string("\t", !IO)
+ ;
+ Result = no,
+ unexpected(this_file, "output_x86_64_instr: ret: unexpected:"
+ ++ "check_unsigned_int_size failed")
+ )
+ ;
+ Op = no
+ ->
+ io.write_string("\tret\t\t", !IO)
+ ;
+ unexpected(this_file, "output_x86_64_instr: ret: unexpected"
+ ++ " invalid operand")
+ ).
+output_x86_64_inst(ro(Amnt, Dest, Dir), !IO) :-
+ check_operand_not_mem_ref(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tro" ++ Dir ++ "\t", !IO),
+ io.write_string(Op1 ++ ", " ++ Op2 ++ "\t\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: ro: unexpected:"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: ro: unexpected"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(sal(Amnt, Dest), !IO) :-
+ check_operand_unsigned_imm_or_reg(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tsal\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: sal: unexpected:"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: sal: unexpected:"
+ ++ "invalid first operand")
+ ).
+output_x86_64_inst(shl(Amnt, Dest), !IO) :-
+ check_operand_unsigned_imm_or_reg(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tshl\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: shl: unexpected:"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: shl: unexpected:"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(sar(Amnt, Dest), !IO) :-
+ check_operand_unsigned_imm_or_reg(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tsar\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: sar: unexpected:"
+ ++ "invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: sar: unexpected:"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(sbb(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("sbb", Src, yes(Dest), !IO).
+output_x86_64_inst(set(Operand, Cond), !IO) :-
+ check_operand_not_immediate(Operand, Result),
+ (
Result = yes,
- io.write_string("\tret\t", !IO),
- io.write_int(NumBytes, !IO),
- io.write_string("\t", !IO)
+ output_instr_with_condition("set", Operand, no, Cond, !IO)
;
Result = no,
- unexpected(this_file, "output_x86_64_instr: ret unexpected")
+ unexpected(this_file, "output_x86_64_instr: set: unexpected"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(shld(Amnt, Dest1, Reg), !IO) :-
+ check_operand_unsigned_imm_or_reg(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest1, Result2),
+ (
+ Result2 = yes,
+ check_operand_register(Reg, Result3),
+ (
+ Result3 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Amnt, Op2),
+ operand_type(Amnt, Op3),
+ io.write_string("\tshld\t" ++ Op1 ++ ", ", !IO),
+ io.write_string(Op2 ++ ", " ++ Op3 ++ "\t", !IO)
+ ;
+ Result3 = no,
+ unexpected(this_file, "output_x86_64_instr: shld: unexpected:"
+ ++ "invalid third operand")
+ )
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: shld: unexpected:"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: shld: unexpected"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(shr(Amnt, Dest), !IO) :-
+ check_operand_unsigned_imm_or_reg(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\tshr\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: shr: unexpected"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: shr: unexpected"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(shrd(Amnt, Dest1, Reg), !IO) :-
+ check_operand_unsigned_imm_or_reg(Amnt, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest1, Result2),
+ (
+ Result2 = yes,
+ check_operand_register(Reg, Result3),
+ (
+ Result3 = yes,
+ operand_type(Amnt, Op1),
+ operand_type(Amnt, Op2),
+ operand_type(Amnt, Op3),
+ io.write_string("\tshrd\t" ++ Op1 ++ ", ", !IO),
+ io.write_string(Op2 ++ ", " ++ Op3 ++ "\t", !IO)
+ ;
+ Result3 = no,
+ unexpected(this_file, "output_x86_64_instr: shrd: unexpected"
+ ++ " invalid third operand")
+ )
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: shrd: unexpected"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: shrd: unexpected:"
+ ++ " invalid first operand")
).
-output_x86_64_instr(rol(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("rol", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(ror(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("ror", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(sal(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("sal", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(shl(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("shl", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(sar(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("sar", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(sbb(Src, Dest), !IO) :-
- instr_with_op_and_rmro("sbb", Src, Dest, !IO).
-output_x86_64_instr(seto(RegOrMemRef), !IO) :-
- instr_with_rmro("seto", RegOrMemRef, !IO).
-output_x86_64_instr(setno(RegOrMemRef), !IO) :-
- instr_with_rmro("setno", RegOrMemRef, !IO).
-output_x86_64_instr(setb(RegOrMemRef), !IO) :-
- instr_with_rmro("setb", RegOrMemRef, !IO).
-output_x86_64_instr(setc(RegOrMemRef), !IO) :-
- instr_with_rmro("setc", RegOrMemRef, !IO).
-output_x86_64_instr(setnae(RegOrMemRef), !IO) :-
- instr_with_rmro("setnae", RegOrMemRef, !IO).
-output_x86_64_instr(setnb(RegOrMemRef), !IO) :-
- instr_with_rmro("setnb", RegOrMemRef, !IO).
-output_x86_64_instr(setnc(RegOrMemRef), !IO) :-
- instr_with_rmro("setnc", RegOrMemRef, !IO).
-output_x86_64_instr(setae(RegOrMemRef), !IO) :-
- instr_with_rmro("setae", RegOrMemRef, !IO).
-output_x86_64_instr(setz(RegOrMemRef), !IO) :-
- instr_with_rmro("setz", RegOrMemRef, !IO).
-output_x86_64_instr(sete(RegOrMemRef), !IO) :-
- instr_with_rmro("sete", RegOrMemRef, !IO).
-output_x86_64_instr(setnz(RegOrMemRef), !IO) :-
- instr_with_rmro("setnz", RegOrMemRef, !IO).
-output_x86_64_instr(setne(RegOrMemRef), !IO) :-
- instr_with_rmro("setne", RegOrMemRef, !IO).
-output_x86_64_instr(setbe(RegOrMemRef), !IO) :-
- instr_with_rmro("setbe", RegOrMemRef, !IO).
-output_x86_64_instr(setna(RegOrMemRef), !IO) :-
- instr_with_rmro("setna", RegOrMemRef, !IO).
-output_x86_64_instr(setnbe(RegOrMemRef), !IO) :-
- instr_with_rmro("setnbe", RegOrMemRef, !IO).
-output_x86_64_instr(seta(RegOrMemRef), !IO) :-
- instr_with_rmro("seta", RegOrMemRef, !IO).
-output_x86_64_instr(sets(RegOrMemRef), !IO) :-
- instr_with_rmro("sets", RegOrMemRef, !IO).
-output_x86_64_instr(setns(RegOrMemRef), !IO) :-
- instr_with_rmro("setns", RegOrMemRef, !IO).
-output_x86_64_instr(setp(RegOrMemRef), !IO) :-
- instr_with_rmro("setp", RegOrMemRef, !IO).
-output_x86_64_instr(setpe(RegOrMemRef), !IO) :-
- instr_with_rmro("setpe", RegOrMemRef, !IO).
-output_x86_64_instr(setnp(RegOrMemRef), !IO) :-
- instr_with_rmro("setnp", RegOrMemRef, !IO).
-output_x86_64_instr(setpo(RegOrMemRef), !IO) :-
- instr_with_rmro("setpo", RegOrMemRef, !IO).
-output_x86_64_instr(setl(RegOrMemRef), !IO) :-
- instr_with_rmro("sel", RegOrMemRef, !IO).
-output_x86_64_instr(setnge(RegOrMemRef), !IO) :-
- instr_with_rmro("setnge", RegOrMemRef, !IO).
-output_x86_64_instr(setnl(RegOrMemRef), !IO) :-
- instr_with_rmro("setnl", RegOrMemRef, !IO).
-output_x86_64_instr(setge(RegOrMemRef), !IO) :-
- instr_with_rmro("setge", RegOrMemRef, !IO).
-output_x86_64_instr(setle(RegOrMemRef), !IO) :-
- instr_with_rmro("setle", RegOrMemRef, !IO).
-output_x86_64_instr(setng(RegOrMemRef), !IO) :-
- instr_with_rmro("setng", RegOrMemRef, !IO).
-output_x86_64_instr(setnle(RegOrMemRef), !IO) :-
- instr_with_rmro("setnle", RegOrMemRef, !IO).
-output_x86_64_instr(setg(RegOrMemRef), !IO) :-
- instr_with_rmro("setg", RegOrMemRef, !IO).
-output_x86_64_instr(shld(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
- instr_with_crio_rmro_and_reg("shld", ClRegOrImm, RegOrMemRef, Reg, !IO).
-output_x86_64_instr(shr(ClRegOrImm, RegOrMemRef), !IO) :-
- instr_with_crio_and_rmro("shr", ClRegOrImm, RegOrMemRef, !IO).
-output_x86_64_instr(shrd(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
- instr_with_crio_rmro_and_reg("shrd", ClRegOrImm, RegOrMemRef, Reg, !IO).
-output_x86_64_instr(stc, !IO) :-
+output_x86_64_inst(stc, !IO) :-
io.write_string("\tstc\t", !IO).
-output_x86_64_instr(std, !IO) :-
+output_x86_64_inst(std, !IO) :-
io.write_string("\tstd\t", !IO).
-output_x86_64_instr(sub(Src, Dest), !IO) :-
- instr_with_op_and_rmro("sub", Src, Dest, !IO).
-output_x86_64_instr(test(Src1, Src2), !IO) :-
- instr_with_rmro_and_rio("test", Src1, Src2, !IO).
-output_x86_64_instr(xadd(Src, Dest), !IO) :-
- instr_with_reg_and_rmro("xadd", Src, Dest, !IO).
-output_x86_64_instr(xchg(Src1, Src2), !IO) :-
- instr_with_rmro_and_rmro("xchg", Src1, Src2, !IO).
-output_x86_64_instr(xor(Src, Dest), !IO) :-
- instr_with_op_and_rmro("xor", Src, Dest, !IO).
+output_x86_64_inst(sub(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("sub", Src, yes(Dest), !IO).
+output_x86_64_inst(test(Src1, Src2), !IO) :-
+ check_operand_not_mem_ref(Src1, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Src2, Result2),
+ (
+ Result2 = yes,
+ operand_type(Src1, Op1),
+ operand_type(Src2, Op2),
+ io.write_string("\ttest\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: test: unexpected"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: test: unexpected"
+ ++ " invalid first operand")
+ ).
+output_x86_64_inst(xadd(Src, Dest), !IO) :-
+ check_operand_register(Src, Result1),
+ (
+ Result1 = yes,
+ check_operand_not_immediate(Dest, Result2),
+ (
+ Result2 = yes,
+ operand_type(Src, Op1),
+ operand_type(Dest, Op2),
+ io.write_string("\txadd\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: unexpected
+ xadd second operand is an immediate value")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: unexpected
+ xadd first operand is not a register")
+ ).
+output_x86_64_inst(xchg(Src1, Src2), !IO) :-
+ check_operand_reg_or_mem(Src1, Result1),
+ (
+ Result1 = yes,
+ check_operand_reg_or_mem(Src2, Result2),
+ (
+ Result2 = yes,
+ operand_type(Src1, Op1),
+ operand_type(Src2, Op2),
+ io.write_string("\txchg\t" ++ Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_x86_64_instr: xchg: unexpected"
+ ++ " invalid second operand")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_x86_64_instr: xchg: unexpected"
+ ++ " invalid second operand")
+ ).
+output_x86_64_inst(xor(Src, Dest), !IO) :-
+ output_instr_not_imm_dest("xor", Src, yes(Dest), !IO).
-:- pred output_comment(string::in, io::di, io::uo) is det.
+:- pred output_x86_64_comment(string::in, io::di, io::uo) is det.
-output_comment(Comment, !IO) :-
+output_x86_64_comment(Comment, !IO) :-
( string.length(Comment) > 0 ->
io.write_string("\t# ", !IO),
io.write_string(Comment, !IO)
@@ -947,30 +1047,14 @@
imm_op_type(imm32(int32(Val)), ImmVal) :-
ImmVal = "$" ++ string.int_to_string(Val).
- % Output a string representation of a general-purpose register.
- %
-:- pred reg_type(gp_reg::in, string::out) is det.
-reg_type(rax, "%rax").
-reg_type(rbx, "%rbx").
-reg_type(rcx, "%rcx").
-reg_type(rdx, "%rdx").
-reg_type(rbp, "%rbp").
-reg_type(rsi, "%rsi").
-reg_type(rdi, "%rdi").
-reg_type(rsp, "%rsp").
-reg_type(r8, "%r8").
-reg_type(r9, "%r9").
-reg_type(r10, "%r10").
-reg_type(r11, "%r11").
-reg_type(r12, "%r12").
-reg_type(r13, "%r13").
-reg_type(r14, "%r14").
-reg_type(r15, "%r15").
+:- func reg_type(gp_reg) = string.
+
+reg_type(gp_reg(RegNum)) = "%r" ++ string.int_to_string(RegNum).
% Output a string representation of a memory reference.
%
-:- pred mem_ref_type(mem_ref::in, string::out) is det.
+:- pred mem_ref_type(x86_64_mem_ref::in, string::out) is det.
mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
base_address_type(DirectMemRef, MemRefVal).
@@ -982,11 +1066,10 @@
:- pred base_address_type(base_address::in, string::out) is det.
base_address_type(base_reg(Offset, Reg), BaseAddress) :-
- reg_type(Reg, RegType),
( Offset = 0 ->
- BaseAddress = "(" ++ RegType ++ ")"
+ BaseAddress = "(" ++ reg_type(Reg) ++ ")"
;
- BaseAddress = string.int_to_string(Offset) ++ "(" ++ RegType ++ ")"
+ BaseAddress = string.int_to_string(Offset) ++ "(" ++ reg_type(Reg) ++ ")"
).
base_address_type(base_expr(Expr), DispType) :-
DispType = "$" ++ Expr.
@@ -1002,7 +1085,8 @@
InstrPtrType = string.int_to_string(Constant) ++ "(%rip)"
;
Result = no,
- unexpected(this_file, "instr_ptr_type: int32 unexpected")
+ unexpected(this_file, "instr_ptr_type: rip_constant: unexpected"
+ ++ " check_signed_int_size failed")
).
instr_ptr_type(rip_expr(Symbol), InstrPtrType) :-
InstrPtrType = Symbol ++ "(%rip)".
@@ -1022,7 +1106,8 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro8 unexpected")
+ unexpected(this_file, "rel_offset_type: ro8(int8): unexpected:"
+ ++ " check_signed_int_size failed")
).
rel_offset_type(ro16(int16(Val)), RelOffsetVal) :-
check_signed_int_size(16, Val, Result),
@@ -1035,7 +1120,8 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro16 unexpected")
+ unexpected(this_file, "rel_offset_type: ro16(int16): unexpected"
+ ++ " check_signed_int_size failed")
).
rel_offset_type(ro32(int32(Val)), RelOffsetVal) :-
check_signed_int_size(32, Val, Result),
@@ -1048,252 +1134,322 @@
)
;
Result = no,
- unexpected(this_file, "rel_offset_type: ro32 unexpected")
+ unexpected(this_file, "rel_offset_type: ro32(int32): unexpected"
+ ++ " check_signed_int_size failed")
).
- % Output a string representation of a general operand type.
- %
-:- pred operand_type(operand::in, string::out) is det.
operand_type(operand_reg(Reg), RegType) :-
- reg_type(Reg, RegType).
+ RegType = reg_type(Reg).
operand_type(operand_imm(Imm), ImmVal) :-
imm_op_type(Imm, ImmVal).
operand_type(operand_mem_ref(MemRef), MemRefVal) :-
mem_ref_type(MemRef, MemRefVal).
-
- % Output a string representation of an operand whose type is a register/
- % memory reference.
- %
-:- pred rmro_type(reg_or_mem_ref_op::in, string::out) is det.
-
-rmro_type(rmro_reg(Reg), RegType) :-
- reg_type(Reg, RegType).
-rmro_type(rmro_mem_ref(MemRef), MemRefVal) :-
- mem_ref_type(MemRef, MemRefVal).
-
- % Output a string representation of an operand whose type is a register
- % or an immediate value.
- %
-:- pred rio_type(reg_or_imm_op::in, string::out) is det.
-
-rio_type(rio_reg(Reg), RegType) :-
- reg_type(Reg, RegType).
-rio_type(rio_imm(Imm), ImmVal) :-
- imm_op_type(Imm, ImmVal).
-
- % Output a string representation of an operand whose type is a cl register
- % or an unsigned immediate value.
- %
-:- pred crio_type(cl_reg_or_imm_op::in, string::out) is det.
-
-crio_type(crio_reg_cl(Reg), RegType) :-
- ( Reg = rcx ->
- RegType = "%cl"
- ;
- unexpected(this_file, "crio_type: crio_reg_cl unexpected")
- ).
-crio_type(crio_imm8(int8(Val)), ImmVal) :-
- check_unsigned_int_size(8, Val, Result),
- (
- Result = yes,
- ImmVal = "$" ++ string.int_to_string(Val)
- ;
- Result = no,
- unexpected(this_file, "crio_type: crio_imm8 unexpected")
- ).
-
- % Output a string representation of an operand whose type is either
- % a register, memory reference, signed relative offset or a label.
- %
-:- pred rmrol_type(rmrol::in, string::out) is det.
-
-rmrol_type(rmrol_reg(Reg), RegType) :-
- reg_type(Reg, RegType).
-rmrol_type(rmrol_mem_ref(MemRef), MemRefVal) :-
- mem_ref_type(MemRef, MemRefVal).
-rmrol_type(rmrol_rel_offset(RelOffset), RelOffsetVal) :-
- rel_offset_type(RelOffset, RelOffsetVal).
-rmrol_type(rmrol_label(LabelName), LabelOut) :-
- LabelOut = LabelName.
+operand_type(operand_rel_offset(RelOffset), RelOffsetType) :-
+ rel_offset_type(RelOffset, RelOffsetType).
+operand_type(operand_label(Label), (Label)).
%-----------------------------------------------------------------------------%
%
% Subsection of "Output of x86_64 instructions".
%
- % Output an instruction with a register/memory reference as an operand.
+ % Output an instruction with either one or two operand(s). If the second
+ % operand is present, it cannot be an immediate operand.
%
-:- pred instr_with_rmro(string::in, reg_or_mem_ref_op::in,
+:- pred output_instr_not_imm_dest(string::in, operand::in, maybe(operand)::in,
io::di, io::uo) is det.
-instr_with_rmro(InstrName, RegOrMemRef, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- rmro_type(RegOrMemRef, RegOrMemRefType),
- io.write_string(RegOrMemRefType ++ "\t\t", !IO).
+output_instr_not_imm_dest(Instr, Op1, Op2, !IO) :-
+ operand_type(Op1, Op1Type),
+ (
+ Op2 = yes(Op2Result),
+ check_not_both_memory_ops(Op1, Op2Result, Result1),
+ (
+ Result1 = yes,
+ operand_type(Op2Result, Op2Type),
+ check_operand_not_immediate(Op2Result, Result2),
+ (
+ Result2 = yes,
+ io.write_string("\t" ++ Instr ++ "\t", !IO),
+ io.write_string(Op1Type ++ ", " ++ Op2Type ++ "\t", !IO)
+ ;
+ Result2 = no,
+ io.write_string("\tmov\t" ++ Op2Type ++ ", %r13\t", !IO),
+ io.write_string("# move immediate to temp reg\n", !IO),
+ io.write_string("\t" ++ Instr ++ "\t", !IO),
+ io.write_string(Op1Type ++ ", " ++ "%r13\t", !IO)
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_instr_not_imm_dest: unexpected:"
+ ++ " invalid operands - two memory references are not allowed")
+ )
+ ;
+ Op2 = no,
+ io.write_string(Op1Type ++ "\t\t", !IO)
+ ).
% Output an instruction with a signed offset relative to the instruction
% pointer as an operand.
- %
-:- pred instr_with_rel_offset_op(string::in, rel_offset::in,
- io::di, io::uo) is det.
-
-instr_with_rel_offset_op(InstrName, RelOffset, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- rel_offset_type(RelOffset, RelOffsetType),
- io.write_string(RelOffsetType ++ "\t\t", !IO).
-
% Output an instruction with a signed 8-bit offset relative to the
% instruction pointer as an operand.
%
-:- pred instr_with_8bit_rel_offset_op(string::in, rel_offset::in,
+:- pred output_instr_8bit_rel_offset(string::in, operand::in,
io::di, io::uo) is det.
-instr_with_8bit_rel_offset_op(InstrName, RelOffset, !IO) :-
+output_instr_8bit_rel_offset(InstrName, RelOffset, !IO) :-
+ check_operand_rel_offset(RelOffset, Result1),
(
- RelOffset = ro8(int8(Val)),
- check_signed_int_size(8, Val, Result),
- Result = yes
- ->
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- io.write_int(Val, !IO),
- io.write_string("\t\t", !IO)
+ Result1 = yes,
+ operand_type(RelOffset, RelOffsetType),
+ ( string.to_int(RelOffsetType, Val) ->
+ check_signed_int_size(8, Val, Result2),
+ (
+ Result2 = yes,
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ io.write_int(Val, !IO),
+ io.write_string("\t\t", !IO)
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_instr_8bit_rel_offset:"
+ ++ " unexpected: check_signed_int_size failed")
+ )
+ ;
+ unexpected(this_file, "output_instr_8bit_rel_offset: unexpected:"
+ ++ " string.to_int failed")
+ )
;
- unexpected(this_file, "instr_with_8bit_rel_offset_op: unexpected")
+ Result1 = no,
+ unexpected(this_file, "output_instr_8bit_rel_offset: unexpected:"
+ ++ " invalid operand - operand is not a relative offset")
).
- % Output an instruction with either a register, memory reference,
- % relative offset or a label as its operand.
- %
-:- pred instr_with_rmrol(string::in, rmrol::in, io::di, io::uo) is det.
+:- pred output_bit_test_instr(string::in, operand::in, operand::in, io::di,
+ io::uo) is det.
-instr_with_rmrol(InstrName, Target, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- rmrol_type(Target, TargetType),
- io.write_string(TargetType ++ "\t\t", !IO).
+output_bit_test_instr(Instr, Src, Idx, !IO) :-
+ check_operand_not_immediate(Src, Result1),
+ (
+ Result1 = yes,
+ operand_type(Src, Op1),
+ check_operand_not_mem_ref(Idx, Result2),
+ (
+ Result2 = yes,
+ operand_type(Idx, Op2),
+ ( string.to_int(Op2, IdxInt) ->
+ check_signed_int_size(8, IdxInt, Result3),
+ (
+ Result3 = yes,
+ io.write_string("\t" ++ Instr ++ "\t", !IO),
+ io.write_string(Op1 ++ ", " ++ Op2 ++ "\t", !IO)
+ ;
+ Result3 = no,
+ unexpected(this_file, "output_bit_test_instr: bt:"
+ ++ " unexpected: invalid second operand")
+ )
+ ;
+ unexpected(this_file, "output_bit_test_instr: unexpected:"
+ ++ " string.to_int failed")
+ )
+ ;
+ Result2 = no,
+ unexpected(this_file, "output_bit_test_instr: bt: unexpected:"
+ ++ " invalid second operand - memory reference is not allowed")
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_bit_test_instr: bt: unexpected:"
+ ++ " invalid first operand - immediate value is not allowed")
+ ).
- % Output an instruction with a general operand and a register/memory
- % reference as the first and second operand respectively.
- %
-:- pred instr_with_op_and_rmro(string::in, operand::in, reg_or_mem_ref_op::in,
- io::di, io::uo) is det.
+:- pred output_instr_with_condition(string::in, operand::in, maybe(operand)::in,
+ condition::in, io::di, io::uo) is det.
-instr_with_op_and_rmro(InstrName, SrcOperand, DestRegOrMemRefOp, !IO) :-
- (
- SrcOperand = operand_mem_ref(_),
- DestRegOrMemRefOp = rmro_mem_ref(_)
+output_instr_with_condition(Instr, Op1, Op2, Cond, !IO) :-
+ check_operand_not_immediate(Op1, Result1),
+ (
+ Result1 = yes,
+ instr_condition(Cond, CondRes),
+ io.write_string("\t" ++ Instr, !IO),
+ io.write_string(CondRes ++ "\t", !IO),
+ operand_type(Op1, Op1Type),
+ io.write_string(Op1Type, !IO),
+ (
+ Op2 = yes(Op2Res),
+ check_operand_register(Op2Res, Result3),
+ (
+ Result3 = yes,
+ operand_type(Op2Res, Op2Type),
+ io.write_string(", " ++ Op2Type, !IO)
+ ;
+ Result3 = no,
+ unexpected(this_file, "output_instr_with_condition:"
+ ++ " invalid second operand")
+ )
+ ;
+ Op2 = no,
+ io.write_string("\t\t", !IO)
+ )
+ ;
+ Result1 = no,
+ unexpected(this_file, "output_instr_with_condition: unexpected:"
+ ++ "invalid first operand - immediate value is not allowed")
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred check_rc_first_operand(operand::in, bool::out) is det.
+
+check_rc_first_operand(Op, Result) :-
+ ( Op = operand_imm(_) ->
+ operand_type(Op, OpType),
+ ( string.to_int(OpType, OpInt) ->
+ check_unsigned_int_size(8, OpInt, Result1),
+ (
+ Result1 = yes,
+ Result = yes
+ ;
+ Result1 = no,
+ Result = no
+ )
+ ;
+ unexpected(this_file, "check_rc_first_operand: unexpected:"
+ ++ " string.to_int")
+ )
+ ;
+ Op = operand_reg(_) ->
+ check_operand_register(Op, Result2),
+ (
+ Result2 = yes,
+ Result = yes
+ ;
+ Result2 = no,
+ Result = no
+ )
+ ;
+ unexpected(this_file, "check_rc_first_operand: unexpected:"
+ ++ " invalid operand")
+ ).
+
+:- pred check_not_both_memory_ops(operand::in, operand::in, bool::out) is det.
+
+check_not_both_memory_ops(Op1, Op2, Result) :-
+ (
+ Op1 = operand_mem_ref(_),
+ Op2 = operand_mem_ref(_)
->
- % Both operands cannot be of type memory reference.
- unexpected(this_file, "instr_with_op_and_rmro: unexpected")
+ Result = no
;
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- operand_type(SrcOperand, OperandType),
- io.write_string(OperandType ++ ", ", !IO),
- rmro_type(DestRegOrMemRefOp, DestType),
- io.write_string(DestType ++ "\t", !IO)
+ Result = yes
).
- % Output an instruction with a register/memory reference and a register as
- % the first and second operand respectively.
- %
-:- pred instr_with_rmro_and_reg(string::in, reg_or_mem_ref_op::in, gp_reg::in,
- io::di, io::uo) is det.
+:- pred check_operand_not_immediate(operand::in, bool::out) is det.
-instr_with_rmro_and_reg(InstrName, SrcRegOrMemRefOp, DestReg, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- rmro_type(SrcRegOrMemRefOp, SrcType),
- io.write_string(SrcType ++ ", ", !IO),
- reg_type(DestReg, RegType),
- io.write_string(RegType ++ "\t", !IO).
+check_operand_not_immediate(Operand, Result) :-
+ ( Operand = operand_imm(_) ->
+ Result = no
+ ;
+ Result = yes
+ ).
- % Output an instruction with a register/memory reference and a register/
- % immediate value as the first and second operand respectively.
- %
-:- pred instr_with_rmro_and_rio(string::in, reg_or_mem_ref_op::in,
- reg_or_imm_op::in, io::di, io::uo) is det.
+:- pred check_operand_reg_or_mem(operand::in, bool::out) is det.
-instr_with_rmro_and_rio(InstrName, SrcRegOrMemRefOp, DestRegOrImmOp, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- rmro_type(SrcRegOrMemRefOp, SrcType),
- io.write_string(SrcType ++ ",", !IO),
- rio_type(DestRegOrImmOp, DestType),
- io.write_string(DestType ++ "\t", !IO).
+check_operand_reg_or_mem(Operand, Result) :-
+ ( Operand = operand_reg(_) ->
+ Result = yes
+ ;
+ Operand = operand_mem_ref(_) ->
+ Result = yes
+ ;
+ Result = no
+ ).
- % Output an instruction with a register/memory reference as the first and
- % second operand respectively.
- %
-:- pred instr_with_rmro_and_rmro(string::in, reg_or_mem_ref_op::in,
- reg_or_mem_ref_op::in, io::di, io::uo) is det.
+:- pred check_operand_unsigned_imm_or_reg(operand::in, bool::out) is det.
-instr_with_rmro_and_rmro(InstrName, RegOrMemRefOp0, RegOrMemRefOp1, !IO) :-
- (
- RegOrMemRefOp0 = rmro_mem_ref(_),
- RegOrMemRefOp1 = rmro_mem_ref(_)
- ->
- unexpected(this_file, "instr_with_rmro_and_rmro: unexpected")
+check_operand_unsigned_imm_or_reg(Operand, Result) :-
+ ( Operand = operand_imm(Imm) ->
+ imm_op_type(Imm, ImmType),
+ ( string.to_int(ImmType, ImmInt) ->
+ (
+ check_unsigned_int_size(32, ImmInt, Result1),
+ (
+ Result1 = yes,
+ Result = yes
+ ;
+ Result1 = no,
+ Result = no
+ )
+ )
+ ;
+ unexpected(this_file, "check_operand_unsigned_imm_or_reg:"
+ ++ " unexpected: string.to_int failed")
+ )
;
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- rmro_type(RegOrMemRefOp0, Type0),
- io.write_string(Type0 ++ ", ", !IO),
- rmro_type(RegOrMemRefOp1, Type1),
- io.write_string(Type1 ++ "\t", !IO)
+ Result = no
).
- % Output an instruction with a register and a register/memory reference as
- % the first and second operand respectively.
- %
-:- pred instr_with_reg_and_rmro(string::in, gp_reg::in, reg_or_mem_ref_op::in,
- io::di, io::uo) is det.
+:- pred check_operand_register(operand::in, bool::out) is det.
-instr_with_reg_and_rmro(InstrName, SrcReg, DestRegOrMemRefOp, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- reg_type(SrcReg, RegType),
- io.write_string(RegType ++ ", ", !IO),
- rmro_type(DestRegOrMemRefOp, DestType),
- io.write_string(DestType ++ "\t", !IO).
+check_operand_register(Operand, Result) :-
+ ( Operand = operand_reg(_) ->
+ Result = yes
+ ;
+ Result = no
+ ).
- % Output an instruction with a cl register/immediate value and a register/
- % memory reference as the first and second operand respectively.
- %
-:- pred instr_with_crio_and_rmro(string::in, cl_reg_or_imm_op::in,
- reg_or_mem_ref_op::in, io::di, io::uo) is det.
+:- pred check_operand_not_mem_ref(operand::in, bool::out) is det.
-instr_with_crio_and_rmro(InstrName, ClRegOrImm, RegOrMemRef, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- crio_type(ClRegOrImm, ClRegOrImmType),
- io.write_string(ClRegOrImmType ++ ", ", !IO),
- rmro_type(RegOrMemRef, RegOrMemRefType),
- io.write_string(RegOrMemRefType ++ "\t", !IO).
-
- % Output an instruction with a cl register/immediate value, a register/
- % memory reference and a register as the first, second and third operand
- % respectively.
- %
-:- pred instr_with_crio_rmro_and_reg(string::in, cl_reg_or_imm_op::in,
- reg_or_mem_ref_op::in, gp_reg::in, io::di, io::uo) is det.
+check_operand_not_mem_ref(Operand, Result) :-
+ ( Operand = operand_mem_ref(_) ->
+ Result = no
+ ;
+ Result = yes
+ ).
-instr_with_crio_rmro_and_reg(InstrName, ClRegOrImm, RegOrMemRef, Reg, !IO) :-
- io.write_string("\t" ++ InstrName ++ "\t", !IO),
- crio_type(ClRegOrImm, ClRegOrImmType),
- io.write_string(ClRegOrImmType ++ "\t", !IO),
- rmro_type(RegOrMemRef, RegOrMemRefType),
- io.write_string(RegOrMemRefType ++ ", ", !IO),
- reg_type(Reg, RegType),
- io.write_string(RegType ++ "\t", !IO).
+:- pred check_operand_rel_offset(operand::in, bool::out) is det.
- % Output an instruction with a memory reference and a register as the first
- % and second operand respectively.
- %
-:- pred instr_with_mem_ref_and_reg_op(string::in, mem_ref::in,
- gp_reg::in, io::di, io::uo) is det.
+check_operand_rel_offset(Operand, Result) :-
+ ( Operand = operand_rel_offset(_) ->
+ Result = yes
+ ;
+ Result = no
+ ).
-instr_with_mem_ref_and_reg_op(InstrName, SrcMemRef, DestReg, !IO) :-
- mem_ref_type(SrcMemRef, MemRefType),
- io.write_string("\t" ++ InstrName ++ "\t" ++ MemRefType, !IO),
- reg_type(DestReg, DestRegType),
- io.write_string(", " ++ DestRegType ++ "\t", !IO).
+ % Check if the argument for a conditional instruction is valid.
+ %
+:- pred instr_condition(condition::in, string::out) is det.
-%-----------------------------------------------------------------------------%
+instr_condition(o, "o").
+instr_condition(no, "no").
+instr_condition(b, "b").
+instr_condition(c, "c").
+instr_condition(nae, "nae").
+instr_condition(nb, "nb").
+instr_condition(nc, "nc").
+instr_condition(ae, "ae").
+instr_condition(z, "z").
+instr_condition(e, "e").
+instr_condition(nz, "nz").
+instr_condition(ne, "ne").
+instr_condition(be, "be").
+instr_condition(na, "na").
+instr_condition(nbe, "nbe").
+instr_condition(a, "a").
+instr_condition(s, "s").
+instr_condition(ns, "ns").
+instr_condition(p, "p").
+instr_condition(pe, "pe").
+instr_condition(np, "np").
+instr_condition(po, "po").
+instr_condition(l, "l").
+instr_condition(nge, "nge").
+instr_condition(nl, "nl").
+instr_condition(ge, "ge").
+instr_condition(le, "le").
+instr_condition(ng, "ng").
+instr_condition(nle, "nle").
+instr_condition(g, "g").
% Check whether an unsigned int (Val) with n bits (BitSize) is within the
% range of 0 and (2^n)-1.
|
||
|
|
90bedf095a |
Create a file to represent x86_64 instruction sets and another file to
Estimated hours taken: 50
Branches: main
Create a file to represent x86_64 instruction sets and another file to
print the instructions out for the needs to compiler LLDS to x86_64.
compiler/x86_64_instrs.m:
Defines a representation of (a subset of) the x86_64 instruction set.
compiler/x86_64_out.m:
Predicates to write out x86_64 instructions.
compiler/ll_backend.m:
Include the new modules.
Index: compiler/ll_backend.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ll_backend.m,v
retrieving revision 1.17
diff -u -r1.17 ll_backend.m
--- compiler/ll_backend.m 27 Jul 2006 05:01:10 -0000 1.17
+++ compiler/ll_backend.m 8 Jan 2007 03:15:58 -0000
@@ -92,6 +92,10 @@
:- include_module layout_out.
:- include_module rtti_out.
+% The LLDS->x86_64 asm phase.
+:- include_module x86_64_instrs.
+:- include_module x86_64_out.
+
:- implementation.
:- import_module check_hlds. % needed for type_util, mode_util etc
Index: compiler/x86_64_instrs.m
===================================================================
RCS file: compiler/x86_64_instrs.m
diff -N compiler/x86_64_instrs.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/x86_64_instrs.m 12 Jan 2007 04:29:30 -0000
@@ -0,0 +1,1629 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: x86_64_instrs.m.
+% Main author: fhandoko.
+%
+% This module contains the representations of the x86_64 instructions.
+%
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.x86_64_instrs.
+:- interface.
+
+:- import_module list.
+:- import_module maybe.
+
+%-----------------------------------------------------------------------------%
+
+:- type x86_64_instruction
+ ---> x86_64_instr(
+ x86_64_instr_name :: x86_64_op,
+ x86_64_comment :: string
+ ).
+
+:- type label_name == string.
+
+:- type x86_64_instr
+ ---> comment(string)
+ ; label(label_name)
+ ; directives(list(pseudo_op))
+ ; instrs(list(x86_64_instruction)).
+
+%-----------------------------------------------------------------------------%
+
+ % Signed integers of various sizes.
+ %
+:- type int8 ---> int8(int). % In bottom 8 bits.
+:- type int16 ---> int16(int). % In bottom 16 bits.
+:- type int32 ---> int32(int). % in bottom 32 bits.
+
+ % Unsigned integers of various sizes.
+ %
+:- type uint8 ---> uint8(int). % In bottom 8 bits.
+:- type uint16 ---> uint16(int). % In bottom 16 bits.
+:- type uint32 ---> uint32(int). % In bottom 32 bits.
+
+
+%-----------------------------------------------------------------------------%
+%
+% x86_64 pseudo-ops.
+%
+
+ % Pseudo op for x86_64. Also called assembler directive.
+ %
+:- type pseudo_op
+ ---> abort
+ % stop the assembly immediately.
+
+ ; align(
+ align_bits :: int,
+ align_fill_value :: maybe(int),
+ align_skip_bytes :: maybe(int)
+ )
+ % Advance the location counter until it is a multiple of
+ % 'align_bits'. The second and third arguments are optional.
+ % 'align_fill_value': value to be stored in the padding bytes.
+ % 'align_skip_bytes': maximum number of bytes to be skipped.
+
+ ; ascii(
+ ascii_literals :: list(string)
+ )
+ % 'ascii_literals' contain zero or more string literals. Assembles
+ % each literal into consecutive addresses.
+
+ ; asciiz(
+ asciiz_literals :: list(string)
+ )
+ % Simiar to '.ascii', but each string is followed by a zero byte.
+
+ ; balign(
+ balign_bits :: int,
+ balign_fill_value :: maybe(int),
+ balign_skip_bytes :: maybe(int)
+ )
+ % Similar to 'align'.
+
+ ; byte(
+ byte_exprs :: list(string)
+ )
+ % 'byte_exprs' contains zero or more expressions. Each expression is
+ % assembled into the next byte.
+
+ ; comm(
+ comm_symbol :: string,
+ comm_length :: int,
+ comm_align :: maybe(int)
+ )
+ % Declare a common symbol 'comm_symbol'. Allocate 'comm_length'
+ % bytes if the symbol has not been defined.
+ % (optional) 'comm_align' is the desired alignment of the symbol.
+
+ ; data(
+ data_subsection :: maybe(int)
+ )
+ % Tells assembler to assemble the following statements onto the end
+ % of the data subsection numbered 'data_subsection'.
+
+ ; desc(
+ desc_symbol :: string,
+ desc_abs_expr :: string
+ )
+ % Set the descriptor of the symbol to the low 16 bits of
+ % 'desc_abs_expr'.
+
+ ; def(
+ def_name :: string
+ )
+ % Begin defining debugging information for a symbol 'def_name'.
+
+ ; dim
+ % Tell to include auxiliary debugging information in the symbol
+ % table.
+
+ ; double(
+ double_nums :: list(float)
+ )
+ % 'double_nums' contains zero or more floating point numbers.
+
+ ; eject
+ % Force a page break.
+
+ ; else_
+ % As in 'if-then-else' conditional expression.
+
+ ; elseif
+ % Shorthand for the beginning a new '.if' block.
+
+ ; end
+ % Mark the end of the assembly file.
+
+ ; endef
+ % End of a symbol definition begun with '.def'.
+
+ ; endfunc
+ % End of a function specified with '.func'.
+
+ ; endif
+ % End of a block of conditional code.
+
+ ; endm
+ % End of assembly macro.
+
+ ; equ(
+ equ_symbol :: string,
+ equ_expr :: string
+ )
+ % Set the value of 'equ_symbol' to 'equ_expr'.
+
+ ; equiv(
+ equiv_symbol :: string,
+ equiv_expr :: string
+ )
+ % Like '.equ' except that the assembler will signal an error
+ % if 'equiv_symbol' is already defined.
+
+ ; err
+ % Print an error message.
+
+ ; exitm
+ % Exit early from the current macro definition.
+
+ ; extern
+ % Ignored. '.extern' is accepted for compatibility only.
+
+ ; fail_(
+ fail_expr :: string
+ )
+ % Generate an error or a warning. If 'fail_expr' is 500 or more, it
+ % prints a warning message. Otherwise, it prints an error message.
+
+ ; file(
+ file_name :: string
+ )
+ % Start a new logical file.
+
+ ; fill(
+ fill_repeat :: int,
+ fill_size :: maybe(int),
+ fill_value :: maybe(int)
+ )
+ % Emits 'fill_repeat' copies of 'fill_size' byte. The contents of
+ % each 'fil_repeat' bytes is taken from an 8-byte number. The
+ % highest order 4 bytes are zero. The lowest order 4 bytes are
+ % 'fill_value'. The last 2 arguments are optional.
+
+ ; float(
+ float_nums :: list(float)
+ )
+ % 'float_nums' contains zero or more floating point numbers.
+
+ ; func_(
+ func_name :: string,
+ func_label :: string
+ )
+ % Emits debugging information to denote function 'func_name' and
+ % is ignored unless the file is assembled with debugging enabled.
+ % 'func_label' is the entry point of the function.
+
+ ; global(
+ global_symbol :: string
+ )
+ % makes the global_symbol' visible to other programs that are linked
+ % with it.
+
+ ; globl(
+ globl_symbol :: string
+ )
+ % makes the globl_symbol' visible to other programs that are linked
+
+ ; hidden(
+ hidden_name :: string
+ )
+ % Override the named symbol default visibility (which is set by
+ % their binding: local, global or weak).
+
+ ; hword(
+ hword_exprs :: list(string)
+ )
+ % 'hword_exprs' contains zero or more expressions and emit a 16-bit
+ % number for each. Synonym for '.short'.
+
+ ; ident
+ % To place tags in object files.
+
+ ; if_(
+ if_expr :: string
+ )
+ % Mark the beginning of a conditional section.
+
+ ; ifdef(
+ ifdef_symbol :: string
+ )
+ % Assemble the following section of code if 'ifdef_symbol' has been
+ % defined.
+
+ ; ifc(
+ ifc_string1 :: string,
+ ifc_string2 :: string
+ )
+ % Assemble the following section of code if the two strings are the
+ % same.
+
+ ; ifeq(
+ ifeq_expr :: string
+ )
+ % Assemble the following section of code if the argument is zero.
+
+ ; ifge(
+ ifge_expr :: string
+ )
+ % Assemble the following section of code if the argument is greater
+ % than equal to zero.
+
+ ; ifgt(
+ ifgt_expr :: string
+ )
+ % Assemble the following section of code if the argument is greater
+ % than zero.
+
+ ; ifle(
+ ifle_expr :: string
+ )
+ % Assemble the following section of code if the argument is less
+ % than equal to zero.
+
+ ; iflt(
+ iflt_expr :: string
+ )
+ % Assemble the following section of code if the argument is less
+ % than zero.
+
+ ; ifnc(
+ ifnc_string1 :: string,
+ ifnc_string2 :: string
+ )
+ % Assemble the following section of code if the two strings are not
+ % the same.
+
+ ; ifndef(
+ ifndef_symbol :: string
+ )
+ % Assemble the following section of code if 'ifndef_symbol' has not
+ % been defined.
+
+ ; ifnotdef(
+ ifnotdef_symbol :: string
+ )
+ % Synonym for ifndef.
+
+ ; ifne(
+ ifne_expr :: string
+ )
+ % Assemble the following section of code if the argument is not
+ % equal to zero.
+
+ ; ifnes(
+ ifnes_string1 :: string,
+ ifnes_string2 :: string
+ )
+ % Assemble the following section of code if the two strings are not
+ % the same.
+
+ ; include(
+ include_file :: string
+ )
+ % Include supporting 'include_file'.
+
+ ; int(
+ int_exprs :: list(string)
+ )
+ % 'int_exprs' contains zero or more expressions. For each
+ % expression, emit a number that, at run time, is the value of that
+ % expression.
+
+ ; internal(
+ internal_name :: string
+ )
+ % Like '.hidden' pseudo-op.
+
+ ; lcomm(
+ lcomm_symbol :: string,
+ lcomm_length :: int
+ )
+ % Reserve 'lcomm_length' bytes for a local common denoted by
+ % 'lcomm_symbol'.
+
+ ; line(
+ line_number :: int
+ )
+ % Change the logical line number.
+
+ ; list
+ % Control whether or not assembly listings are generated. This
+ % increments the internal counter.
+
+ ; long(
+ long_exprs :: list(string)
+ )
+ % Same as '.int'.
+
+ ; macro
+ % Define macro to generate assembly output.
+
+ ; nolist
+ % Control whether or not assembly listings are generated. It
+ % decrements an internal counter.
+
+ ; p2align(
+ p2align_pow_bit :: int,
+ p2align_fill_value :: maybe(int),
+ p2align_skip_bytes :: maybe(int)
+ )
+ % Advances the location counter until it is a multiple of
+ % 2 ^ ('p2align_pow_bit')
+ % p2align_fill_value: value to be stored in padding bytes.
+ % 'p2align_skip_bytes: maximum bytes to be skipped.
+
+ ; popsection
+ % Replace the current section (and subsection) with the top section
+ % (and subsection) on the section stack.
+
+ ; previous
+ % Swap the current section (and subsection) with most recently
+ % referenced secction (and subsection) prior to this one.
+
+ ; print(string)
+ % print string on the standard output.
+
+ ; protected(
+ protected_name :: string
+ )
+ % Like '.hidden' or '.internal'
+
+ ; psize(
+ psize_lines :: int,
+ psize_cols :: maybe(int)
+ )
+ % Declare the number of lines specified by 'psize_lines' and
+ % an optional number of columns specified by 'psize_cols'.
+
+ ; purgem(
+ purgem_name :: string
+ )
+ % Undefine the macro 'purgem_name' so that later uses of the string
+ % will not be expanded.
+
+ ; pushsection(
+ pushsection_name :: string,
+ pushsection_subsect :: int
+ )
+ % Push the current section (and subsection) onto the top of the
+ % section stack and then replace the current section and subsection
+ % with 'pushsection_name' and 'pushsection_subsect'.
+
+ ; quad(
+ quad_bignums :: list(string)
+ )
+ % 'quad_bignums' contains zero or more bignums. For each bignum, it
+ % emits an 8-byte-integer.
+
+ ; rept(
+ rept_count :: int
+ )
+ % Repeat the sequence of lines between the '.rept' directive and the
+ % next '.endr' directive 'rept_count' times.
+
+ ; sbttl(
+ sbttl_subheading :: string
+ )
+ % Use 'subttl_subheading' as the title (immediately after the title
+ % line).
+
+ ; scl(
+ scl_class :: string
+ )
+ % Set the storage-class value for a symbol.
+
+ ; section(
+ section_name :: string,
+ section_flags :: maybe(string),
+ section_type :: maybe(string),
+ section_entsize :: maybe(int)
+ )
+ % ELF section stack manipulation directive.
+
+ ; set(
+ set_symbol :: string,
+ set_expression :: string
+ )
+ % Set the value of 'set_symbol' to 'set_expression'
+
+ ; short(
+ short_exprs :: list(string)
+ )
+
+ ; single(
+ single_nums :: list(float)
+ )
+ % Has the same effect as '.float'.
+
+ ; size(
+ size_name :: string,
+ size_exprs :: string
+ )
+ % Set the size associated with symbol'size_name'. The size in bytes
+ % is computed from 'size_expr'.
+
+ ; skip(
+ skip_size :: int,
+ skip_value :: maybe(int)
+ )
+ % Emit 'skip_size' bytes, each of value 'skip_value' (optional).
+
+ ; sleb128(
+ sleb128_exprs :: list(string)
+ )
+ % Stand for "signed little endian base 128". It is a variable length
+ % representation of numbers used by the DWARF symbolic.
+
+ ; space(
+ space_size :: int,
+ space_fill :: maybe(int)
+ )
+ % Emit 'space_size' bytes, each of value 'space_fill' (optional).
+
+ ; string(
+ string_str :: list(string)
+ )
+ % Copy the characters in each string inside 'string_strs' to the
+ % object file.
+
+ ; struct(
+ struct_expr :: string
+ )
+ % Switch to the absolute section and set the section offset to
+ % 'struct_expr'.
+
+ ; subsection(
+ subsection_name :: string
+ )
+ % Replace the current subsection with 'subsection_name'.
+
+ ; symver(
+ symver_name :: string,
+ symver_alias :: string
+ )
+ % If 'symver_name' is defined within the file being assembled, it
+ % creates a symbol alias with the name 'symver_alias'
+
+ ; tag(
+ tag_struct_name :: string
+ )
+ % Include auxiliary debugging information in the symbol table.
+
+ ; text(
+ text_subsection :: maybe(int)
+ )
+ % Assemble the following statements onto the end of the text
+ % subsection numbered zero or 'text_subsection' (if present).
+
+ ; title(
+ title_heading :: string
+ )
+ % Use 'title_heading' as the title when generating assembly listing.
+
+ ; type_(
+ type_name :: string,
+ type_desc :: string
+ )
+ % Set the type of symbol'type_name' to be either a function or an
+ % object symbol.
+
+ ; uleb128(
+ uleb128_exprs :: list(string)
+ )
+ % Stands for "unsigned little endian base 128". It is a variable
+ % length representation of numbers used by the DWARF symbolic
+ % debugging format.
+
+ ; val(
+ val_addr :: string
+ )
+ % Record 'val_addr' as the value attribute of a symbol table entry.
+
+ ; version(
+ version_note :: string
+ )
+ % Create a '.note' section and places into it an ELF formatted note
+ % of type NT_VERSION>
+
+ ; weak(
+ weak_names :: list(string)
+ )
+ % Set the weak attribute on the list of symbol in 'weak_names'. If
+ % the symbol has not existed, it will be created.
+
+ ; word(
+ word_exprs :: list(string)
+ ).
+ % 'word_exprs' contains zero or more expressions.
+
+%-----------------------------------------------------------------------------%
+%
+% x86_64 registers.
+%
+
+ % 64-bit RFLAGS register holding various status flags and one control flag.
+ % Details on amd64-prog-man-vol1 manual p38.
+ %
+:- type flags_reg
+ ---> rflags(int).
+
+ % General purpose registers on the x86_64.
+ % Details on amd64-prog-man-vol1 manual p27.
+ %
+:- type gp_reg
+ ---> rax
+ ; rbx
+ ; rcx
+ ; rdx
+ ; rbp
+ ; rsi
+ ; rdi
+ ; rsp
+ ; r8
+ ; r9
+ ; r10
+ ; r11
+ ; r12
+ ; r13
+ ; r14
+ ; r15.
+
+ % 64-bit instruction pointer register on the x86_64. Instruction pointer
+ % RIP is used as a base register for relative addressing. x86_64
+ % instructions using RIP can be:
+ % rip_constant(%rip)
+ % rip_expr(%rip)
+ % Details on GNU assembler 'as' documentation in the section entitled
+ % "Machine Dependencies: i386-Dependent: i386-Memory".
+ %
+:- type instr_ptr
+ ---> rip_constant(
+ rip_byte_offset :: int32
+ )
+
+ ; rip_expr(
+ rip_expr :: string
+ ).
+
+%-----------------------------------------------------------------------------%
+%
+% Operands for x86_64 instructions.
+%
+
+ % Immediate operands for the x86_64 instruction.
+ %
+:- type imm_operand
+ ---> imm8(int8)
+ ; imm16(int16)
+ ; imm32(int32).
+
+ % Memory reference operands for the x86_64 instruction can be an absolute
+ % address (given as a displacement from the base address of a data segment)
+ % or an instruction-relative address.
+ % Details on amd64-prog-man-vol1 p19.
+ %
+:- type mem_ref
+ ---> mem_abs(
+ mem_abs_address :: base_address
+ )
+
+ ; mem_rip(
+ instr_rel_address :: instr_ptr
+ ).
+
+ % Base address can be relative to the content of a general-purpose register
+ % or relative value of an expression (such as arithmetic expression
+ % containing labels in data segment).
+ %
+:- type base_address
+ ---> base_reg(
+ base_offset :: int,
+ base_reg :: gp_reg
+ )
+
+ ; base_expr(
+ base_expr :: string
+ ).
+
+ % All operands for the x86_64 instructions.
+ %
+:- type operand
+ ---> operand_reg(gp_reg)
+ ; operand_imm(imm_operand)
+ ; operand_mem_ref(mem_ref).
+
+
+%
+% Subtypes of the operand type.
+% XXX maybe we should use inst-subtyping for these?
+%
+
+ % x86_64_instruction's operand is either the content a general-purpose
+ % register or the content of a memory reference.
+ %
+:- type reg_or_mem_ref_op
+ ---> rmro_reg(gp_reg)
+ ; rmro_mem_ref(mem_ref).
+
+ % x86_64_instruction's operand is either the contents of a general-purpose
+ % register or the value of an immediate operand.
+ %
+:- type reg_or_imm_op
+ ---> rio_reg(gp_reg)
+ ; rio_imm(imm_operand).
+
+ % x86_64_instruction's operand is either the content of CL register (the
+ % bottom 16 bits of RCX register) or an 8-bit immediate value.
+ %
+:- type cl_reg_or_imm_op
+ ---> crio_reg_cl(gp_reg)
+ ; crio_imm8(int8).
+
+ % x86_64 instruction's operand is an offset relative to the instruction
+ % pointer.
+ %
+:- type rel_offset
+ ---> ro8(int8) % Signed 8-bit offset (in bottom 8 bits).
+ ; ro16(int16) % Signed 16-bit offset (in bottom 16 bits).
+ ; ro32(int32). % Signed 32-bit offset (in bottom 32 bits).
+
+ % x86_64 instruction's operand can be a register, memory reference,
+ % signed relative offset or a label.
+ %
+:- type rmrol
+ ---> rmrol_reg(gp_reg)
+ ; rmrol_mem_ref(mem_ref)
+ ; rmrol_rel_offset(rel_offset)
+ ; rmrol_label(
+ rmrol_label_name :: string
+ ).
+
+%-----------------------------------------------------------------------------%
+%
+% x86_64 instructions.
+%
+
+ % We use At&T style instructions where the source comes before the
+ % destination.
+ %
+:- type x86_64_op
+ ---> adc(
+ adc_src :: operand,
+ adc_dst :: reg_or_mem_ref_op
+ )
+ % Add with carry. Add 'adc_src' to 'adc_dst' + carry flag (CF).
+ % Details on amd64-prog-man-vol3 manual p65.
+
+ ; add(
+ add_src :: operand,
+ add_dst :: reg_or_mem_ref_op
+ )
+ % Signed or unsigned add. Add 'adc_src' to 'adc_dst'.
+ % Details on amd64-prog-man-vol3 manual p67.
+
+ ; and(
+ and_src :: operand,
+ and_dst :: reg_or_mem_ref_op
+ )
+ % Performs a bitwise AND operation on both operands.
+ % Details on amd64-prog-man-vol3 manual p69.
+
+ ; bsf(
+ bsf_src :: reg_or_mem_ref_op,
+ bsf_dst :: gp_reg
+ )
+ % Bit scan forward. Searches the value in 'bsf_src' for the least
+ % significant set bit.
+ % Details on amd64-prog-man-vol3 manual p74.
+
+ ; bsr(
+ bsr_src :: reg_or_mem_ref_op,
+ bsr_dst :: gp_reg
+ )
+ % Bit scan reverse. Searches the value in 'bsf_src' for the most
+ % significant set bit.
+ % Details on amd64-prog-man-vol3 manual p75.
+
+ ; bswap(gp_reg)
+ % Byte swap. Reverses the byte order of the specified 'gp_reg'.
+ % Details on amd64-prog-man-vol3 manual p76.
+
+ ; bt(
+ bt_src :: reg_or_mem_ref_op,
+ bt_idx :: reg_or_imm_op
+ )
+ % Bit test. Copies a bit specified by 'bt_idx' from a bit string in
+ % 'bt_src' to the carry flag (CF) or RFLAGS register.
+ % Details on amd64-prog-man-vol3 manual p77.
+
+ ; btc(
+ btc_src :: reg_or_mem_ref_op,
+ btc_idx :: reg_or_imm_op
+ )
+ % Bit test and complement. Complements 'btc_src' after performing
+ % 'bt' operation.
+ % Details on amd64-prog-man-vol3 manual p79.
+
+ ; btr(
+ btr_src :: reg_or_mem_ref_op,
+ btr_idx :: reg_or_imm_op
+ )
+ % Bit test and reverse. Clears 'btr_src' to 0 after performing 'bt'
+ % operation.
+ % Details on amd64-prog-man-vol3 manual p81.
+
+ ; bts(
+ bts_src :: reg_or_mem_ref_op,
+ bts_idx :: reg_or_imm_op
+ )
+ % Bit test and set. Sets 'bts_src' to 1 after performing 'bt'
+ % operation.
+ % Details on amd64-prog-man-vol3 manual p83.
+
+ ; call(rmrol)
+ % Call with target specified by 'rmrol': register, memory location,
+ % relative offset or a label.
+ % Details on amd64-prog-man-vol3 manual p85.
+
+ ; cbw
+ % Sign-extend AL into AX.
+ % Details on amd64-prog-man-vol3 manual p94.
+
+ ; cwde
+ % Sign-extend AX into EAX.
+ % Details on amd64-prog-man-vol3 manual p94.
+
+ ; cdqe
+ % Sign-extend EAX into RAX.
+ % Details on amd64-prog-man-vol3 manual p94.
+
+ ; cwd
+ % Sign-extend AX into DX:AX.
+ % Details on amd64-prog-man-vol3 manual p95.
+
+ ; cdq
+ % Sign-extend EAX into EDX:EAX.
+ % Details on amd64-prog-man-vol3 manual p95.
+
+ ; cqo
+ % Sign-extend RAX into RDX:RAX.
+ % Details on amd64-prog-man-vol3 manual p95.
+
+ ; clc
+ % Clears the carry flag (CF) in the rFLAGS register to zero.
+ % Details on amd64-prog-man-vol3 manual p96.
+
+ ; cld
+ % Clears the direction flag (DF) in the rFLAGS register to zero.
+ % Details on amd64-prog-man-vol3 manual p97.
+
+ ; cmc
+ % Complements the carry flag bit (CF) bit in the rFLAGS register.
+ % Details on amd64-prog-man-vol3 manual p100.
+
+ ; cmovo(
+ cmovo_src :: reg_or_mem_ref_op,
+ cmovo_dest :: gp_reg
+ )
+ % Moves if overflow (OF = 1).
+ % Details on amd64-prog-man-vol3 manual p101.
+
+ ; cmovno(
+ cmovno_src :: reg_or_mem_ref_op,
+ cmovno_dest :: gp_reg
+ )
+ % Moves if not overflow (OF = 0).
+ % Details on amd64-prog-man-vol3 manual p101.
+
+ ; cmovb(
+ cmovb_src :: reg_or_mem_ref_op,
+ cmovb_dest :: gp_reg
+ )
+ % Moves if below (CF = 1).
+ % Details on amd64-prog-man-vol3 manual p101.
+
+ ; cmovc(
+ cmovc_src :: reg_or_mem_ref_op,
+ cmovc_dest :: gp_reg
+ )
+ % Moves if carry (CF = 1).
+ % Details on amd64-prog-man-vol3 manual p101.
+
+ ; cmovnae(
+ cmovnae_src :: reg_or_mem_ref_op,
+ cmovnae_dest :: gp_reg
+ )
+ % Moves if not above or equal (CF = 1).
+ % Details on amd64-prog-man-vol3 manual p101.
+
+ ; cmovnb(
+ cmovnb_src :: reg_or_mem_ref_op,
+ cmovnb_dest :: gp_reg
+ )
+ % Moves if not below (CF = 0).
+ % Details on amd64-prog-man-vol3 manual p101.
+
+ ; cmovnc(
+ cmovnc_src :: reg_or_mem_ref_op,
+ cmovnc_dest :: gp_reg
+ )
+ % Moves if not carry (CF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovae(
+ cmovae_src :: reg_or_mem_ref_op,
+ cmovae_dest :: gp_reg
+ )
+ % Moves if above or equal (CF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovz(
+ cmovz_src :: reg_or_mem_ref_op,
+ cmovz_dest :: gp_reg
+ )
+ % Moves if zero (ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmove(
+ cmove_src :: reg_or_mem_ref_op,
+ cmove_dest :: gp_reg
+ )
+ % Moves if equal (ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovnz(
+ cmovnz_src :: reg_or_mem_ref_op,
+ cmovnz_dest :: gp_reg
+ )
+ % Moves if not zero (ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovne(
+ cmovne_src :: reg_or_mem_ref_op,
+ cmovne_dest :: gp_reg
+ )
+ % Moves if not equal (ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovbe(
+ cmovbe_src :: reg_or_mem_ref_op,
+ cmovbe_dest :: gp_reg
+ )
+ % Moves if below or equal (CF = 1 or ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovna(
+ cmovna_src :: reg_or_mem_ref_op,
+ cmovna_dest :: gp_reg
+ )
+ % Moves if not above (CF = 1 or ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovnbe(
+ cmovnbe_src :: reg_or_mem_ref_op,
+ cmovnbe_dest :: gp_reg
+ )
+ % Moves if not below or equal (CF = 0 or ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmova(
+ cmova_src :: reg_or_mem_ref_op,
+ cmova_dest :: gp_reg
+ )
+ % Moves if above (CF = 1 or ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovs(
+ cmovs_src :: reg_or_mem_ref_op,
+ cmovs_dest :: gp_reg
+ )
+ % Moves if sign (SF = 1).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovns(
+ cmovns_src :: reg_or_mem_ref_op,
+ cmovns_dest :: gp_reg
+ )
+ % Moves if not sign (SF = 0).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovp(
+ cmovp_src :: reg_or_mem_ref_op,
+ cmovp_dest :: gp_reg
+ )
+ % Moves if parity (PF = 1).
+ % Details on amd64-prog-man-vol3 manual p102.
+
+ ; cmovpe(
+ cmovpe_src :: reg_or_mem_ref_op,
+ cmovpe_dest :: gp_reg
+ )
+ % Moves if parity even (PF = 1).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovnp(
+ cmovnp_src :: reg_or_mem_ref_op,
+ cmovnp_dest :: gp_reg
+ )
+ % Moves if not parity (PF = 0).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovpo(
+ cmovpo_src :: reg_or_mem_ref_op,
+ cmovpo_dest :: gp_reg
+ )
+ % Moves if parity odd (PF = 0).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovl(
+ cmovl_src :: reg_or_mem_ref_op,
+ cmovl_dest :: gp_reg
+ )
+ % Moves if less (SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovnge(
+ cmovnge_src :: reg_or_mem_ref_op,
+ cmovnge_dest :: gp_reg
+ )
+ % Moves if not greater or equal (SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovnl(
+ cmovnl_src :: reg_or_mem_ref_op,
+ cmovnl_dest :: gp_reg
+ )
+ % Moves if not less (SF = OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovge(
+ cmovge_src :: reg_or_mem_ref_op,
+ cmovge_dest :: gp_reg
+ )
+ % Moves if greater or equal (SF = OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovle(
+ cmovle_src :: reg_or_mem_ref_op,
+ cmovle_dest :: gp_reg
+ )
+ % Moves if less or equal (ZF = 1 or SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovng(
+ cmovng_src :: reg_or_mem_ref_op,
+ cmovng_dest :: gp_reg
+ )
+ % Moves if not greater (ZF = 1 or SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovnle(
+ cmovnle_src :: reg_or_mem_ref_op,
+ cmovnle_dest :: gp_reg
+ )
+ % Moves if not less or equal (ZF = 0 or SF = OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmovg(
+ cmovg_src :: reg_or_mem_ref_op,
+ cmovg_dest :: gp_reg
+ )
+ % Moves if greater (ZF = 0 or SF = OF).
+ % Details on amd64-prog-man-vol3 manual p103.
+
+ ; cmp(
+ cmp_src :: operand,
+ cmp_dest :: reg_or_mem_ref_op
+ )
+ % Compares 'cmp_src' with 'cmp_dest'.
+ % Details on amd64-prog-man-vol3 manual p105.
+
+ ; cmpxchg(
+ cmpxchg_cmp :: reg_or_mem_ref_op,
+ cmpxchg_xchg :: gp_reg
+ )
+ % Compares the value in RAX with the value in 'cmpxchg_cmp'.
+ % If equal, copies the value in 'cmpxchg_xchg' to 'cmpxchg_cmp'.
+ % Details on amd64-prog-man-vol3 manual p111.
+
+ ; cmpxchg8b(mem_ref)
+ % Compares the value in EDX:EAX with the value in 'mem_ref'.
+ % Details on amd64-prog-man-vol3 manual p113.
+
+ ; dec(reg_or_mem_ref_op)
+ % Decrements the contents of 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p120.
+
+ ; div(reg_or_mem_ref_op)
+ % Unsigned divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p122.
+
+ ; enter(
+ enter_stack_size :: uint16,
+ enter_nesting_level :: uint8
+ )
+ % Creates a procedure stack frame with a stack size specified in
+ % 'enter_stack_size' and nesting level specified in
+ % 'enter_nesting_level'(0 to 31).
+ % Details on amd64-prog-man-vol3 manual p124.
+
+ ; idiv(reg_or_mem_ref_op)
+ % Signed divide RDX:RAX by the value in 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p126.
+
+ ; imul(reg_or_mem_ref_op)
+ % Signed multiply RAX by the value in 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p128.
+
+ ; imul(
+ imul1_src :: reg_or_mem_ref_op,
+ imul1_dest :: gp_reg
+ )
+ % Signed multiply 'imul1_src' by 'imul1_dest'.
+ % Details on amd64-prog-man-vol3 manual p129.
+
+ ; imul(
+ imul2_src :: reg_or_mem_ref_op,
+ imul2_multiplicand :: imm_operand,
+ imul2_dest :: gp_reg
+ )
+ % Signed multiply 'imul2_src' by 'imul2_multiplicand'.
+ % Details on amd64-prog-man-vol3 manual p129.
+
+ ; inc(reg_or_mem_ref_op)
+ % Increments the contents of 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p133.
+
+ ; jo(rel_offset)
+ % Jumps if overflow (OF = 1).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jno(rel_offset)
+ % Jumps if not overflow (OF = 0).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jb(rel_offset)
+ % Jumps if below (CF = 1).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jc(rel_offset)
+ % Jumps if carry (CF = 1).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jnae(rel_offset)
+ % Jumps if not above or equal (CF = 1).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jnb(rel_offset)
+ % Jumps if not below (CF = 0).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jnc(rel_offset)
+ % Jumps if not carry (CF = 0).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jae(rel_offset)
+ % Jumps if above or equal (CF = 0).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jz(rel_offset)
+ % Jumps if zero (ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; je(rel_offset)
+ % Jumps if equal (ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jnz(rel_offset)
+ % Jumps if not zero (ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jne(rel_offset)
+ % Jumps if not equal (ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p147.
+
+ ; jbe(rel_offset)
+ % Jumps if below or equal (CF = 1 or ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jna(rel_offset)
+ % Jumps if not above (CF = 1 or ZF = 1).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jnbe(rel_offset)
+ % Jumps if not below or equal (CF = 0 or ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; ja(rel_offset)
+ % Jumps if above (CF = 0 or ZF = 0).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; js(rel_offset)
+ % Jumps if sign (SF = 1).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jns(rel_offset)
+ % Jumps if not sign (SF = 0).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jp(rel_offset)
+ % Jumps if parity (PF = 1).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jpe(rel_offset)
+ % Jumps if parity even (PF = 1).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jnp(rel_offset)
+ % Jumps if not parity (PF = 0).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jpo(rel_offset)
+ % Jumps if parity odd (PF = 0).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jl(rel_offset)
+ % Jumps if less (SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jnge(rel_offset)
+ % Jumps if not greater or equal (SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jnl(rel_offset)
+ % Jumps if not less (SF = OF).
+ % Details on amd64-prog-man-vol3 manual p148.
+
+ ; jge(rel_offset)
+ % Jumps if greater or equal (SF = OF).
+ % Details on amd64-prog-man-vol3 manual p149.
+
+ ; jle(rel_offset)
+ % Jumps if less or equal (ZF = 1 or SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p149.
+
+ ; jng(rel_offset)
+ % Jumps if not greater (ZF = 1 or SF <> OF).
+ % Details on amd64-prog-man-vol3 manual p149.
+
+ ; jnle(rel_offset)
+ % Jumps if not less or equal (ZF = 0 and SF = OF).
+ % Details on amd64-prog-man-vol3 manual p149.
+
+ ; jg(rel_offset)
+ % Jumps if greater (ZF = 0 and SF = OF).
+ % Details on amd64-prog-man-vol3 manual p149.
+
+ ; jrcxz(rel_offset)
+ % Jumps to the target instruction located at the specified 8-bit
+ % relative offset if RCX is zero.
+ % Details on amd64-prog-man-vol3 manual p150.
+
+ ; jmp(rmrol)
+ % Jumps with target specified in 'rmrol': register, memory location,
+ % relative offset or label.
+ % Details on amd64-prog-man-vol3 manual p152.
+
+ ; lea(
+ lea_src :: mem_ref,
+ lea_dest :: gp_reg
+ )
+ % Stores effective address 'lea_src' into 'lea_dest'.
+ % Details on amd64-prog-man-vol3 manual p163.
+
+ ; leave
+ % Sets RSP to the value in RBP and pop RBP.
+ % Details on amd64-prog-man-vol3 manual p164.
+
+ ; loop(
+ loop_rel_8bit :: rel_offset
+ )
+ % Decrements RCX then jump if RCX is not zero
+ % Details on amd64-prog-man-vol3 manual p169.
+
+ ; loope(
+ loope_rel_8bit :: rel_offset
+ )
+ % Decrements RCX then jump if RCX is not zero and ZF = 1.
+ % Details on amd64-prog-man-vol3 manual p169.
+
+ ; loopne(
+ loopne_rel_8bit :: rel_offset
+ )
+ % Decrements RCX then jump if RCX is not zero and ZF = 0.
+ % Details on amd64-prog-man-vol3 manual p169.
+
+ ; loopnz(
+ loopnz_rel_8bit :: rel_offset
+ )
+ % Decrements RCX then jump if RCX is not zero and ZF = 0.
+ % Details on amd64-prog-man-vol3 manual p170.
+
+ ; loopz(
+ loopz_rel_8bit :: rel_offset
+ )
+ % Decrements RCX then jump if RCX is not zero and ZF = 1.
+ % Details on amd64-prog-man-vol3 manual p170.
+
+ ; mov(
+ mov_src :: operand,
+ mov_dest :: reg_or_mem_ref_op
+ )
+ % Copies 'mov_src' to 'mov_dest'.
+ % Details on amd64-prog-man-vol3 manual p173.
+
+ ; mul(reg_or_mem_ref_op)
+ % Unsigned multiply 'reg_or_mem_ref_op' by RAX.
+ % Details on amd64-prog-man-vol3 manual p190.
+
+ ; neg(reg_or_mem_ref_op)
+ % Performs a two's complement negation of 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p192.
+
+ ; nop
+ % Increments RIP to point to next instruction.
+ % Details on amd64-prog-man-vol3 manual p194.
+
+ ; not_(reg_or_mem_ref_op)
+ % Performs one's complement negation (NOT) of 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p195.
+
+ ; or(
+ or_src :: operand,
+ or_dest :: reg_or_mem_ref_op
+ )
+ % Performs a logical OR on the bits in 'or_src' and 'or_dest'.
+ % Details on amd64-prog-man-vol3 manual p196.
+
+ ; pop(reg_or_mem_ref_op)
+ % Pops the stack into 'reg_or_mem_ref_op'.
+ % Details on amd64-prog-man-vol3 manual p204.
+
+ ; popfq
+ % Pops a quadword from the stack to the RFLAGS register.
+ % Details on amd64-prog-man-vol3 manual p208.
+
+ ; push(operand)
+ % Pushes the content of operand onto the stack.
+ % Details on amd64-prog-man-vol3 manual p215.
+
+ ; pushfq
+ % Pushes the RFLAGS quadword onto the stack.
+ % Details on amd64-prog-man-vol3 manual p218.
+
+ ; ret
+ % Near return to the calling procedure.
+ % Details on amd64-prog-man-vol3 manual p224.
+
+ ; rcl(
+ rcl_amount :: cl_reg_or_imm_op,
+ rcl_dest :: reg_or_mem_ref_op
+ )
+ % Rotate bits in 'rcl_dest' to the left and through the carry flag
+ % by the number of bit positions as specified in 'rcl_amount'.
+ % Details on amd64-prog-man-vol3 manual p220.
+
+ ; rcr(
+ rcr_amount :: cl_reg_or_imm_op,
+ rcr_dest :: reg_or_mem_ref_op
+ )
+ % Rotate bits in 'rcr_dest' to the right and through the carry flag
+ % by the number of bit positions as specified in 'rcr_amount'.
+ % Details on amd64-prog-man-vol3 manual p222.
+
+ ; ret(uint16)
+ % Near return to the calling procedure, then pop the specified
+ % number of bytes from stack.
+ % Details on amd64-prog-man-vol3 manual p224.
+
+ ; rol(
+ rol_amount :: cl_reg_or_imm_op,
+ rol_dest :: reg_or_mem_ref_op
+ )
+ % Rotates the bits of 'rol_dest' left by 'rol_amount' bits.
+ % Details on amd64-prog-man-vol3 manual p230.
+
+ ; ror(
+ ror_amount :: cl_reg_or_imm_op,
+ ror_dest :: reg_or_mem_ref_op
+ )
+ % Rotates the bits of 'ror_dest' right by 'ror_amount bits'.
+ % Details on amd64-prog-man-vol3 manual p232.
+
+ ; sal(
+ sal_amount :: cl_reg_or_imm_op,
+ sal_dest :: reg_or_mem_ref_op
+ )
+ % Shift 'sal_dest' left by 'sal_amount'.
+ % Details on amd64-prog-man-vol3 manual p235.
+
+ ; shl(
+ shl_amount :: cl_reg_or_imm_op,
+ shl_dest :: reg_or_mem_ref_op
+ )
+ % Shift 'shl_dest' left by 'shl_amount'.
+ % Details on amd64-prog-man-vol3 manual p235.
+
+ ; sar(
+ sar_amount :: cl_reg_or_imm_op,
+ sar_dest :: reg_or_mem_ref_op
+ )
+ % Shift 'sar_dest' right by 'sar_amount'.
+ % Details on amd64-prog-man-vol3 manual p238.
+
+ ; sbb(
+ sbb_src :: operand,
+ sbb_dest :: reg_or_mem_ref_op
+ )
+ % Subtracts 'sbb_src' from 'sbb_dest' with borrow.
+ % Details on amd64-prog-man-vol3 manual p241.
+
+ ; seto(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If overflow
+ % (OF = 1), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setno(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not overflow
+ % (OF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setb(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is below
+ % (CF = 1), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setc(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is carry
+ % (CF = 1), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setnae(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is not above
+ % or equal (CF = 1), set the value in the specified register or an
+ % 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setnb(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is not below
+ % (CF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setnc(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is not carry
+ % (CF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setae(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is above or
+ % equal (CF = 0), set the value in the specified register or an
+ % 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setz(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If zero (ZF = 1),
+ % set the value in the specified register or an 8-bit memory
+ % reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; sete(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If equal (ZF = 1),
+ % set the value in the specified register or an 8-bit memory
+ % reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setnz(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not zero
+ % (ZF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setne(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not equal
+ % (ZF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p246.
+
+ ; setbe(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If below or equal
+ % (CF = 1 or ZF = 1), set the value in the specified register or
+ % an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setna(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not above
+ % (CF = 1 or ZF = 1), set the value in the specified register or
+ % an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setnbe(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not below or
+ % equal (CF = 0 and ZF = 0), set the value in the specified
+ % register or an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; seta(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If above
+ % (CF = 0 and ZF = 0), set the value in the specified
+ % register or an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; sets(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is sign,
+ % (SF = 1), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setns(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is not sign,
+ % (SF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setp(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If flag is parity
+ % (PF = 1), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setpe(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If parity even,
+ % (PF = 1), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setnp(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not parity,
+ % (PF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setpo(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If parity odd,
+ % (PF = 0), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setl(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If less (SF <> OF),
+ % set the value in the specified register or an 8-bit memory
+ % reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setnge(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not greater or
+ % equal (SF <> OF), set the value in the specified register or an
+ % 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setnl(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not less
+ % (SF = OF), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setge(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If greater or equal
+ % (SF = OF), set the value in the specified register or an 8-bit
+ % memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setle(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If less or equal
+ % (ZF = 1 or SF <> OF), set the value in the specified register or
+ % an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setng(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not greater
+ % (ZF = 1 or SF <> OF), set the value in the specified register or
+ % an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setnle(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If not less or equal
+ % (ZF = 0 and SF = OF), set the value in the specified register or
+ % an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; setg(reg_or_mem_ref_op)
+ % Check the status flag in the RFLAGS register. If greater
+ % (ZF = 0 and SF = OF), set the value in the specified register or
+ % an 8-bit memory reference to 1.
+ % Details on amd64-prog-man-vol3 manual p247.
+
+ ; shld(
+ shld_amount :: cl_reg_or_imm_op,
+ shld_dest1 :: reg_or_mem_ref_op,
+ shld_dest2 :: gp_reg
+ )
+ % Shift 'shld_dest1' to the left by 'shld_amount' and shift in a bit
+ % pattern in 'shld_dest2' from the right.
+ % Details on amd64-prog-man-vol3 manual p251.
+
+ ; shr(
+ shr_amount :: cl_reg_or_imm_op,
+ shr_dest :: reg_or_mem_ref_op
+ )
+ % Shift 'shr_dest' right by 'shr_amount'.
+ % Details on amd64-prog-man-vol3 manual p253.
+
+ ; shrd(
+ shrd_amount :: cl_reg_or_imm_op,
+ shrd_dest1 :: reg_or_mem_ref_op,
+ shrd_dest2 :: gp_reg
+ )
+ % Shift 'shrd_dest1' to the right by 'shrd_amount' and shift in
+ % a bit pattern in 'shrd_dest2' from the left.
+ % Details on amd64-prog-man-vol3 manual p255.
+
+ ; stc
+ % Sets the carry flag (CF) in the RFLAGS register to 1.
+ % Details on amd64-prog-man-vol3 manual p257.
+
+ ; std
+ % Sets the direction flag (DF) in the rflags register to 1.
+ % Details on amd64-prog-man-vol3 manual p258.
+
+ ; sub(
+ sub_src :: operand,
+ sub_dest :: reg_or_mem_ref_op
+ )
+ % Subtracts 'sub_src' from 'sub_dest'.
+ % Details on amd64-prog-man-vol3 manual p261.
+
+ ; test(
+ test_src1 :: reg_or_mem_ref_op,
+ test_src2 :: reg_or_imm_op
+ )
+ % Performs a bitwise AND on 'test_src1' and 'test_src2'.
+ % Details on amd64-prog-man-vol3 manual p264.
+
+ ; xadd(
+ xadd_src :: gp_reg,
+ xadd_dest :: reg_or_mem_ref_op
+ )
+ % Exchanges the contents of 'xadd_src' with 'xadd_dest', load
+ % their sum into 'xadd_dest'.
+ % Details on amd64-prog-man-vol3 manual p266.
+
+ ; xchg(
+ xchg_src1 :: reg_or_mem_ref_op,
+ xchg_src2 :: reg_or_mem_ref_op
+ )
+ % Exchanges the contents of 'xchg_src1' and 'xchg_src2'.
+ % Details on amd64-prog-man-vol3 manual p268.
+
+ ; xor(
+ xor_src :: operand,
+ xor_dest :: reg_or_mem_ref_op
+ ).
+ % Performs a bitwise XOR on 'xor_src' with 'xor_dest' and stores
+ % the result in xor_dest.
+ % Details on amd64-prog-man-vol3 manual p272.
+
+%-----------------------------------------------------------------------------%
Index: compiler/x86_64_out.m
===================================================================
RCS file: compiler/x86_64_out.m
diff -N compiler/x86_64_out.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/x86_64_out.m 12 Jan 2007 04:29:28 -0000
@@ -0,0 +1,1311 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: x86_64_out.m.
+% Main author: fhandoko.
+%
+% This module defines the routines for printing out x86_64 instructions.
+%
+%-----------------------------------------------------------------------------%
+
+:- module ll_backend.x86_64_out.
+:- interface.
+
+:- import_module ll_backend.x86_64_instrs.
+
+:- import_module io.
+
+%-----------------------------------------------------------------------------%
+
+:- pred output_x86_64_instrs(x86_64_instr::in, io::di, io::uo) is det.
+
+ % XXX This is just for testing purposes.
+ %
+% :- pred pretend_main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module libs.compiler_util.
+
+:- import_module bool.
+:- import_module char.
+:- import_module int.
+:- import_module list.
+:- import_module maybe.
+:- import_module string.
+:- import_module type_desc.
+
+%-----------------------------------------------------------------------------%
+
+% pretend_main(!IO) :-
+% Comment1 = comment("This is a comment"),
+% Label1 = label(".L1"),
+% PseudoOps1 = [
+% abort,
+% align(6, no, yes(2)),
+% align(7, yes(12), no),
+% align(8, no, no),
+% ascii([".LI", ".L2"]),
+% comm(".L3", 8, no),
+% section(".data", no, no, no)
+% ],
+% Instrs1 = [
+% x86_64_instr(adc(operand_reg(rax),
+% rmro_reg(rbx)
+% ), ""),
+% x86_64_instr(add(operand_imm(imm8(int8(0x178))),
+% rmro_mem_ref(mem_abs(base_reg(0, r8)))
+% ), ""),
+% x86_64_instr(and(operand_reg(rdx),
+% rmro_mem_ref(mem_abs(base_reg(2, rdx)))
+% ), ""),
+% x86_64_instr(bsf(rmro_reg(r8), r15), ""),
+% x86_64_instr(bsr(rmro_reg(rcx), rax), ""),
+% x86_64_instr(bswap(r10), ""),
+% x86_64_instr(bt(rmro_mem_ref(mem_rip(rip_expr(".L1"))),
+% rio_reg(rsi)), ""),
+% x86_64_instr(btc(rmro_reg(rdi), rio_imm(imm16(int16(0x1822)))), ""),
+% x86_64_instr(btr(rmro_reg(rbp),
+% rio_imm(imm32(int32(0x182199)))), ""),
+% x86_64_instr(call(rmrol_rel_offset(ro8(int8(127)))), "comment"),
+% x86_64_instr(cmovo(rmro_mem_ref(mem_rip(rip_constant(int32(2)))),
+% r11), ""),
+% x86_64_instr(mov(operand_imm(imm32(int32(10))), rmro_reg(rbx)), ""),
+% x86_64_instr(or(operand_mem_ref(mem_rip(rip_constant(int32(2)))),
+% rmro_reg(rcx)), ""),
+% x86_64_instr(push(operand_mem_ref(mem_abs(base_expr(".L2")))), ""),
+% x86_64_instr(rol(crio_reg_cl(rcx), rmro_reg(rax)), ""),
+% x86_64_instr(ror(crio_imm8(int8(20)), rmro_mem_ref(mem_rip(
+% rip_expr(".L2")) )), ""),
+% x86_64_instr(sbb(operand_mem_ref(mem_rip(rip_expr(".L1"))),
+% rmro_reg(r11)), "")
+% ],
+%
+% Label2 = label(".L2"),
+% PseudoOps2 = [
+% section(".rodata", yes("aMS"), yes("@progbits"), yes(1)),
+% p2align(1,no,yes(7)),
+% type_("Type", "@function")
+% ],
+% Instrs2 = [
+% x86_64_instr(loop(ro8(int8(19))), "another comment"),
+% x86_64_instr(xor(operand_imm(imm32(int32(19))),
+% rmro_mem_ref(mem_rip(rip_expr(".L4")))
+% ), "comment"),
+% x86_64_instr(jo(ro8(int8(22))), "comment again"),
+% x86_64_instr(div(rmro_reg(rdx)), "comment div"),
+% x86_64_instr(jmp(rmrol_label(".L2")), "comment jmp"),
+% x86_64_instr(mov(operand_mem_ref(mem_abs(base_expr(".L3"))),
+% rmro_reg(rbx)), "")
+% ],
+%
+% Instructions = [
+% comment(""), label(""), directives([file("x86_64_out.m")]),
+% instrs([]),
+% Comment1, Label1, directives(PseudoOps1), instrs(Instrs1),
+% comment("Comment"), Label2, directives(PseudoOps2),
+% instrs(Instrs2)
+% ],
+% list.foldl(output_x86_64_instrs, Instructions, !IO).
+
+%-----------------------------------------------------------------------------%
+
+ % Output x86_64 instructions including comments, labels and pseudo-ops.
+ %
+output_x86_64_instrs(comment(Comment), !IO) :-
+ ( string.length(Comment) > 0 ->
+ io.write_string("# " ++ Comment ++ "\n", !IO)
+ ;
+ true
+ ).
+output_x86_64_instrs(label(LabelName), !IO) :-
+ ( string.length(LabelName) > 0 ->
+ io.write_string(LabelName ++ ":\n", !IO)
+ ;
+ true
+ ).
+output_x86_64_instrs(directives(PseudoOps), !IO) :-
+ list.foldl(output_x86_64_pseudo_op, PseudoOps, !IO).
+output_x86_64_instrs(instrs(Instrs), !IO) :-
+ ( list.length(Instrs) > 0 ->
+ output_x86_64_instr_and_comment(Instrs, !IO)
+ ;
+ true
+ ).
+
+%-----------------------------------------------------------------------------%
+%
+% Output x86_64 pseudo-op.
+%
+
+:- pred output_x86_64_pseudo_op(pseudo_op::in, io::di, io::uo) is det.
+
+output_x86_64_pseudo_op(abort, !IO) :-
+ io.write_string("\t.abort\n", !IO).
+output_x86_64_pseudo_op(align(Bytes, FillVal, SkipBytes), !IO) :-
+ output_pseudo_op_with_int_args(".align", Bytes, FillVal, SkipBytes, !IO).
+output_x86_64_pseudo_op(ascii(Literals), !IO) :-
+ output_pseudo_op_str_args(".ascii", Literals, !IO).
+output_x86_64_pseudo_op(asciiz(Literals), !IO) :-
+ output_pseudo_op_str_args(".asciiz", Literals, !IO).
+output_x86_64_pseudo_op(balign(Bytes, FillVal, SkipBytes), !IO) :-
+ output_pseudo_op_with_int_args(".balign", Bytes, FillVal, SkipBytes, !IO).
+output_x86_64_pseudo_op(byte(ExprList), !IO) :-
+ output_pseudo_op_str_args(".byte", ExprList, !IO).
+output_x86_64_pseudo_op(comm(Symbol, Length, Align0), !IO) :-
+ io.write_string("\t.comm\t" ++ Symbol ++ ",", !IO),
+ io.write_int(Length, !IO),
+ ( Align0 = yes(Align1) ->
+ io.write_string(",", !IO),
+ io.write_int(Align1, !IO)
+ ;
+ true
+ ),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(data(Subsection0), !IO) :-
+ io.write_string("\t.data\t", !IO),
+ ( Subsection0 = yes(Subsection1) ->
+ io.write_int(Subsection1, !IO)
+ ;
+ true
+ ),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(desc(Symbol, AbsExpr), !IO) :-
+ io.write_string("\t.desc\t" ++ Symbol ++ "," ++ AbsExpr ++ "\n", !IO).
+output_x86_64_pseudo_op(def(Name), !IO) :-
+ io.write_string("\t.def\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(dim, !IO) :-
+ io.write_string("\t.dim\n", !IO).
+output_x86_64_pseudo_op(double(NumList), !IO) :-
+ output_pseudo_op_float_args(".double", NumList, !IO).
+output_x86_64_pseudo_op(eject, !IO) :-
+ io.write_string("\t.eject\n", !IO).
+output_x86_64_pseudo_op(else_, !IO) :-
+ io.write_string("\t.else\n", !IO).
+output_x86_64_pseudo_op(elseif, !IO) :-
+ io.write_string("\t.elseif\n", !IO).
+output_x86_64_pseudo_op(end, !IO) :-
+ io.write_string("\t.end\n", !IO).
+output_x86_64_pseudo_op(endef, !IO) :-
+ io.write_string("\t.endef\n", !IO).
+output_x86_64_pseudo_op(endfunc, !IO) :-
+ io.write_string("\t.endfunc\n", !IO).
+output_x86_64_pseudo_op(endif, !IO) :-
+ io.write_string("\t.endif\n", !IO).
+output_x86_64_pseudo_op(endm, !IO) :-
+ io.write_string("\t.endm\n", !IO).
+output_x86_64_pseudo_op(equ(Symbol, Expr), !IO) :-
+ io.write_string("\t.equ\t" ++ Symbol ++ "," ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(equiv(Symbol, Expr), !IO) :-
+ io.write_string("\t.equiv\t" ++ Symbol ++ "," ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(err, !IO) :-
+ io.write_string("\t.err\n", !IO).
+output_x86_64_pseudo_op(exitm, !IO) :-
+ io.write_string("\t.exitm\n", !IO).
+output_x86_64_pseudo_op(extern, !IO) :-
+ io.write_string("\t.extern\n", !IO).
+output_x86_64_pseudo_op(fail_(Expr), !IO) :-
+ io.write_string("\t.fail\t" ++ Expr++ "\n", !IO).
+output_x86_64_pseudo_op(file(Name), !IO) :-
+ io.write_string("\t.file\t\"" ++ Name ++ "\"\n", !IO).
+output_x86_64_pseudo_op(fill(Repeat, Size, Val), !IO) :-
+ output_pseudo_op_with_int_args(".repeat", Repeat, Size, Val, !IO).
+output_x86_64_pseudo_op(float(NumList), !IO) :-
+ output_pseudo_op_float_args(".float", NumList, !IO).
+output_x86_64_pseudo_op(func_(Name, Label), !IO) :-
+ io.write_string("\t.func\t" ++ Name ++ "," ++ Label ++ "\n", !IO).
+output_x86_64_pseudo_op(global(Symbol), !IO) :-
+ io.write_string("\t.global\t" ++ Symbol ++ "\n", !IO).
+output_x86_64_pseudo_op(globl(Symbol), !IO) :-
+ io.write_string("\t.globl\t" ++ Symbol ++ "\n", !IO).
+output_x86_64_pseudo_op(hidden(Name), !IO) :-
+ io.write_string("\t.hidden\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(hword(ExprList), !IO) :-
+ output_pseudo_op_str_args(".hword", ExprList, !IO).
+output_x86_64_pseudo_op(ident, !IO) :-
+ io.write_string("\t.ident\n", !IO).
+output_x86_64_pseudo_op(if_(Expr), !IO) :-
+ io.write_string("\t.if\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(ifdef(Symbol), !IO) :-
+ io.write_string("\t.ifdef\t" ++ Symbol ++ "\n", !IO).
+output_x86_64_pseudo_op(ifc(Str1, Str2), !IO) :-
+ io.write_string("\t.ifc\t" ++ Str1 ++ "," ++ Str2 ++ "\n", !IO).
+output_x86_64_pseudo_op(ifeq(Expr), !IO) :-
+ io.write_string("\t.ifeq\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(ifge(Expr), !IO) :-
+ io.write_string("\t.ifge\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(ifgt(Expr), !IO) :-
+ io.write_string("\t.ifgt\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(ifle(Expr), !IO) :-
+ io.write_string("\t.ifle\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(iflt(Expr), !IO) :-
+ io.write_string("\t.iflt\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(ifnc(Str1, Str2), !IO) :-
+ io.write_string("\t.ifnc\t" ++ Str1 ++ "," ++ Str2 ++ "\n", !IO).
+output_x86_64_pseudo_op(ifndef(Symbol), !IO) :-
+ io.write_string("\t.ifndef\t" ++ Symbol ++ "\n", !IO).
+output_x86_64_pseudo_op(ifnotdef(Symbol), !IO) :-
+ io.write_string("\t.ifnotdef\t" ++ Symbol ++ "\n", !IO).
+output_x86_64_pseudo_op(ifne(Expr), !IO) :-
+ io.write_string("\t.ifne\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(ifnes(Str1, Str2), !IO) :-
+ io.write_string("\t.ifnes\t" ++ Str1 ++ "," ++ Str2 ++ "\n", !IO).
+output_x86_64_pseudo_op(include(File), !IO) :-
+ io.write_string("\t.include\t" ++ "\"" ++ File ++ "\"\n", !IO).
+output_x86_64_pseudo_op(int(ExprList), !IO) :-
+ output_pseudo_op_str_args(".int", ExprList, !IO).
+output_x86_64_pseudo_op(internal(Name), !IO) :-
+ io.write_string("\t.internal\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(lcomm(Symbol, Length), !IO) :-
+ io.write_string("\tlcomm\t" ++ Symbol, !IO),
+ io.write_int(Length, !IO),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(line(LineNum), !IO) :-
+ io.write_string("\t.line\t", !IO),
+ io.write_int(LineNum, !IO),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(list, !IO) :-
+ io.write_string("\t.list\n", !IO).
+output_x86_64_pseudo_op(long(ExprList), !IO) :-
+ output_pseudo_op_str_args(".long", ExprList, !IO).
+output_x86_64_pseudo_op(macro, !IO) :-
+ io.write_string("\t.macro\n", !IO).
+output_x86_64_pseudo_op(nolist, !IO) :-
+ io.write_string("\t.nolist\n", !IO).
+output_x86_64_pseudo_op(p2align(PowBit, FillVal, SkipBytes), !IO) :-
+ output_pseudo_op_with_int_args(".p2align", PowBit, FillVal, SkipBytes, !IO).
+output_x86_64_pseudo_op(popsection, !IO) :-
+ io.write_string("\t.popsection\n", !IO).
+output_x86_64_pseudo_op(previous, !IO) :-
+ io.write_string("\t.previous\n", !IO).
+output_x86_64_pseudo_op(print(Str), !IO) :-
+ io.write_string("\t.print\t" ++ Str ++ "\n", !IO).
+output_x86_64_pseudo_op(protected(Name), !IO) :-
+ io.write_string("\t.protected\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(psize(Lines, Cols), !IO) :-
+ output_pseudo_op_with_int_args(".psize", Lines, Cols, no, !IO).
+output_x86_64_pseudo_op(purgem(Name), !IO) :-
+ io.write_string("\t.purgem\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(pushsection(Name, Subsection), !IO) :-
+ io.write_string("\t.pushsection\t" ++ Name, !IO),
+ io.write_int(Subsection, !IO),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(quad(BigNumList), !IO) :-
+ output_pseudo_op_str_args("\t.quad\t", BigNumList, !IO).
+output_x86_64_pseudo_op(rept(Count), !IO) :-
+ io.write_string("\t.rept\t", !IO),
+ io.write_int(Count, !IO),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(sbttl(SubHeading), !IO) :-
+ io.write_string("\t.sbttl\t" ++ "\"" ++ SubHeading ++ "\"\n", !IO).
+output_x86_64_pseudo_op(scl(Class), !IO) :-
+ io.write_string("\t.scl\t" ++ Class ++ "\n", !IO).
+output_x86_64_pseudo_op(section(Name, Flags0, Type0, EntSize0), !IO) :-
+ io.write_string("\t.section\t" ++ Name, !IO),
+ ( Flags0 = yes(Flags1) ->
+ check_section_flags_and_type(Flags1, Type0, Result0),
+ (
+ Result0 = yes,
+ Type0 = yes(Type1)
+ ->
+ io.write_string(",\"" ++ Flags1 ++ "\"", !IO),
+ ( check_pseudo_section_type(Type1) ->
+ io.write_string("," ++ Type1, !IO)
+ ;
+ unexpected(this_file, "output_x86_64_pseudo_op: section:
+ check_section_type unexpected")
+ )
+ ;
+ unexpected(this_file, "output_x86_64_pseudo_op: section:
+ check_section_flags_and_type unexpected")
+ )
+ ;
+ true
+ ),
+ ( EntSize0 = yes(EntSize1)->
+ io.write_string(",", !IO),
+ io.write_int(EntSize1, !IO)
+ ;
+ true
+ ),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(set(Symbol, Expr), !IO) :-
+ io.write_string("\t.set\t" ++ Symbol ++ "," ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(short(ExprList), !IO) :-
+ output_pseudo_op_str_args(".short", ExprList, !IO).
+output_x86_64_pseudo_op(single(FloatList), !IO) :-
+ output_pseudo_op_float_args(".single", FloatList, !IO).
+output_x86_64_pseudo_op(size(Name, Expr), !IO) :-
+ io.write_string("\t.size\t" ++ Name ++ "," ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(skip(Size, Val), !IO) :-
+ output_pseudo_op_with_int_args(".skip", Size, Val, no, !IO).
+output_x86_64_pseudo_op(sleb128(ExprList), !IO) :-
+ output_pseudo_op_str_args(".sleb128\t", ExprList, !IO).
+output_x86_64_pseudo_op(space(Size, Fill), !IO) :-
+ output_pseudo_op_with_int_args(".space", Size, Fill, no, !IO).
+output_x86_64_pseudo_op(string(StrList), !IO) :-
+ output_pseudo_op_str_args(".string", StrList, !IO).
+output_x86_64_pseudo_op(struct(Expr), !IO) :-
+ io.write_string("\t.struct\t" ++ Expr ++ "\n", !IO).
+output_x86_64_pseudo_op(subsection(Name), !IO) :-
+ io.write_string("\t.subsection\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(symver(Name, Alias), !IO) :-
+ io.write_string("\t.symver\t" ++ Name ++ "," ++ Alias ++ "\n", !IO).
+output_x86_64_pseudo_op(tag(Name), !IO) :-
+ io.write_string("\t.tag\t" ++ Name ++ "\n", !IO).
+output_x86_64_pseudo_op(text(Subsection0), !IO) :-
+ io.write_string("\ttext\t", !IO),
+ ( Subsection0 = yes(Subsection1) ->
+ io.write_int(Subsection1, !IO)
+ ;
+ true
+ ),
+ io.write_string("\n", !IO).
+output_x86_64_pseudo_op(title(Heading), !IO) :-
+ io.write_string("\t.title\t" ++ Heading ++ "\n", !IO).
+output_x86_64_pseudo_op(type_(Name, Desc), !IO) :-
+ ( check_pseudo_type_desc(Desc) ->
+ io.write_string("\t.type\t" ++ Name ++ "," ++ Desc ++ "\n", !IO)
+ ;
+ unexpected(this_file, "output_x86_64_pseudo_op: type_ unexpected")
+ ).
+output_x86_64_pseudo_op(uleb128(ExprList), !IO) :-
+ output_pseudo_op_str_args(".uleb128", ExprList, !IO).
+output_x86_64_pseudo_op(val(Addr), !IO) :-
+ io.write_string("\t.val\t" ++ Addr ++ "\n", !IO).
+output_x86_64_pseudo_op(version(Note), !IO) :-
+ io.write_string("\t.version\t" ++ Note ++ "\n", !IO).
+output_x86_64_pseudo_op(weak(NameList), !IO) :-
+ output_pseudo_op_str_args(".weak", NameList, !IO).
+output_x86_64_pseudo_op(word(ExprList), !IO) :-
+ output_pseudo_op_str_args(".word", ExprList, !IO).
+
+ % Output pseudo-op name with 1, 2 or 3 integer arguments.
+ %
+:- pred output_pseudo_op_with_int_args(string::in, int::in, maybe(int)::in,
+ maybe(int)::in, io::di, io::uo) is det.
+
+output_pseudo_op_with_int_args(OpName, Arg1, Arg2, Arg3, !IO) :-
+ io.write_string("\t" ++ OpName ++ "\t", !IO),
+ io.write_int(Arg1, !IO),
+ ( Arg2 = yes(Arg2Out) ->
+ io.write_string(",", !IO),
+ io.write_int(Arg2Out, !IO)
+ ;
+ true
+ ),
+ ( Arg3 = yes(Arg3Out) ->
+ ( Arg2 = no ->
+ io.write_string(",,", !IO),
+ io.write_int(Arg3Out, !IO)
+ ;
+ io.write_string(",", !IO),
+ io.write_int(Arg3Out, !IO)
+ )
+ ;
+ true
+ ),
+ io.write_string("\n", !IO).
+
+ % Output pseudo-op having list of float as its argument.
+ %
+:- pred output_pseudo_op_float_args(string::in, list(float)::in,
+ io::di, io::uo) is det.
+
+output_pseudo_op_float_args(OpName, FloatArgs, !IO) :-
+ io.write_string("\t" ++ OpName ++ "\t", !IO),
+ pseudo_op_float_args_while(FloatArgs, !IO),
+ io.write_string("\n", !IO).
+
+:- pred pseudo_op_float_args_while(list(float)::in, io::di, io::uo) is det.
+
+pseudo_op_float_args_while([], !IO).
+pseudo_op_float_args_while([Arg | Args], !IO) :-
+ io.write_float(Arg, !IO),
+ ( Args = [] ->
+ pseudo_op_float_args_while(Args, !IO)
+ ;
+ io.write_string(",", !IO),
+ pseudo_op_float_args_while(Args, !IO)
+ ).
+
+ % Output pseudo-op having list of string as its argument.
+ %
+:- pred output_pseudo_op_str_args(string::in, list(string)::in,
+ io::di, io::uo) is det.
+
+output_pseudo_op_str_args(OpName, StrArgs, !IO) :-
+ io.write_string("\t" ++ OpName ++ "\t", !IO),
+ pseudo_op_str_args_while(StrArgs, !IO),
+ io.write_string("\n", !IO).
+
+:- pred pseudo_op_str_args_while(list(string)::in, io::di, io::uo) is det.
+
+pseudo_op_str_args_while([], !IO).
+pseudo_op_str_args_while([Arg | Args], !IO) :-
+ io.write_string(Arg, !IO),
+ ( Args = [] ->
+ pseudo_op_str_args_while(Args, !IO)
+ ;
+ io.write_string(",", !IO),
+ pseudo_op_str_args_while(Args, !IO)
+ ).
+
+ % Check if FLAGS and TYPE argument of '.section' pseudo-op is valid
+ %
+:- pred check_section_flags_and_type(string::in, maybe(string)::in,
+ bool::out) is det.
+
+check_section_flags_and_type(Flags, Type0, Result) :-
+ ( string.contains_char(Flags, 'M') ->
+ (
+ Type0 = yes(Type1),
+ string.length(Type1) > 0
+ ->
+ true
+ ;
+ unexpected(this_file, "check_section_flags_and_type:
+ flag unexpected")
+ )
+ ;
+ true
+ ),
+ string.to_char_list(Flags, CharList),
+ check_pseudo_section_flags(CharList, Result0),
+ ( Result0 = yes ->
+ Result = yes
+ ;
+ Result = no
+ ).
+
+ % Check FLAGS argument of '.section' pseudo-op
+ %
+:- pred check_pseudo_section_flags(list(char)::in, bool::out) is det.
+
+check_pseudo_section_flags([], yes).
+check_pseudo_section_flags([Char | Chars], Result) :-
+ ( string.contains_char(section_pseudo_op_flags, Char) ->
+ check_pseudo_section_flags(Chars, Result)
+ ;
+ Result = no
+ ).
+
+ % The optional FLAGS argument of '.section' pseudo-op contains any
+ % combination of:
+ % 'a' - section is allocatable
+ % 'w' - section is writable
+ % 'x' - section is executable
+ % 'M' - section is mergeable
+ % 'S' - section contains zero terminated string
+ %
+:- func section_pseudo_op_flags = string.
+
+section_pseudo_op_flags = "awxMS".
+
+ % The optional type of '.section' pseudo-op may contain:
+ % @progbits - section contains data
+ % @nobits - section does not contain data
+ %
+:- pred check_pseudo_section_type(string::in) is semidet.
+
+check_pseudo_section_type("@progbits").
+check_pseudo_section_type("@nobits").
+
+ % Two valid values of 'type_desc' field in pseudo-op '.type':
+ % @function
+ % @object
+ %
+:- pred check_pseudo_type_desc(string::in) is semidet.
+
+check_pseudo_type_desc("@function").
+check_pseudo_type_desc("@function").
+
+%-----------------------------------------------------------------------------%
+%
+% Output x86_64 instructions.
+%
+
+:- pred output_x86_64_instr_and_comment(list(x86_64_instruction)::in, io::di,
+ io::uo) is det.
+
+output_x86_64_instr_and_comment([], !IO).
+output_x86_64_instr_and_comment([Instr | Instrs], !IO) :-
+ Instr = x86_64_instr(InstrName, Comment),
+ output_x86_64_instr(InstrName, !IO),
+ output_comment(Comment, !IO),
+ output_x86_64_instr_and_comment(Instrs, !IO).
+
+ % Output x86_64 instruction and its operands (if any).
+ %
+:- pred output_x86_64_instr(x86_64_op::in, io::di, io::uo) is det.
+
+output_x86_64_instr(adc(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("adc", Src, Dest, !IO).
+output_x86_64_instr(add(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("add", Src, Dest, !IO).
+output_x86_64_instr(and(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("and", Src, Dest, !IO).
+output_x86_64_instr(bsf(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("bsf", Src, Dest, !IO).
+output_x86_64_instr(bsr(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("bsr", Src, Dest, !IO).
+output_x86_64_instr(bswap(Reg), !IO) :-
+ io.write_string("\tbswap\t", !IO),
+ reg_type(Reg, RegType),
+ io.write_string(RegType ++ "\t", !IO).
+output_x86_64_instr(bt(Src, Idx), !IO) :-
+ instr_with_rmro_and_rio("bt", Src, Idx, !IO).
+output_x86_64_instr(btc(Src, Idx), !IO) :-
+ instr_with_rmro_and_rio("btc", Src, Idx, !IO).
+output_x86_64_instr(btr(Src, Idx), !IO) :-
+ instr_with_rmro_and_rio("btr", Src, Idx, !IO).
+output_x86_64_instr(bts(Src, Idx), !IO) :-
+ instr_with_rmro_and_rio("bts", Src, Idx, !IO).
+output_x86_64_instr(call(TargetLocation), !IO) :-
+ instr_with_rmrol("call", TargetLocation, !IO).
+output_x86_64_instr(cbw, !IO) :-
+ io.write_string("\tcbw\t", !IO).
+output_x86_64_instr(cwde, !IO) :-
+ io.write_string("\tcwde\t", !IO).
+output_x86_64_instr(cdqe, !IO) :-
+ io.write_string("\tcdqe\t", !IO).
+output_x86_64_instr(cwd, !IO) :-
+ io.write_string("\tcwd\t", !IO).
+output_x86_64_instr(cdq, !IO) :-
+ io.write_string("\tcdq\t", !IO).
+output_x86_64_instr(cqo, !IO) :-
+ io.write_string("\tcqo\t", !IO).
+output_x86_64_instr(clc, !IO) :-
+ io.write_string("\tclc\t", !IO).
+output_x86_64_instr(cld, !IO) :-
+ io.write_string("\tcld\t", !IO).
+output_x86_64_instr(cmc, !IO) :-
+ io.write_string("\tcmc\t", !IO).
+output_x86_64_instr(cmovo(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovo", Src, Dest, !IO).
+output_x86_64_instr(cmovno(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovno", Src, Dest, !IO).
+output_x86_64_instr(cmovb(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovb", Src, Dest, !IO).
+output_x86_64_instr(cmovc(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovc", Src, Dest, !IO).
+output_x86_64_instr(cmovnae(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnae", Src, Dest, !IO).
+output_x86_64_instr(cmovnb(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnb", Src, Dest, !IO).
+output_x86_64_instr(cmovnc(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnc", Src, Dest, !IO).
+output_x86_64_instr(cmovae(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovae", Src, Dest, !IO).
+output_x86_64_instr(cmovz(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovz", Src, Dest, !IO).
+output_x86_64_instr(cmove(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmove", Src, Dest, !IO).
+output_x86_64_instr(cmovnz(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnz", Src, Dest, !IO).
+output_x86_64_instr(cmovne(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovne", Src, Dest, !IO).
+output_x86_64_instr(cmovbe(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovbe", Src, Dest, !IO).
+output_x86_64_instr(cmovna(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovna", Src, Dest, !IO).
+output_x86_64_instr(cmovnbe(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnbe", Src, Dest, !IO).
+output_x86_64_instr(cmova(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmova", Src, Dest, !IO).
+output_x86_64_instr(cmovs(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovs", Src, Dest, !IO).
+output_x86_64_instr(cmovns(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovns", Src, Dest, !IO).
+output_x86_64_instr(cmovp(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovp", Src, Dest, !IO).
+output_x86_64_instr(cmovpe(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovpe", Src, Dest, !IO).
+output_x86_64_instr(cmovnp(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnp", Src, Dest, !IO).
+output_x86_64_instr(cmovpo(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovpo", Src, Dest, !IO).
+output_x86_64_instr(cmovl(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovl", Src, Dest, !IO).
+output_x86_64_instr(cmovnge(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnge", Src, Dest, !IO).
+output_x86_64_instr(cmovnl(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnl", Src, Dest, !IO).
+output_x86_64_instr(cmovge(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovge", Src, Dest, !IO).
+output_x86_64_instr(cmovle(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovle", Src, Dest, !IO).
+output_x86_64_instr(cmovng(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovng", Src, Dest, !IO).
+output_x86_64_instr(cmovnle(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovnle", Src, Dest, !IO).
+output_x86_64_instr(cmovg(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("cmovg", Src, Dest, !IO).
+output_x86_64_instr(cmp(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("cmp", Src, Dest, !IO).
+output_x86_64_instr(cmpxchg(Cmp, Xchg), !IO) :-
+ instr_with_rmro_and_reg("cmpxchg", Cmp, Xchg, !IO).
+output_x86_64_instr(cmpxchg8b(MemRef), !IO) :-
+ mem_ref_type(MemRef, MemRefType),
+ io.write_string("\tcmpxchg8b" ++ MemRefType, !IO).
+output_x86_64_instr(dec(RegOrMemRef), !IO) :-
+ instr_with_rmro("dec", RegOrMemRef, !IO).
+output_x86_64_instr(div(RegOrMemRef), !IO) :-
+ instr_with_rmro("div", RegOrMemRef, !IO).
+output_x86_64_instr(enter(StackSize, NestingLevel), !IO) :-
+ StackSize = uint16(Size),
+ NestingLevel = uint8(Level),
+ check_unsigned_int_size(16, Size, Result0),
+ check_unsigned_int_size(8, Level, Result1),
+ (
+ Result0 = yes,
+ Result1 = yes
+ ->
+ io.write_string("\tenter\t", !IO),
+ io.write_int(Size, !IO),
+ io.write_string(",", !IO),
+ io.write_int(Level, !IO),
+ io.write_string("\t", !IO)
+ ;
+ unexpected(this_file, "output_x86_64_instr: enter unexpected")
+ ).
+output_x86_64_instr(idiv(RegOrMemRef), !IO) :-
+ instr_with_rmro("idiv", RegOrMemRef, !IO).
+output_x86_64_instr(imul(RegOrMemRef), !IO) :-
+ instr_with_rmro("idiv", RegOrMemRef, !IO).
+output_x86_64_instr(imul(Src, Dest), !IO) :-
+ instr_with_rmro_and_reg("imul", Src, Dest, !IO).
+output_x86_64_instr(imul(RegOrMemRefOp, Imm, Reg), !IO) :-
+ io.write_string("\timul\t", !IO),
+ rmro_type(RegOrMemRefOp, Type),
+ io.write_string(Type ++ ", ", !IO),
+ imm_op_type(Imm, ImmVal),
+ io.write_string(ImmVal ++ ", ", !IO),
+ reg_type(Reg, RegType),
+ io.write_string(RegType ++ "\t", !IO).
+output_x86_64_instr(inc(RegOrMemRef), !IO) :-
+ instr_with_rmro("inc", RegOrMemRef, !IO).
+output_x86_64_instr(jo(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jo", RelOffset, !IO).
+output_x86_64_instr(jno(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jno", RelOffset, !IO).
+output_x86_64_instr(jb(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jb", RelOffset, !IO).
+output_x86_64_instr(jc(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jc", RelOffset, !IO).
+output_x86_64_instr(jnae(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnae", RelOffset, !IO).
+output_x86_64_instr(jnb(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnb", RelOffset, !IO).
+output_x86_64_instr(jnc(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnc", RelOffset, !IO).
+output_x86_64_instr(jae(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jae", RelOffset, !IO).
+output_x86_64_instr(jz(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jz", RelOffset, !IO).
+output_x86_64_instr(je(RelOffset), !IO) :-
+ instr_with_rel_offset_op("je", RelOffset, !IO).
+output_x86_64_instr(jnz(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnz", RelOffset, !IO).
+output_x86_64_instr(jne(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jne", RelOffset, !IO).
+output_x86_64_instr(jbe(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jbe", RelOffset, !IO).
+output_x86_64_instr(jna(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jna", RelOffset, !IO).
+output_x86_64_instr(jnbe(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnbe", RelOffset, !IO).
+output_x86_64_instr(ja(RelOffset), !IO) :-
+ instr_with_rel_offset_op("ja", RelOffset, !IO).
+output_x86_64_instr(js(RelOffset), !IO) :-
+ instr_with_rel_offset_op("js", RelOffset, !IO).
+output_x86_64_instr(jns(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jns", RelOffset, !IO).
+output_x86_64_instr(jp(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jp", RelOffset, !IO).
+output_x86_64_instr(jpe(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jpe", RelOffset, !IO).
+output_x86_64_instr(jnp(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnp", RelOffset, !IO).
+output_x86_64_instr(jpo(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jpo", RelOffset, !IO).
+output_x86_64_instr(jl(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jl", RelOffset, !IO).
+output_x86_64_instr(jnge(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnge", RelOffset, !IO).
+output_x86_64_instr(jnl(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnl", RelOffset, !IO).
+output_x86_64_instr(jge(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jge", RelOffset, !IO).
+output_x86_64_instr(jle(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jle", RelOffset, !IO).
+output_x86_64_instr(jng(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jng", RelOffset, !IO).
+output_x86_64_instr(jnle(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jnle", RelOffset, !IO).
+output_x86_64_instr(jg(RelOffset), !IO) :-
+ instr_with_rel_offset_op("jg", RelOffset, !IO).
+output_x86_64_instr(jrcxz(RelOffset), !IO) :-
+ instr_with_8bit_rel_offset_op("jrcxz", RelOffset, !IO).
+output_x86_64_instr(jmp(Target), !IO) :-
+ instr_with_rmrol("jmp", Target, !IO).
+output_x86_64_instr(lea(Src, Dest), !IO) :-
+ instr_with_mem_ref_and_reg_op("lea", Src, Dest, !IO).
+output_x86_64_instr(leave, !IO) :-
+ io.write_string("\tleave\t", !IO).
+output_x86_64_instr(loop(RelOffset), !IO) :-
+ instr_with_8bit_rel_offset_op("loop", RelOffset, !IO).
+output_x86_64_instr(loope(RelOffset), !IO) :-
+ instr_with_8bit_rel_offset_op("loope", RelOffset, !IO).
+output_x86_64_instr(loopne(RelOffset), !IO) :-
+ instr_with_8bit_rel_offset_op("loopne", RelOffset, !IO).
+output_x86_64_instr(loopnz(RelOffset), !IO) :-
+ instr_with_8bit_rel_offset_op("loopnz", RelOffset, !IO).
+output_x86_64_instr(loopz(RelOffset), !IO) :-
+ instr_with_8bit_rel_offset_op("loopz", RelOffset, !IO).
+output_x86_64_instr(mov(Source, Dest), !IO) :-
+ instr_with_op_and_rmro("mov", Source, Dest, !IO).
+output_x86_64_instr(mul(RegOrMemRef), !IO) :-
+ instr_with_rmro("mul", RegOrMemRef, !IO).
+output_x86_64_instr(neg(RegOrMemRef), !IO) :-
+ instr_with_rmro("neg", RegOrMemRef, !IO).
+output_x86_64_instr(nop, !IO) :-
+ io.write_string("nop", !IO).
+output_x86_64_instr(not_(RegOrMemRef), !IO) :-
+ instr_with_rmro("not", RegOrMemRef, !IO).
+output_x86_64_instr(or(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("or", Src, Dest, !IO).
+output_x86_64_instr(pop(RegOrMemRefOp), !IO) :-
+ instr_with_rmro("pop", RegOrMemRefOp, !IO).
+output_x86_64_instr(popfq, !IO) :-
+ io.write_string("\tpopfq\t", !IO).
+output_x86_64_instr(push(Operand), !IO) :-
+ io.write_string("\tpush\t", !IO),
+ operand_type(Operand, OperandType),
+ io.write_string(OperandType ++ "\t", !IO).
+output_x86_64_instr(pushfq, !IO) :-
+ io.write_string("\tpushfq\t", !IO).
+output_x86_64_instr(rcl(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("rcl", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(rcr(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("rcr", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(ret, !IO) :-
+ io.write_string("\tret\t", !IO).
+output_x86_64_instr(ret(uint16(NumBytes)), !IO) :-
+ check_unsigned_int_size(16, NumBytes, Result),
+ ( Result = yes ->
+ io.write_string("\tret\t", !IO),
+ io.write_int(NumBytes, !IO),
+ io.write_string("\t", !IO)
+ ;
+ unexpected(this_file, "output_x86_64_instr: ret unexpected")
+ ).
+output_x86_64_instr(rol(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("rol", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(ror(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("ror", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(sal(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("sal", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(shl(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("shl", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(sar(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("sar", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(sbb(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("sbb", Src, Dest, !IO).
+output_x86_64_instr(seto(RegOrMemRef), !IO) :-
+ instr_with_rmro("seto", RegOrMemRef, !IO).
+output_x86_64_instr(setno(RegOrMemRef), !IO) :-
+ instr_with_rmro("setno", RegOrMemRef, !IO).
+output_x86_64_instr(setb(RegOrMemRef), !IO) :-
+ instr_with_rmro("setb", RegOrMemRef, !IO).
+output_x86_64_instr(setc(RegOrMemRef), !IO) :-
+ instr_with_rmro("setc", RegOrMemRef, !IO).
+output_x86_64_instr(setnae(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnae", RegOrMemRef, !IO).
+output_x86_64_instr(setnb(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnb", RegOrMemRef, !IO).
+output_x86_64_instr(setnc(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnc", RegOrMemRef, !IO).
+output_x86_64_instr(setae(RegOrMemRef), !IO) :-
+ instr_with_rmro("setae", RegOrMemRef, !IO).
+output_x86_64_instr(setz(RegOrMemRef), !IO) :-
+ instr_with_rmro("setz", RegOrMemRef, !IO).
+output_x86_64_instr(sete(RegOrMemRef), !IO) :-
+ instr_with_rmro("sete", RegOrMemRef, !IO).
+output_x86_64_instr(setnz(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnz", RegOrMemRef, !IO).
+output_x86_64_instr(setne(RegOrMemRef), !IO) :-
+ instr_with_rmro("setne", RegOrMemRef, !IO).
+output_x86_64_instr(setbe(RegOrMemRef), !IO) :-
+ instr_with_rmro("setbe", RegOrMemRef, !IO).
+output_x86_64_instr(setna(RegOrMemRef), !IO) :-
+ instr_with_rmro("setna", RegOrMemRef, !IO).
+output_x86_64_instr(setnbe(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnbe", RegOrMemRef, !IO).
+output_x86_64_instr(seta(RegOrMemRef), !IO) :-
+ instr_with_rmro("seta", RegOrMemRef, !IO).
+output_x86_64_instr(sets(RegOrMemRef), !IO) :-
+ instr_with_rmro("sets", RegOrMemRef, !IO).
+output_x86_64_instr(setns(RegOrMemRef), !IO) :-
+ instr_with_rmro("setns", RegOrMemRef, !IO).
+output_x86_64_instr(setp(RegOrMemRef), !IO) :-
+ instr_with_rmro("setp", RegOrMemRef, !IO).
+output_x86_64_instr(setpe(RegOrMemRef), !IO) :-
+ instr_with_rmro("setpe", RegOrMemRef, !IO).
+output_x86_64_instr(setnp(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnp", RegOrMemRef, !IO).
+output_x86_64_instr(setpo(RegOrMemRef), !IO) :-
+ instr_with_rmro("setpo", RegOrMemRef, !IO).
+output_x86_64_instr(setl(RegOrMemRef), !IO) :-
+ instr_with_rmro("sel", RegOrMemRef, !IO).
+output_x86_64_instr(setnge(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnge", RegOrMemRef, !IO).
+output_x86_64_instr(setnl(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnl", RegOrMemRef, !IO).
+output_x86_64_instr(setge(RegOrMemRef), !IO) :-
+ instr_with_rmro("setge", RegOrMemRef, !IO).
+output_x86_64_instr(setle(RegOrMemRef), !IO) :-
+ instr_with_rmro("setle", RegOrMemRef, !IO).
+output_x86_64_instr(setng(RegOrMemRef), !IO) :-
+ instr_with_rmro("setng", RegOrMemRef, !IO).
+output_x86_64_instr(setnle(RegOrMemRef), !IO) :-
+ instr_with_rmro("setnle", RegOrMemRef, !IO).
+output_x86_64_instr(setg(RegOrMemRef), !IO) :-
+ instr_with_rmro("setg", RegOrMemRef, !IO).
+output_x86_64_instr(shld(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
+ instr_with_crio_rmro_and_reg("shld", ClRegOrImm, RegOrMemRef, Reg, !IO).
+output_x86_64_instr(shr(ClRegOrImm, RegOrMemRef), !IO) :-
+ instr_with_crio_and_rmro("shr", ClRegOrImm, RegOrMemRef, !IO).
+output_x86_64_instr(shrd(ClRegOrImm, RegOrMemRef, Reg), !IO) :-
+ instr_with_crio_rmro_and_reg("shrd", ClRegOrImm, RegOrMemRef, Reg, !IO).
+output_x86_64_instr(stc, !IO) :-
+ io.write_string("\tstc\t", !IO).
+output_x86_64_instr(std, !IO) :-
+ io.write_string("\tstd\t", !IO).
+output_x86_64_instr(sub(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("sub", Src, Dest, !IO).
+output_x86_64_instr(test(Src1, Src2), !IO) :-
+ instr_with_rmro_and_rio("test", Src1, Src2, !IO).
+output_x86_64_instr(xadd(Src, Dest), !IO) :-
+ instr_with_reg_and_rmro("xadd", Src, Dest, !IO).
+output_x86_64_instr(xchg(Src1, Src2), !IO) :-
+ instr_with_rmro_and_rmro("xchg", Src1, Src2, !IO).
+output_x86_64_instr(xor(Src, Dest), !IO) :-
+ instr_with_op_and_rmro("xor", Src, Dest, !IO).
+
+
+:- pred output_comment(string::in, io::di, io::uo) is det.
+
+output_comment(Comment, !IO) :-
+ ( string.length(Comment) > 0 ->
+ io.write_string("\t# ", !IO),
+ io.write_string(Comment, !IO)
+ ;
+ true
+ ),
+ io.write_string("\n", !IO).
+
+%-----------------------------------------------------------------------------%
+%
+% Output of x86_64 operands.
+%
+
+ % Output a string representation of an immediate value.
+ %
+:- pred imm_op_type(imm_operand::in, string::out) is det.
+
+imm_op_type(imm8(int8(Val)), ImmVal) :-
+ ImmVal = "$" ++ string.int_to_string(Val).
+imm_op_type(imm16(int16(Val)), ImmVal) :-
+ ImmVal = "$" ++ string.int_to_string(Val).
+imm_op_type(imm32(int32(Val)), ImmVal) :-
+ ImmVal = "$" ++ string.int_to_string(Val).
+
+ % Output a string representation of a general-purpose register.
+ %
+:- pred reg_type(gp_reg::in, string::out) is det.
+
+reg_type(rax, "%rax").
+reg_type(rbx, "%rbx").
+reg_type(rcx, "%rcx").
+reg_type(rdx, "%rdx").
+reg_type(rbp, "%rbp").
+reg_type(rsi, "%rsi").
+reg_type(rdi, "%rdi").
+reg_type(rsp, "%rsp").
+reg_type(r8, "%r8").
+reg_type(r9, "%r9").
+reg_type(r10, "%r10").
+reg_type(r11, "%r11").
+reg_type(r12, "%r12").
+reg_type(r13, "%r13").
+reg_type(r14, "%r14").
+reg_type(r15, "%r15").
+
+ % Output a string representation of a memory reference.
+ %
+:- pred mem_ref_type(mem_ref::in, string::out) is det.
+
+mem_ref_type(mem_abs(DirectMemRef), MemRefVal) :-
+ base_address_type(DirectMemRef, MemRefVal).
+mem_ref_type(mem_rip(InstrPtr), MemRefVal) :-
+ instr_ptr_type(InstrPtr, MemRefVal).
+
+ % Output a string representation of a base address in a memory reference.
+ %
+:- pred base_address_type(base_address::in, string::out) is det.
+
+base_address_type(base_reg(Offset, Reg), BaseAddress) :-
+ reg_type(Reg, RegType),
+ ( Offset = 0 ->
+ BaseAddress = "(" ++ RegType ++ ")"
+ ;
+ BaseAddress = string.int_to_string(Offset) ++ "(" ++ RegType ++ ")"
+ ).
+base_address_type(base_expr(Expr), DispType) :-
+ DispType = "$" ++ Expr.
+
+ % Output a string representation of RIP relative addressing.
+ %
+:- pred instr_ptr_type(instr_ptr::in, string::out) is det.
+
+instr_ptr_type(rip_constant(int32(Constant)), InstrPtrType) :-
+ check_signed_int_size(32, Constant, Result),
+ (
+ Result = yes,
+ InstrPtrType = string.int_to_string(Constant) ++ "(%rip)"
+ ;
+ Result = no,
+ unexpected(this_file, "instr_ptr_type: int32 unexpected")
+ ).
+instr_ptr_type(rip_expr(Symbol), InstrPtrType) :-
+ InstrPtrType = Symbol ++ "(%rip)".
+
+ % Output a string representation of a relative offset.
+ %
+:- pred rel_offset_type(rel_offset::in, string::out) is det.
+
+rel_offset_type(ro8(int8(Val)), RelOffsetVal) :-
+ check_signed_int_size(8, Val, Result),
+ ( Result = yes ->
+ ( Val = 0 ->
+ RelOffsetVal = ""
+ ;
+ RelOffsetVal = string.int_to_string(Val)
+ )
+ ;
+ unexpected(this_file, "rel_offset_type: ro8 unexpected")
+ ).
+rel_offset_type(ro16(int16(Val)), RelOffsetVal) :-
+ check_signed_int_size(16, Val, Result),
+ ( Result = yes ->
+ ( Val = 0 ->
+ RelOffsetVal = ""
+ ;
+ RelOffsetVal = string.int_to_string(Val)
+ )
+ ;
+ unexpected(this_file, "rel_offset_type: ro16 unexpected")
+ ).
+rel_offset_type(ro32(int32(Val)), RelOffsetVal) :-
+ check_signed_int_size(32, Val, Result),
+ ( Result = yes ->
+ ( Val = 0 ->
+ RelOffsetVal = ""
+ ;
+ RelOffsetVal = string.int_to_string(Val)
+ )
+ ;
+ unexpected(this_file, "rel_offset_type: ro32 unexpected")
+ ).
+
+ % Output a string representation of a general operand type.
+ %
+:- pred operand_type(operand::in, string::out) is det.
+
+operand_type(operand_reg(Reg), RegType) :-
+ reg_type(Reg, RegType).
+operand_type(operand_imm(Imm), ImmVal) :-
+ imm_op_type(Imm, ImmVal).
+operand_type(operand_mem_ref(MemRef), MemRefVal) :-
+ mem_ref_type(MemRef, MemRefVal).
+
+ % Output a string representation of an operand whose type is a register/
+ % memory reference.
+ %
+:- pred rmro_type(reg_or_mem_ref_op::in, string::out) is det.
+
+rmro_type(rmro_reg(Reg), RegType) :-
+ reg_type(Reg, RegType).
+rmro_type(rmro_mem_ref(MemRef), MemRefVal) :-
+ mem_ref_type(MemRef, MemRefVal).
+
+ % Output a string representation of an operand whose type is a register
+ % or an immediate value.
+ %
+:- pred rio_type(reg_or_imm_op::in, string::out) is det.
+
+rio_type(rio_reg(Reg), RegType) :-
+ reg_type(Reg, RegType).
+rio_type(rio_imm(Imm), ImmVal) :-
+ imm_op_type(Imm, ImmVal).
+
+ % Output a string representation of an operand whose type is a cl register
+ % or an unsigned immediate value.
+ %
+:- pred crio_type(cl_reg_or_imm_op::in, string::out) is det.
+
+crio_type(crio_reg_cl(Reg), RegType) :-
+ ( Reg = rcx ->
+ RegType = "%cl"
+ ;
+ unexpected(this_file, "crio_type: crio_reg_cl unexpected")
+ ).
+crio_type(crio_imm8(int8(Val)), ImmVal) :-
+ check_unsigned_int_size(8, Val, Result),
+ ( Result = yes ->
+ ImmVal = "$" ++ string.int_to_string(Val)
+ ;
+ unexpected(this_file, "crio_type: crio_imm8 unexpected")
+ ).
+
+ % Output a string representation of an operand whose type is either
+ % a register, memory reference, signed relative offset or a label.
+ %
+:- pred rmrol_type(rmrol::in, string::out) is det.
+
+rmrol_type(rmrol_reg(Reg), RegType) :-
+ reg_type(Reg, RegType).
+rmrol_type(rmrol_mem_ref(MemRef), MemRefVal) :-
+ mem_ref_type(MemRef, MemRefVal).
+rmrol_type(rmrol_rel_offset(RelOffset), RelOffsetVal) :-
+ rel_offset_type(RelOffset, RelOffsetVal).
+rmrol_type(rmrol_label(LabelName), LabelOut) :-
+ LabelOut = LabelName.
+
+%-----------------------------------------------------------------------------%
+%
+% Subsection of "Output of x86_64 instructions".
+%
+
+ % Output an instruction with a register/memory reference as an operand.
+ %
+:- pred instr_with_rmro(string::in, reg_or_mem_ref_op::in,
+ io::di, io::uo) is det.
+
+instr_with_rmro(InstrName, RegOrMemRef, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ rmro_type(RegOrMemRef, RegOrMemRefType),
+ io.write_string(RegOrMemRefType ++ "\t\t", !IO).
+
+ % Output an instruction with a signed offset relative to the instruction
+ % pointer as an operand.
+ %
+:- pred instr_with_rel_offset_op(string::in, rel_offset::in,
+ io::di, io::uo) is det.
+
+instr_with_rel_offset_op(InstrName, RelOffset, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ rel_offset_type(RelOffset, RelOffsetType),
+ io.write_string(RelOffsetType ++ "\t\t", !IO).
+
+ % Output an instruction with a signed 8-bit offset relative to the
+ % instruction pointer as an operand.
+ %
+:- pred instr_with_8bit_rel_offset_op(string::in, rel_offset::in,
+ io::di, io::uo) is det.
+
+instr_with_8bit_rel_offset_op(InstrName, RelOffset, !IO) :-
+ (
+ RelOffset = ro8(int8(Val)),
+ check_signed_int_size(8, Val, Result),
+ Result = yes
+ ->
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ io.write_int(Val, !IO),
+ io.write_string("\t\t", !IO)
+ ;
+ unexpected(this_file, "instr_with_8bit_rel_offset_op: unexpected")
+ ).
+
+ % Output an instruction with either a register, memory reference,
+ % relative offset or a label as its operand.
+ %
+:- pred instr_with_rmrol(string::in, rmrol::in, io::di, io::uo) is det.
+
+instr_with_rmrol(InstrName, Target, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ rmrol_type(Target, TargetType),
+ io.write_string(TargetType ++ "\t\t", !IO).
+
+ % Output an instruction with a general operand and a register/memory
+ % reference as the first and second operand respectively.
+ %
+:- pred instr_with_op_and_rmro(string::in, operand::in, reg_or_mem_ref_op::in,
+ io::di, io::uo) is det.
+
+instr_with_op_and_rmro(InstrName, SrcOperand, DestRegOrMemRefOp, !IO) :-
+ (
+ SrcOperand = operand_mem_ref(_),
+ DestRegOrMemRefOp = rmro_mem_ref(_)
+ ->
+ % Both operands cannot be of type memory reference.
+ unexpected(this_file, "instr_with_op_and_rmro: unexpected")
+ ;
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ operand_type(SrcOperand, OperandType),
+ io.write_string(OperandType ++ ", ", !IO),
+ rmro_type(DestRegOrMemRefOp, DestType),
+ io.write_string(DestType ++ "\t", !IO)
+ ).
+
+ % Output an instruction with a register/memory reference and a register as
+ % the first and second operand respectively.
+ %
+:- pred instr_with_rmro_and_reg(string::in, reg_or_mem_ref_op::in, gp_reg::in,
+ io::di, io::uo) is det.
+
+instr_with_rmro_and_reg(InstrName, SrcRegOrMemRefOp, DestReg, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ rmro_type(SrcRegOrMemRefOp, SrcType),
+ io.write_string(SrcType ++ ", ", !IO),
+ reg_type(DestReg, RegType),
+ io.write_string(RegType ++ "\t", !IO).
+
+ % Output an instruction with a register/memory reference and a register/
+ % immediate value as the first and second operand respectively.
+ %
+:- pred instr_with_rmro_and_rio(string::in, reg_or_mem_ref_op::in,
+ reg_or_imm_op::in, io::di, io::uo) is det.
+
+instr_with_rmro_and_rio(InstrName, SrcRegOrMemRefOp, DestRegOrImmOp, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ rmro_type(SrcRegOrMemRefOp, SrcType),
+ io.write_string(SrcType ++ ",", !IO),
+ rio_type(DestRegOrImmOp, DestType),
+ io.write_string(DestType ++ "\t", !IO).
+
+ % Output an instruction with a register/memory reference as the first and
+ % second operand respectively.
+ %
+:- pred instr_with_rmro_and_rmro(string::in, reg_or_mem_ref_op::in,
+ reg_or_mem_ref_op::in, io::di, io::uo) is det.
+
+instr_with_rmro_and_rmro(InstrName, RegOrMemRefOp0, RegOrMemRefOp1, !IO) :-
+ (
+ RegOrMemRefOp0 = rmro_mem_ref(_),
+ RegOrMemRefOp1 = rmro_mem_ref(_)
+ ->
+ unexpected(this_file, "instr_with_rmro_and_rmro: unexpected")
+ ;
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ rmro_type(RegOrMemRefOp0, Type0),
+ io.write_string(Type0 ++ ", ", !IO),
+ rmro_type(RegOrMemRefOp1, Type1),
+ io.write_string(Type1 ++ "\t", !IO)
+ ).
+
+ % Output an instruction with a register and a register/memory reference as
+ % the first and second operand respectively.
+ %
+:- pred instr_with_reg_and_rmro(string::in, gp_reg::in, reg_or_mem_ref_op::in,
+ io::di, io::uo) is det.
+
+instr_with_reg_and_rmro(InstrName, SrcReg, DestRegOrMemRefOp, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ reg_type(SrcReg, RegType),
+ io.write_string(RegType ++ ", ", !IO),
+ rmro_type(DestRegOrMemRefOp, DestType),
+ io.write_string(DestType ++ "\t", !IO).
+
+ % Output an instruction with a cl register/immediate value and a register/
+ % memory reference as the first and second operand respectively.
+ %
+:- pred instr_with_crio_and_rmro(string::in, cl_reg_or_imm_op::in,
+ reg_or_mem_ref_op::in, io::di, io::uo) is det.
+
+instr_with_crio_and_rmro(InstrName, ClRegOrImm, RegOrMemRef, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ crio_type(ClRegOrImm, ClRegOrImmType),
+ io.write_string(ClRegOrImmType ++ ", ", !IO),
+ rmro_type(RegOrMemRef, RegOrMemRefType),
+ io.write_string(RegOrMemRefType ++ "\t", !IO).
+
+ % Output an instruction with a cl register/immediate value, a register/
+ % memory reference and a register as the first, second and third operand
+ % respectively.
+ %
+:- pred instr_with_crio_rmro_and_reg(string::in, cl_reg_or_imm_op::in,
+ reg_or_mem_ref_op::in, gp_reg::in, io::di, io::uo) is det.
+
+instr_with_crio_rmro_and_reg(InstrName, ClRegOrImm, RegOrMemRef, Reg, !IO) :-
+ io.write_string("\t" ++ InstrName ++ "\t", !IO),
+ crio_type(ClRegOrImm, ClRegOrImmType),
+ io.write_string(ClRegOrImmType ++ "\t", !IO),
+ rmro_type(RegOrMemRef, RegOrMemRefType),
+ io.write_string(RegOrMemRefType ++ ", ", !IO),
+ reg_type(Reg, RegType),
+ io.write_string(RegType ++ "\t", !IO).
+
+ % Output an instruction with a memory reference and a register as the first
+ % and second operand respectively.
+ %
+:- pred instr_with_mem_ref_and_reg_op(string::in, mem_ref::in,
+ gp_reg::in, io::di, io::uo) is det.
+
+instr_with_mem_ref_and_reg_op(InstrName, SrcMemRef, DestReg, !IO) :-
+ mem_ref_type(SrcMemRef, MemRefType),
+ io.write_string("\t" ++ InstrName ++ "\t" ++ MemRefType, !IO),
+ reg_type(DestReg, DestRegType),
+ io.write_string(", " ++ DestRegType ++ "\t", !IO).
+
+%-----------------------------------------------------------------------------%
+
+ % Check whether an unsigned int (Val) with n bits (BitSize) is within the
+ % range of 0 and (2^n)-1.
+ %
+:- pred check_unsigned_int_size(int::in, int::in, bool::out) is det.
+
+check_unsigned_int_size(BitSize, Val, Result) :-
+ MaxInt = (1 << BitSize) - 1,
+ (
+ Val >= 0,
+ Val =< MaxInt
+ ->
+ Result = yes
+ ;
+ Result = no
+ ).
+
+ % Check whether a signed int (Val) with n bits (BitSize) is within the
+ % range of -2^(n-1) and 2^(n-1)-1.
+ %
+:- pred check_signed_int_size(int::in, int::in, bool::out) is det.
+
+check_signed_int_size(BitSize, Val, Result) :-
+ MinInt = - (1 << (BitSize - 1)),
+ MaxInt = (1 << (BitSize - 1)) - 1,
+ (
+ Val >= MinInt,
+ Val =< MaxInt
+ ->
+ Result = yes
+ ;
+ Result = no
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "x86_64_out.m".
+
+:- end_module x86_64_out.
+%-----------------------------------------------------------------------------%
|
||
|
|
9d23d8e2e7 |
Implement the trace goal construct we discussed, for now for the LLDS backends
Estimated hours taken: 70
Branches: main
Implement the trace goal construct we discussed, for now for the LLDS backends
only.
Since the syntax of trace goals is non-trivial, useful feedback on syntax
errors inside trace goal attributes is essential. With the previous setup, this
wasn't possible, since the code that turned terms into parse tree goals turned
*all* terms into goals; it couldn't recognize any errors, sweeping them under
the rug as calls. This diff changes that. Now, if this code recognizes a
keyword that indicates a particular construct, it insists on the rest of the
code following the syntax required for that construct, and returns error
messages if it doesn't.
We handle the trace goal attributes that specify state variables to be threaded
through the trace goal (either the I/O state or a mutable variable) in
add_clause.m, at the point at which we transform the list of items to the HLDS.
We handle the compile-time condition on trace goals in the invocation of
simplify at the end of semantics analysis, by eliminating the goal if the
compile-time condition isn't met. We handle run-time conditions on trace goals
partially in the same invocation of simplify: we transform trace goals with
runtime conditions into an if-then-else with the trace goal as the then part
and `true' as the else part, the condition being a foreign_proc that is handled
specially by the code generator, that special handling being to replace
the actual code of the foreign_proc (which is a dummy) with the evaluation of
the runtime condition.
Since these changes require significant changes to some of our key data
structures, I took the liberty of doing some renaming of function symbols
at the same time to avoid using ambiguities with respect to language keywords.
library/ops.m:
Add "trace" as an operator.
compiler/prog_data.m:
Define data types to represent the various attributes of trace goals.
Rename some function symbols to avoid ambiguities.
compiler/prog_item.m:
Extend the parse tree representation of goals with a trace goal.
compiler/mercury_to_mercury.m:
Output the new kind of goal and its components.
compiler/hlds_goal.m:
Extend the HLDS representation of scopes with a scope_reason
representing trace goals.
Add a mechanism (an extra argument in foreign_procs) to allow
the representation of goals that evaluate runtime trace conditions.
Since this requires modifying all code that traverses the HLDS,
do some renames that were long overdue: rename not as negation,
rename call as plain_call, and rename foreign_proc as
call_foreign_proc. These renames all avoid using language keywords
as function symbols.
Change the way we record goals' purities. Instead of optional features
to indicate impure or semipure, which is error-prone, use a plain
field in the goal_info, accessed in the usual way.
Add a way to represent that a goal contains a trace goal, and should
therefore be treated as if it were impure when considering whether to
optimize it away.
Reformat some comments describing function symbols.
compiler/hlds_out.m:
Output the new construct in the HLDS.
compiler/prog_io_util.m:
Generalize the maybe[123] types to allow the representation of more
than one error message. Add functions to extract the error messages.
Add a maybe4 type. Rename the function symbols of these types to
avoid massive ambiguity.
Change the order of some predicates to bring related predicates
next to each other.
compiler/prog_io.m:
compiler/prog_io_dcg.m:
compiler/prog_io_goal.m:
compiler/prog_io_pragma.m:
Rework these modules almost completely to find and accumulate syntax
errors as terms are being parsed. In some cases, this allowed us to
replace "XXX this is a hack" markers with meaningful error-reporting
code.
In prog_io_goal.m, add code for parsing trace goals.
In a bunch of places, update obsolete coding practices, such as using
nested chains of closures instead of simple sequential code, and
using A0 and A to refer to values of different types (terms and goals
respectively). Use more meaningful variable names.
Break up some too-large predicates.
compiler/superhomogeneous.m:
Find and accumulate syntax errors as terms are being parsed.
compiler/add_clause.m:
Add code to transform trace goals from the parse tree to the HLDS.
This is where the IO state and mutable variable attributes of trace
goals are handled.
Eliminate the practice of using the naming scheme Body0 and Body
to refer to values of different types (prog_item.goal and hlds_goal
respectively).
Use error_util for some error messages.
library/private_builtin.m:
Add the predicates referred to by the transformation in add_clause.m.
compiler/goal_util.m:
Rename a predicate to avoid ambiguity.
compiler/typecheck.m:
Do not print error messages about missing clauses if some errors have
been detected previously.
compiler/purity.m:
Instead of just computing purity, compute (and record) also whether
a goal contains a trace goal. However, treat trace goals as pure.
compiler/mode_info.m:
Add trace goals as a reason for locking variables.
Rename some function symbols to avoid ambiguity.
compiler/modes.m:
When analyzing trace goal scopes, lock the scope's nonlocal variables
to prevent them from being further instantiated.
compiler/det_analysis.m:
Insist on the code in trace goal scopes being det or cc_multi.
compiler/det_report.m:
Generate the error message if the code in a trace goal scope isn't det
or cc_multi.
compiler/simplify.m:
At the end of the front end, eliminate trace goal scopes if their
compile-time condition is false. Transform trace goals with runtime
conditions as described at the top.
Treat goals that contain trace goals as if they were impure when
considering whether to optimize them away.
compiler/mercury_compile.m:
Tell simplify when it is being invoked at the end of the front end.
Rename a predicate to avoid ambiguity.
compiler/trace_params.m:
Provide the predicates simplify.m need to be able to evaluate the trace
goal conditions regarding trace levels.
compiler/trace.m:
compiler/trace_gen.m:
Rename the trace module as trace_gen, since "trace" is now an operator.
Rename some predicates exported by the module, now that it is no longer
possible to preface calls with "trace." as a module qualifier.
compiler/notes/compiler_design.html:
Document this name change.
compiler/options.m:
Rename the trace option as trace_level internally, since "trace"
is now an operator. The user-visible name remains the same.
Add the new --trace-flag option.
Delete an obsolete option.
compiler/handle_options.m:
Rename the function symbols of the grade_component type,
since "trace" is now an operator.
compiler/llds.m:
Extend the LLDS with a mechanism to refer to C global variables.
For now, these are used to refer to C globals that will be created
by mkinit to represent the initial values of the environment variables
referred to by trace goals.
compiler/commit_gen.m:
Check that no trace goal with a runtime condition survives to code
generation; they should have been transformed by simplify.m.
compiler/code_gen.m:
Tell commit_gen.m what kind of scope it is generating code for.
compiler/pragma_c_gen.m:
Generate code for runtime conditions when handling the foreign_procs
created by simplify.m.
compiler/code_info.m:
Allow pragma_c_gen.m to record what environment variables it has
generated references to.
compiler/proc_gen.m:
Record the set of environment variables a procedure refers to
in the LLDS procedure header, for efficient access by llds_out.m.
compiler/llds_out.m:
Handle the new LLDS construct, and tell mkinit which environment
variables need C globals created for them.
compiler/pd_util.m:
Rename some predicates to avoid ambiguity.
compiler/*.m:
Conform to the changes above, mainly the renames of function symbols
and predicates, the changed signatures of some predicates, and the new
handling of purity.
util/mkinit.c:
Generate the definitions and the initializations of any C globals
representing the initial status (set or not set) of environment
variables needed by trace goals.
library/assoc_list.m:
Add some predicates that are useful in prog_io*.m.
library/term_io.m:
Minor cleanup.
tests/hard_coded/trace_goal_{1,2}.{m,exp}:
New test cases to test the new construct, identical except for whether
the trace goal is enabled at compile time.
tests/hard_coded/trace_goal_env_{1,2}.{m,exp}:
New test cases to test the new construct, identical except for whether
the trace goal is enabled at run time.
tests/hard_coded/Mercury.options:
tests/hard_coded/Mmakefile:
Enable the new test cases.
tests/invalid/*.err_exp:
Update the expected output for the new versions of the error messages
now being generated.
|
||
|
|
4e6c603d30 |
Fix two bugs that caused test case failures in deep profiling grades.
Estimated hours taken: 3 Branches: main compiler/lookup_switch.m: Fix two bugs that caused test case failures in deep profiling grades. One bug was that an acquired register wasn't being released before the creation of a resume point, which rebuilds the code generator state (and thus forgets about acquired registers). The other bug was that is_lookup_switch wasn't performing the actions generate_goal would have when processing goals. In particular, it wasn't invoking pre_goal_update and post_goal_update on disjunctions inside the switch. compiler/lookup_util.m: Do not standardize goals by removing scopes from around other goals, because this could also remove the effects of the code generator annotations (e.g. liveness changes such as pre-births) on the scope goal. compiler/simplify.m: Eliminate those redundant scopes if asked to do so. Since this is done before the code generator annotations are put on goals, this is safe. compiler/code_gen.m: compiler/proc_gen.m: Divide the old code_gen.m into two modules: the new code_gen.m concerned with generating code for goals, and the new module proc_gen.m concerned with generating code for procedures. Without this, the code for handling goals is lost inside the old code_gen.m module. compiler/ll_backend.m: Include the new module. compiler/mercury_compile.m: Import proc_gen instead of code_gen, and ask simplify to eliminate unnecessary scopes before code generation. compiler/middle_rec.m: Update a reference to a predicate now in proc_gen.m. compiler/notes/compiler_design.html: Document the new module. |
||
|
|
d5d5986472 |
Implement lookup switches in which a switch arm may contain more than one
Estimated hours taken: 40
Branches: main
Implement lookup switches in which a switch arm may contain more than one
solution, such as this code here:
p(d, "four", f1, 4.4).
p(e, "five", f2, 5.5).
p(e, "five2", f3(5), 55.5).
p(f, "six", f4("hex"), 6.6).
p(g, "seven", f5(77.7), 7.7).
p(g, "seven2", f1, 777.7).
p(g, "seven3", f2, 7777.7).
Such code occurs frequently in benchmark programs used to evaluate the
performance of tabled logic programming systems.
Change frameopt.m, which previously worked only on det and semidet code,
to also work for nondet code. For predicates such as the one above, frameopt
can now arrange for the predicate's nondet stack frame to be created only
when a switch arm that has more than one solution is selected.
compiler/lookup_switch.m:
Extend the existing code for recognizing and implementing lookup
switches to recognize and implement them even if they are model_non.
compiler/lookup_util.m:
New module containing utility predicates useful for implementing
both lookup switches, and in the future, lookup disjunctions (i.e.
disjunctions that correspond to a nondet arm of a lookup switch).
compiler/ll_backend.m:
Include the new module.
compiler/notes/compiler_design.html:
Mention the new module.
compiler/global_data.m:
Move the job of filling in dummy slots to our caller, in this case
lookup_switch.m.
compiler/frameopt.m:
Generalize the existing code for delaying stack frame creation,
which worked only on predicates that live on the det stack, to work
also on predicates that live on the nondet stack. Without this,
predicates whose bodies are model_non lookup switches would create
a nonstack stack frame before the switch is ever entered, which
is wasteful if the selected switch arm has at most one solution.
Since the structure of model_non predicates is more complex (you can
cause a branch to a label by storing its address in a redoip slot,
you can succeed from the frame without removing the frame), this
required considerable extra work. To make the new code debuggable,
record, for each basic block that needs a stack frame, *why* it
needs that stack frame.
compiler/opt_util.m:
Be more conservative about what refers to the stack. Export some
previously internal functionality for frameopt. Turn some predicates
into functions, and rename them to better reflect their purpose.
compiler/opt_debug.m:
Print much more information about pragma_c and call LLDS instructions.
compiler/prog_data.m:
Add an extra attribute to foreign_procs that says that the code
of the foreign_proc assumes the existence of a stack frame.
This is needed to avoid frameopt optimizing the stack frame away.
compiler/add_pragma.m:
When processing fact tables, we create foreign_procs that assume
the existence of the stack frame, so set the new attribute.
compiler/pragma_c_gen.m:
When processing foreign_procs, transmit the information in the
attribute to the generated LLDS code.
compiler/llds.m:
Rename the function symbols referring to the fixed slots in nondet
stack frames to make them clearer and to avoid overloading function
symbols such as curfr and succip.
Rename the function symbols of the call_model type to avoid overloading
the function symbols of the code_model type.
Add a new field to the c_procedure type giving the code_model of the
procedure, and give names to all the fields.
Describe the stack slots used by lookup switches to the debugger
and native gc.
compiler/options.m:
doc/user_guide.texi:
Add a new option, --debug-opt-pred-name, that does when the existing
--debug-opt-pred-id options does, but taking a user-friendly predicate
name rather than a pred_id as its argument.
compiler/handle_options.m:
Process --debug-opt-pred-name, and make --frameopt-comments imply
--auto-comments, since it is not useful without it.
Reformat some existing comments that were written in the days of
8-space indentation.
compiler/optimize.m:
Implement the new option.
Use the new field of the c_procedure type to try only the version
of frameopt appropriate for the code model of the current procedure.
Do a peephole pass after frameopt, since frameopt can generate code
sequences that peephole can optimize.
Make the mechanism for recording the process of optimizing procedure
bodies more easily usable by including the name of the optimization
that created a given version of the code in the name of the file
that contains that version of the code, and ensuring that all numbers
are two characters long, so that "vi procname*.opt*" looks at the
relevant files in the proper chronological sequence, instead of having
version 11 appear before version 2.
compiler/peephole.m:
Add a new optimization pattern: a "mkframe, goto fail" pair (which
can be generated by frameopt) should be replaced by a simple "goto
redo".
compiler/code_gen.m:
Factor out some common code.
compiler/llds_out.m:
Ensure that C comments nested inside comment(_) LLDS instructions
aren't emitted as nested C comments, since C compilers cannot handle
these.
compiler/code_info.m:
compiler/code_util.m:
compiler/continuation_info.m:
compiler/dupelim.m:
compiler/exprn_aux.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_out.m:
compiler/mercury_compile.m:
compiler/middle_rec.m:
compiler/ml_code_gen.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/peephole.m:
compiler/stack_layout.m:
compiler/transform_llds.m:
compiler/var_locn.m:
Conform to the change to prog_data.m, opt_util.m and/or llds.m.
compiler/handle_options.m:
Don't execute the code in stdlabel.m if doing so would cause a compiler
abort.
tests/hard_coded/dense_lookup_switch_non.{m,exp}:
New test case to exercise the new algorithm.
tests/hard_coded/Mmakefile:
Enable the new test case.
tests/hard_coded/cycles.m:
Make this test case conform to our coding convention.
|
||
|
|
e8832be3a5 |
A new module that contains code to standardize labels in the LLDS.
Estimated hours taken: 1 Branches: main compiler/stdlabel.m: A new module that contains code to standardize labels in the LLDS. compiler/ll_backend.m: Include the new module in this package. compiler/options.m: Add an option that governs whether stdlabel.m is invoked or not. compiler/optimize.m: If the option is set, invoke stdlabel.m. compiler/opt_util.m: Add an option to opt_util.replace_labels_instruction_list to allow it to replace labels in label instructions themselves. compiler/dupelim.m: Conform to the changes in opt_util.m compiler/notes/compiler_design.html: Document the new module. |
||
|
|
5af71b60ac |
Remove support for the Aditi backend. It is a pain to have to update it every
Estimated hours taken: 2 Branches: main Remove support for the Aditi backend. It is a pain to have to update it every time a data structure changes when we don't see any benefit from it, and its presence makes compilation of the compiler directory take about 10% longer (since the Aditi backend modules are roughly 10% of the code in the compiler directory). Deleting the Aditi-specific data structures from the HLDS should also speed up compilation a little bit. I have spoken to Rao and he is fine with this step. Aditi users, if there are any, can continue to use the Aditi support in release 0.12.*. I also tagged the last version on the trunk to support aditi with the name "last_aditi". The need for modifications in this Aditi support is likely to be very rare to nonexistent, if the recent past is any guide: the Aditi backend hasn't seen a nontrivial modification in a year or more. This diff removes a net 31492 lines. compiler/add_aditi.m: compiler/aditi_backend.pp: compiler/aditi_builtin_ops.m: compiler/context.m: compiler/dnf.m: compiler/magic.m: compiler/magic_util.m: compiler/rl.m: compiler/rl_analyse.m: compiler/rl_block.m: compiler/rl_block_opt.m: compiler/rl_code.m: compiler/rl_dump.m: compiler/rl_exprn.m: compiler/rl_file.pp: compiler/rl_gen.m: compiler/rl_info.m: compiler/rl_key.m: compiler/rl_liveness.m: compiler/rl_loop.m: compiler/rl_opt.m: compiler/rl_out.pp: compiler/rl_relops.m: compiler/rl_sort.m: compiler/rl_stream.m: Remove these compiler modules, since they existed only to support the Aditi backend. compiler/hlds_goal.m: Delete the Aditi-specific components of goals (e.g. the aditi-builtin kind of generic calls and Aditi-evaluated lambdas). compiler/hlds_pred.m: Delete the Aditi-specific components of pred_infos. compiler/prog_data.m: Delete the Aditi-specific items. compiler/passes_aux.m: Don't worry about processing all procedures or just all non-Aditi procedures. compiler/add_clause.m: Add a predicate from a deleted module that is now used only here. compiler/*.m: Conform to the data structure changes above. compiler/notes/*.html: Remove references to the Aditi backend. tests/invalid/aditi.m: tests/invalid/aditi_errors.err_exp: tests/invalid/aditi_errors.m: tests/invalid/aditi_private_builtin.m: tests/invalid/aditi_state_errors.err_exp: tests/invalid/aditi_state_errors.m: tests/invalid/aditi_update_derived_relation.err_exp: tests/invalid/aditi_update_derived_relation.m: tests/invalid/aditi_update_errors.err_exp: tests/invalid/aditi_update_errors.m: tests/invalid/aditi_update_mode_errors.err_exp: tests/invalid/aditi_update_mode_errors.m: tests/valid/aditi.m: tests/valid/aditi_calls_mercury.m: tests/valid/aditi_error_bug.m: tests/valid/aditi_error_bug2.m: tests/valid/aditi_error_bug3.m: tests/valid/aditi_private_builtin.m: tests/valid/aditi_query.m: tests/valid/aditi_update.m: tests/valid/base_relation.m: tests/valid/base_relation2.m: tests/valid/ite_to_disj.m: Remove these Aditi-specific tests. tests/*/Mmakefile: Remove the references to these Aditi-specific tests. |
||
|
|
905e4a114f |
Convert a bunch of modules to four-space indentation.
Estimated hours taken: 4 Branches: main compiler/*.m: Convert a bunch of modules to four-space indentation. In the process, fix departures from our coding standards. In some cases, do minor other cleanups such as changing argument orders to be friendly to state variables. There are no algorithmic changes. |
||
|
|
df0d9036cf |
Optimize calls that would be tail calls in Prolog but are followed by
Estimated hours taken: 40 Branches: main Optimize calls that would be tail calls in Prolog but are followed by construction unifications in Mercury: last call modulo construction. For now, the optimization is available only for the LLDS backend. compiler/lco.m: Turn this module from a placeholder to a real implementation of the optimization. compiler/hlds_goal.m: Allow lco.m to attach to construction unifications a note that says that certain arguments, instead of being filled in by the unification, should have their addresses taken and stored in the corresponding variables. Group this note together with the note that asks for term size profiling to avoid an increase in the sizes of goals in the compiler in most cases. compiler/hlds_pred.m: Provide a predicate for setting the name of a predicate after its creation. This functionality is used by lco.m. Extend the pred_transformation part of the pred_origin type to allow it to express that a procedure was created by lco.m. List the new primitive store_at_ref as a no-typeinfo builtin. Fix some problems with indentation. compiler/layout_out.m: Handle the new pred_transformation. compiler/unify_gen.m: When processing construction unifications that have the new feaure turned on, perform the requested action. Fix some departures from coding style. Shorten lines by deleting unnecessary module qualifications. Add some auxiliary predicates to make the code easier to read. compiler/var_locn.m: Fix an earlier oversight: when materializing variables inside rvals and lvals, look inside memory references too. Previously, the omission didn't matter, since we didn't generate such references, but now we do. Fix some departures from coding style. compiler/llds_out.m: Fix some old XXXs in code handling memory references. We didn't use to generate such references, but now we do. Move some functionality here from code_aux.m. compiler/code_info.m: Provide some primitive operations needed by the new code in var_locn.m. Delete an unneeded predicate. compiler/options.m: Rename the existing option optimize_constructor_last_call as optimize_constructor_last_call_accumulator, since that optimization is done by accumulator.m. Make optimize_constructor_last_call be the option that calls for the new optimization. compiler/handle_options.m: Handle the implications of the new option. compiler/mercury_compile.m: Invoke the lco module by its new interface. librrary/private_builtin.m: Add a new primitive operation, store_at_ref, for use by the new optimization. Switch the module to four-space indentation. compiler/add_clause.m: Comment out the warning for clauses for builtin, since this is needed to bootstrap the addition of the new builtin. compiler/term_constr_initial.m: Handle the new builtin. compiler/accumulator.m: Conform to the change in options. compiler/builtin_ops.m: Provide a third template for builtins, for use by store_at_ref. Convert the file to four-space indentation. compiler/call_gen.m: Generate code following the new builtin template. compiler/rl_exprn.m: Minor changes to conform to the changes in builtin templates. compiler/quantification.m: Minor changes to conform to the changes in construct unifications. Don't make the "get" predicates operating on quantification_infos to return the "new" quantification_info: it is always the same as the old one. compiler/aditi_builtin_ops.m: compiler/common.m: compiler/deep_profiling.m: compiler/higher_order.m: compiler/hlds_out.m: compiler/lambda.m: compiler/magic_util.m: compiler/ml_unify_gen.m: compiler/modecheck_unify.m: compiler/polymorphism.m: compiler/size_prof.m: Minor changes to conform to the changes in construct unifications. compiler/dependency_graph.m: Add a new predicate to recompute the dependency information, even if a previous (and possibly now inaccurate) version is present. Change the interface to make it clearer, by changing bools into types specific to the situation. Convert the file to four-space indentation. compiler/mode_constraints.m: Minor changes to conform to the changes in dependency_graph.m. compiler/code_aux.m: Delete this module. Half its functionality has been moved into llds_out.m, half to middle_rec.m (its only user). compiler/goal_form.m: Move the predicates in this module that are used only by middle_rec.m to middle_rec.m. Convert the file to four-space indentation. compiler/goal_util.m: compiler/det_util.m: Move update_instmap from det_util to goal_util, since it is usefulness extends beyond determinism analysis. Convert det_util.m to four-space indentation. compiler/middle_rec.m: Move here the code required only here from code_aux and goal_form. Update the moved code for the changes in construct unifications. The updates are specific to middle_rec.m: they wouldn't be of use to other modules. They basically say that any code that takes the addresses of fields cannot be handled by middle_rec.m. compiler/code_gen.m: compiler/det_analysis.m: compiler/live_vars.m: compiler/ll_backend.m: compiler/loop_inv.m: compiler/switch_detection.m: compiler/switch_gen.m: compiler/notes/compiler_design.html: Minor changes to conform to the deletion of code_aux.m and/or the movement of code from det_util to goal_util.m. compiler/opt_debug.m: Print info for vars in rvals. compiler/hlds_module.m: Convert a lambda to an explicit predicate to make some code easier to read. Switch the module to four-space indentation. |
||
|
|
68b1a6c0ea |
Add a new LLDS optimization we discussed on thursday: elimination of procedures
Estimated hours taken: 4 Branches: main Add a new LLDS optimization we discussed on thursday: elimination of procedures whose code is an exact copy of the code of another mode of the same predicate. This happens with in,out vs di,uo and also possibly with in,out vs any,any. The new optimization reduces the compiler's code size by 0.6%. compiler/dupproc.m: A new module implementing the new optimization. compiler/ll_backend.m: Add dupproc.m as a new submodule. compiler/notes/compiler_design.html: Mention the new module. compiler/options.m: Add an option, --optimize-proc-dups, enabling the new optimization. Make --opt-space imply the new option. doc/user_guide.texi: Document the new option. compiler/mercury_compile.m: Invoke the new optimization when compiling by predicates. Move the imports of library modules to their own section. compiler/handle_options.m: Make --optimize-proc-dups imply compiling by predicates. The rest of these changes are cosmetic only. compiler/llds.m: Delete an obsolete form of constant we haven't used in a long time. compiler/exprn_aux.m: compiler/jumpopt.m: compiler/llds_out.m: compiler/opt_debug.m: compiler/opt_util.m: Conform to the change in llds.m. compiler/dependency_graph.m: Clean up some comments. compiler/dupelim.m: Fix some variable names. compiler/hlds_module.m: compiler/hlds_pred.m: Minor cleanups. |
||
|
|
a83b6feca4 |
Don't include static_term as a submodule of ll_backend
Estimated hours taken: 0.1 Branches: main compiler/ll_backend.m: Don't include static_term as a submodule of ll_backend because it no longer exists. XXX I'm not sure why the compiler isn't complaining about this. |
||
|
|
59d2d4a573 |
This adds a module mdbcomp__trace_counts that reads in the
Estimated hours taken: 17 Branches: main This adds a module mdbcomp__trace_counts that reads in the .mercury_trace_counts files produced by the compiler's trace mechanism. The format of said files was slightly changed. As the new module is to be used by the compiler and the debugger, it is placed in the mdbcomp module. This required bringing some types from the compiler into a new module within mdbcomp. browser/trace_counts.m: New module for reading execution trace summaries. browser/prim_data.m: New module holding types and predicates moved in from the compiler. Types: pred_or_func, sym_name, module_name, proc_label, special_pred_id, trace_port Predicates: string_to_sym_name, insert_module_qualifier The mode field of proc_label is now an int instead of a proc_id to avoid pulling proc_id into mdbcomp. browser/mdbcomp.m: Add trace_counts and prim_data to the mdbcomp module. browser/declarative_execution.m: Renamed mdb's definition of module_name to flat_module_name to avoid conflicts with the definition in mdbcomp__prim_data. runtime/mercury_trace_base.c: In the format of .mercury_trace_counts, write module and predicate names now use quoted atom syntax so that names with spaces and non-printable characters can be machine-parsed. browser/: compiler/: Many changes to account for movement of types, and the change to proc_label. |
||
|
|
5d6fd3bd6f |
Reduce the dependence of earlier parts of the compiler on the later ones.
Estimated hours taken: 4 Branches: main Reduce the dependence of earlier parts of the compiler on the later ones. Unnecessary import_module declarations in top level modules such as hlds.m cause unnecessary recompilations when adding new types in later modules, such as submodules of ll_backend.m. This change reduces the number of such unnecessary imports. There are no changes in algorithms, only functionality being moved around. compiler/code_model.m: Change this module from being a submodule of backend_libs.m to being a submodule of hlds.m, since nothing in it is dependent on any backend. compiler/arg_info.m: compiler/code_util.m: Change arg_info.m from being a submodule of ll_backend.m to being a submodule of hlds.m, since most of it is applicable to all current and foreseeable backends. Move the one exported predicate that is ll_backend dependent, and its support predicates, to code_util.m. compiler/backend_libs.m: compiler/ll_backend.m: compiler/hlds.m: Update include_module declarations in accordance with the above. compiler/prog_data.m: compiler/term_util.m: Instead of defining two separate types for holding argument size and termination information, one including HLDS-specific information (in term_util.m) and one not (in prog_data.m), use a polymorphic type defined in prog_data.m and two monomorphic instances. compiler/termination.m: compiler/mercury_to_mercury.m: Change the predicates for writing out argument size and termination information to handle the polymorphic type (we don't need special handling of the monomorphic versions), and move them from termination.m to mercury_to_mercury.m, since this allows us to avoid some undesirable dependencies. compiler/base_typeclass_info.m: compiler/hlds_code_util.m: Move the predicate make_instance_string from base_typeclass_info.m to hlds_code_util.m, again because it allows us to remove some undesirable dependencies. compiler/top_level.m: compiler/backend_libs.m: compiler/check_hlds.m: compiler/hlds.m: compiler/ll_backend.m: compiler/parse_tree.m: compiler/transform_hlds.m: Delete some import_module declarations of other top level modules in these top level modules. Some imports were totally unnecessary. Some imports were useful in only a small minority of submodules; those submodules now import the necessary top level modules directly. Move remaining import_module declarations to the implementation section where this is feasible. Where we still need to import modules we ideally shouldn't, note why. compiler/*.m: Update imports of code_util and arg_info. In some cases, import top level modules no longer imported by the parent module. In some cases, delete unnecessary imports. |
||
|
|
f601bf2dcd |
Various trivial minor cleanups.
Estimated hours taken: 1 Branches: main Various trivial minor cleanups. compiler/hlds.m: compiler/ll_backend.m: Delete obsolete XXX comments that referred to problems which have since been fixed. compiler/ll_backend.m: Fix an XXX: list the HLDS->HLDS passes in the order in which they get invoked. compiler/hlds_code_util.m: Delete a type whose only purpose was to avoid a warning about the interface of this module being empty, since the interface is no longer empty. compiler/modules.m: s/ / / compiler/post_typecheck.m: Delete an unnecessary `:- import_module' declaration. |
||
|
|
92045bdc78 |
Simplify the handling of static ground terms in the LLDS backend.
Estimated hours taken: 5 Branches: main Simplify the handling of static ground terms in the LLDS backend. Instead of creating code, rtti and layout structures all containing create rvals and then converting those rvals to static cells, create the static cells directly. compiler/llds.m: Remove the create alternative from rvals, and the types used only by create. Delete the code handling the global_data type, which has been moved to global_data.m. compiler/global_data.m: A new module handling static data structures for the LLDS backend. The basis of this module is the code that used to be in llds.m handling the global_data type, but this has been augmented to manage static cells as well as the data structures defined in rtti.m and layout.m. Also, rename the non_common_data field of global_data, which no longer makes sense, to refer to deep profiling, since it holds deep profiling data structures. compiler/llds_common.m: Delete this file, since it is no longer needed. The operative part is now in global data.m; the rest (including the code to traverse code and data structures looking for create rvals) is no longer needed. compiler/ll_backend.m: Delete the deleted module, and add the added module. XXX These changes should be also be documented in notes/compiler_design.html when Fergus finishes his changes to that file. compiler/code_info.m: Add the database of static cells to the code generator state. compiler/code_gen.m: compiler/ll_pseudo_type_info.m: compiler/lookup_switch.m: compiler/mercury_compile.m: compiler/stack_layout.m: compiler/static_term.m: compiler/string_switch.m: compiler/unify_gen.m: compiler/var_locn.m: Instead of creating create rvals, create static cells and return references to those cells. The static cell database ensures that we never create duplicate cells (unless --no-common-data forces us to do so). Pass around the static cell database. compiler/code_util.m: compiler/continuation_info.m: compiler/dupelim.m: compiler/exprn_aux.m: compiler/jumpopt.m: compiler/livemap.m: compiler/llds_out.m: compiler/middle_rec.m: compiler/opt_debug.m: compiler/opt_util.m: compiler/optimize.m: Minor changes to conform to the above, mostly consisting of the deletion of code that handled create rvals. |
||
|
|
cbd6a7c56a |
Delete the old, lazy LLDS code generator, since we won't be maintaining it
Estimated hours taken: 3 Branches: main Delete the old, lazy LLDS code generator, since we won't be maintaining it anymore. Its deletion speeds up the compiler by 0.2% when using the LLDS back end. compiler/code_exprn.m: Delete the module. compiler/ll_backend.m: Delete code_exprn from the list of submodules of this module. compiler/notes/compiler_design.html: Delete the documentation of code_exprn.m, and update the documentation of var_locn.m. compiler/options.m: Delete the --lazy-code option that used to select code_exprn over var_locn. Delete the follow_vars option, since the LLDS backend now always executes the follow_vars pass. compiler/handle_options.m: Delete the code setting the follow_vars option. Make the setting of static_ground_terms conditional on the use of the LLDS backend (which now implies the eager code generator). compiler/code_info.m: Delete lots of code that switches between code_exprn.m and var_locn.m. Simplify the data structures accordingly. compiler/store_alloc.m: Delete the code and data structures required to cater for the case where the follow_vars pass isn't run. compiler/pragma_c_gen.m: compiler/var_locn.m: compiler/hlds_goal.m: compiler/lookup_switch.m: Update a comment. doc/user_guide.texi: Delete the documentation of --follow-vars. --lazy-code was already undocumented. tests/valid/Mercury.options: Delete a setting of --no-follow-vars. |
||
|
|
4954da84cc |
Reduce the dependence of the MLDS backend on the LLDS backend by moving
Estimated hours taken: 2 Branches: main Reduce the dependence of the MLDS backend on the LLDS backend by moving functionality dealing with proc_labels from the LLDS backend (code_util.m) to a new module, proc_label.m, which is part of backend_libs. compiler/code_util.m: compiler/proc_label.m: Move a type and some code from code_util to the new module. Convert predicates to functions as relevant. (The old code was written before functions were available). compiler/backend_libs.m: Add proc_label to the list of submodules. compiler/rtti.m: Rename a function to avoid a name clash with a function in proc_label.m. compiler/*.m: Conform to the changes above. Ensure that all imports of modules in the compiler directory are on lines of their own, to make CVS merges easier. Sort the imports. |
||
|
|
189b9215ae |
This diff implements stack slot optimization for the LLDS back end based on
Estimated hours taken: 400
Branches: main
This diff implements stack slot optimization for the LLDS back end based on
the idea that after a unification such as A = f(B, C, D), saving the
variable A on the stack indirectly also saves the values of B, C and D.
Figuring out what subset of {B,C,D} to access via A and what subset to access
via their own stack slots is a tricky optimization problem. The algorithm we
use to solve it is described in the paper "Using the heap to eliminate stack
accesses" by Zoltan Somogyi and Peter Stuckey, available in ~zs/rep/stackslot.
That paper also describes (and has examples of) the source-to-source
transformation that implements the optimization.
The optimization needs to know what variables are flushed at call sites
and at program points that establish resume points (e.g. entries to
disjunctions and if-then-elses). We already had code to compute this
information in live_vars.m, but this code was being invoked too late.
This diff modifies live_vars.m to allow it to be invoked both by the stack
slot optimization transformation and by the code generator, and allows its
function to be tailored to the requirements of each invocation.
The information computed by live_vars.m is specific to the LLDS back end,
since the MLDS back ends do not (yet) have the same control over stack
frame layout. We therefore store this information in a new back end specific
field in goal_infos. For uniformity, we make all the other existing back end
specific fields in goal_infos, as well as the similarly back end specific
store map field of goal_exprs, subfields of this new field. This happens
to significantly reduce the sizes of goal_infos.
To allow a more meaningful comparison of the gains produced by the new
optimization, do not save any variables across erroneous calls even if
the new optimization is not enabled.
compiler/stack_opt.m:
New module containing the code that performs the transformation
to optimize stack slot usage.
compiler/matching.m:
New module containing an algorithm for maximal matching in bipartite
graphs, specialized for the graphs needed by stack_opt.m.
compiler/mercury_compile.m:
Invoke the new optimization if the options ask for it.
compiler/stack_alloc.m:
New module containing code that is shared between the old,
non-optimizing stack slot allocation system and the new, optimizing
stack slot allocation system, and the code for actually allocating
stack slots in the absence of optimization.
Live_vars.m used to have two tasks: find out what variables need to be
saved on the stack, and allocating those variables to stack slots.
Live_vars.m now does only the first task; stack_alloc.m now does
the second, using code that used to be in live_vars.m.
compiler/trace_params:
Add a new function to test the trace level, which returns yes if we
want to preserve the values of the input headvars.
compiler/notes/compiler_design.html:
Document the new modules (as well as trace_params.m, which wasn't
documented earlier).
compiler/live_vars.m:
Delete the code that is now in stack_alloc.m and graph_colour.m.
Separate out the kinds of stack uses due to nondeterminism: the stack
slots used by nondet calls, and the stack slots used by resumption
points, in order to allow the reuse of stack slots used by resumption
points after execution has left their scope. This should allow the
same stack slots to be used by different variables in the resumption
point at the start of an else branch and nondet calls in the then
branch, since the resumption point of the else branch is not in effect
when the then branch is executed.
If the new option --opt-no-return-calls is set, then say that we do not
need to save any values across erroneous calls.
Use type classes to allow the information generated by this module
to be recorded in the way required by its invoker.
Package up the data structures being passed around readonly into a
single tuple.
compiler/store_alloc.m:
Allow this module to be invoked by stack_opt.m without invoking the
follow_vars transformation, since applying follow_vars before the form
of the HLDS code is otherwise final can be a pessimization.
Make the module_info a part of the record containing the readonly data
passed around during the traversal.
compiler/common.m:
Do not delete or move around unifications created by stack_opt.m.
compiler/call_gen.m:
compiler/code_info.m:
compiler/continuation_info.m:
compiler/var_locn.m:
Allow the code generator to delete its last record of the location
of a value when generating code to make an erroneous call, if the new
--opt-no-return-calls option is set.
compiler/code_gen.m:
Use a more useful algorithm to create the messages/comments that
we put into incr_sp instructions, e.g. by distinguishing between
predicates and functions. This is to allow the new scripts in the
tool directory to gather statistics about the effect of the
optimization on stack frame sizes.
library/exception.m:
Make a hand-written incr_sp follow the new pattern.
compiler/arg_info.m:
Add predicates to figure out the set of input, output and unused
arguments of a procedure in several different circumstances.
Previously, variants of these predicates were repeated in several
places.
compiler/goal_util.m:
Export some previously private utility predicates.
compiler/handle_options.m:
Turn off stack slot optimizations when debugging, unless
--trace-optimized is set.
Add a new dump format useful for debugging --optimize-saved-vars.
compiler/hlds_llds.m:
New module for handling all the stuff specific to the LLDS back end
in HLDS goal_infos.
compiler/hlds_goal.m:
Move all the relevant stuff into the new back end specific field
in goal_infos.
compiler/notes/allocation.html:
Update the documentation of store maps to reflect their movement
into a subfield of goal_infos.
compiler/*.m:
Minor changes to accomodate the placement of all back end specific
information about goals from goal_exprs and individual fields of
goal_infos into a new field in goal_infos that gathers together
all back end specific information.
compiler/use_local_vars.m:
Look for sequences in which several instructions use a fake register
or stack slot as a base register pointing to a cell, and make those
instructions use a local variable instead.
Without this, a key assumption of the stack slot optimization,
that accessing a field in a cell costs only one load or store
instruction, would be much less likely to be true. (With this
optimization, the assumption will be false only if the C compiler's
code generator runs out of registers in a basic block, which for
the code we generate should be unlikely even on x86s.)
compiler/options.m:
Make the old option --optimize-saved-vars ask for both the old stack
slot optimization (implemented by saved_vars.m) that only eliminates
the storing of constants in stack slots, and the new optimization.
Add two new options --optimize-saved-vars-{const,cell} to turn on
the two optimizations separately.
Add a bunch of options to specify the parameters of the new
optimizations, both in stack_opt.m and use_local_vars.m. These are
for implementors only; they are deliberately not documented.
Add a new option, --opt-no-return-cells, that governs whether we avoid
saving variables on the stack at calls that cannot return, either by
succeeding or by failing. This is for implementors only, and thus
deliberately documented only in comments. It is enabled by default.
compiler/optimize.m:
Transmit the value of a new option to use_local_vars.m.
doc/user_guide.texi:
Update the documentation of --optimize-saved-vars.
library/tree234.m:
Undo a previous change of mine that effectively applied this
optimization by hand. That change complicated the code, and now
the compiler can do the optimization automatically.
tools/extract_incr_sp:
A new script for extracting stack frame sizes and messages from
stack increment operations in the C code for LLDS grades.
tools/frame_sizes:
A new script that uses extract_incr_sp to extract information about
stack frame sizes from the C files saved from a stage 2 directory
by makebatch and summarizes the resulting information.
tools/avg_frame_size:
A new script that computes average stack frame sizes from the files
created by frame_sizes.
tools/compare_frame_sizes:
A new script that compares the stack frame size information
extracted from two different stage 2 directories by frame_sizes,
reporting on both average stack frame sizes and on specific procedures
that have different stack frame sizes in the two versions.
|
||
|
|
7597790760 |
Use sub-modules to structure the modules in the Mercury compiler directory.
The main aim of this change is to make the overall, high-level structure of the compiler clearer, and to encourage better encapsulation of the major components. compiler/libs.m: compiler/backend_libs.m: compiler/parse_tree.m: compiler/hlds.m: compiler/check_hlds.m: compiler/transform_hlds.m: compiler/bytecode_backend.m: compiler/aditi_backend.m: compiler/ml_backend.m: compiler/ll_backend.m: compiler/top_level.m: New files. One module for each of the major components of the Mercury compiler. These modules contain (as separate sub-modules) all the other modules in the Mercury compiler, except gcc.m and mlds_to_gcc.m. Mmakefile: compiler/Mmakefile: Handle the fact that the top-level module is now `top_level', not `mercury_compile' (since `mercury_compile' is a sub-module of `top_level'). compiler/Mmakefile: Update settings of *FLAGS-<modulename> to use the appropriate nested module names. compiler/recompilation_check.m: compiler/recompilation_version.m: compiler/recompilation_usage.m: compiler/recompilation.check.m: compiler/recompilation.version.m: compiler/recompilation.version.m: Convert the `recompilation_*' modules into sub-modules of the `recompilation' module. compiler/*.m: compiler/*.pp: Module-qualify the module names in `:- module', `:- import_module', and `:- use_module' declarations. compiler/base_type_info.m: compiler/base_type_layout.m: Deleted these unused empty modules. compiler/prog_data.m: compiler/globals.m: Move the `foreign_language' type from prog_data to globals. compiler/mlds.m: compiler/ml_util.m: compiler/mlds_to_il.m: Import `globals', for `foreign_language'. Mmake.common.in: trace/Mmakefile: runtime/Mmakefile: Rename the %.check.c targets as %.check_hdr.c, to avoid conflicts with compiler/recompilation.check.c. |