mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-13 04:44:39 +00:00
Branches: main Store double-precision `float' constructor arguments in unboxed form, in high-level C grades on 32-bit platforms, i.e. `float' (and equivalent) arguments may occupy two machine words. As the C code generated by the MLDS back-end makes use of MR_Float variables and parameters, float (un)boxing may be reduced substantially in many programs. compiler/prog_data.m: Add `double_word' as a new option for constructor argument widths, only used for float arguments as yet. compiler/make_hlds_passes.m: Set constructor arguments to have `double_word' width if required, and possible. compiler/type_util.m: Add helper predicate. compiler/builtin_ops.m: compiler/c_util.m: compiler/llds.m: Add two new binary operators used by the MLDS back-end. compiler/arg_pack.m: Handle `double_word' arguments. compiler/ml_code_util.m: Deciding whether or not a float constructor argument requires boxing now depends on the width of the field. compiler/ml_global_data.m: When a float constant appears as an initialiser of a generic array element, it is now always unboxed, irrespective of --unboxed-float. compiler/ml_type_gen.m: Take double-word arguments into account when generating structure fields. compiler/ml_unify_gen.m: Handle double-word float constructor arguments in (de)constructions. In some cases we break a float argument into its two words, so generating two assignments statements or two separate rvals. Take double-word arguments into account when calculating field offsets. compiler/mlds_to_c.m: The new binary operators require no changes here. As a special case, write `MR_float_from_dword_ptr(&X)' instead of `MR_float_from_dword(X, Y)' when X, Y are consecutive words within a field. The definition of `MR_float_from_dword_ptr' is more straightforward, and gcc produces better code than if we use the more general `MR_float_from_dword'. compiler/rtti_out.m: For double-word arguments, generate MR_DuArgLocn structures with MR_arg_bits set to -1. compiler/rtti_to_mlds.m: Handle double-word arguments in field offset calculation. compiler/unify_gen.m: Partially handle double_word arguments in LLDS back-end. compiler/handle_options.m: Set --unboxed-float when targetting Java, C# and Erlang. compiler/structure_reuse.direct.choose_reuse.m: Rename a predicate. compiler/bytecode.m: compiler/equiv_type.m: compiler/equiv_type_hlds.m: compiler/llds_to_x86_64.m: compiler/mlds_to_gcc.m: compiler/mlds_to_il.m: compiler/opt_debug.m: Conform to changes. library/construct.m: library/store.m: Handle double-word constructor arguments. runtime/mercury_conf.h.in: Clarify what `MR_BOXED_FLOAT' now means. runtime/mercury_float.h: Add helper macros for converting between doubles and word/dwords. runtime/mercury_deconstruct.c: runtime/mercury_deconstruct.h: Add a macro `MR_arg_value' and a helper function to extract a constructor argument value. This replaces `MR_unpack_arg'. runtime/mercury_type_info.h: Remove `MR_unpack_arg'. Document that MR_DuArgLocn.MR_arg_bits may be -1. runtime/mercury_deconstruct_macros.h: runtime/mercury_deep_copy_body.h: runtime/mercury_ml_arg_body.h: runtime/mercury_table_type_body.h: runtime/mercury_tabling.c: runtime/mercury_type_info.c: Handle double-word constructor arguments. tests/hard_coded/Mercury.options: tests/hard_coded/Mmakefile: tests/hard_coded/lco_double.exp: tests/hard_coded/lco_double.m: tests/hard_coded/pack_args_float.exp: tests/hard_coded/pack_args_float.m: Add test cases. trace/mercury_trace_vars.c: Conform to changes.
295 lines
11 KiB
Mathematica
295 lines
11 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2001, 2003-2006, 2009-2011 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: builtin_ops.m -- defines the builtin operator types.
|
|
% Main author: fjh.
|
|
%
|
|
% This module defines various types which enumerate the different builtin
|
|
% operators. Several of the different back-ends -- the bytecode back-end,
|
|
% the LLDS, and the MLDS -- all use the same set of builtin operators.
|
|
% These operators are defined here.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module backend_libs.builtin_ops.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type unary_op
|
|
---> mktag
|
|
; tag
|
|
; unmktag
|
|
; strip_tag
|
|
; mkbody
|
|
; unmkbody
|
|
; bitwise_complement
|
|
; logical_not
|
|
; hash_string
|
|
; hash_string2
|
|
; hash_string3.
|
|
|
|
:- type binary_op
|
|
---> int_add
|
|
; int_sub
|
|
; int_mul
|
|
; int_div % assumed to truncate toward zero
|
|
; int_mod % remainder (w.r.t. truncating integer division)
|
|
% XXX `mod' should be renamed `rem'
|
|
; unchecked_left_shift
|
|
; unchecked_right_shift
|
|
; bitwise_and
|
|
; bitwise_or
|
|
; bitwise_xor
|
|
; logical_and
|
|
; logical_or
|
|
; eq % ==
|
|
; ne % !=
|
|
; body
|
|
; array_index(array_elem_type)
|
|
; str_eq % string comparisons
|
|
; str_ne
|
|
; str_lt
|
|
; str_gt
|
|
; str_le
|
|
; str_ge
|
|
; str_cmp % returns -ve, 0, or +ve
|
|
; int_lt % signed integer comparions
|
|
; int_gt
|
|
; int_le
|
|
; int_ge
|
|
; unsigned_le % unsigned integer comparison
|
|
% Note that the arguments to `unsigned_le' are just ordinary
|
|
% (signed) Mercury ints, but it does the comparison as
|
|
% if they were first cast to an unsigned type, so e.g.
|
|
% binary(unsigned_le, int_const(1), int_const(-1)) returns true,
|
|
% since (MR_Unsigned) 1 <= (MR_Unsigned) -1.
|
|
|
|
; float_plus
|
|
; float_minus
|
|
; float_times
|
|
; float_divide
|
|
; float_eq
|
|
; float_ne
|
|
; float_lt
|
|
; float_gt
|
|
; float_le
|
|
; float_ge
|
|
; float_word_bits
|
|
; float_from_dword
|
|
|
|
; compound_eq
|
|
; compound_lt.
|
|
% Comparisons on values of non-atomic types. This is likely to be
|
|
% supported only on very high-level back-ends.
|
|
|
|
% For the MLDS back-end, we need to know the element type for each
|
|
% array_index operation.
|
|
%
|
|
% Currently array index operations are only generated in limited
|
|
% circumstances. Using a simple representation for them here,
|
|
% rather than just putting the MLDS type here, avoids the need
|
|
% for this module to depend on back-end specific stuff like MLDS types.
|
|
:- type array_elem_type
|
|
---> array_elem_scalar(scalar_array_elem_type)
|
|
; array_elem_struct(list(scalar_array_elem_type)).
|
|
|
|
:- type scalar_array_elem_type
|
|
---> scalar_elem_string % ml_string_type
|
|
; scalar_elem_int % mlds_native_int_type
|
|
; scalar_elem_generic. % mlds_generic_type
|
|
|
|
% translate_builtin:
|
|
%
|
|
% Given a module name, a predicate name, a proc_id and a list of the
|
|
% arguments, find out if that procedure of that predicate is an inline
|
|
% builtin. If so, return code which can be used to evaluate that call:
|
|
% either an assignment (if the builtin is det) or a test (if the builtin
|
|
% is semidet).
|
|
%
|
|
% There are some further guarantees on the form of the expressions
|
|
% in the code returned -- see below for details.
|
|
% (bytecode_gen.m depends on these guarantees.)
|
|
%
|
|
:- pred translate_builtin(module_name::in, string::in, proc_id::in,
|
|
list(T)::in, simple_code(T)::out(simple_code)) is semidet.
|
|
|
|
:- type simple_code(T)
|
|
---> assign(T, simple_expr(T))
|
|
; ref_assign(T, T)
|
|
; test(simple_expr(T))
|
|
; noop(list(T)).
|
|
|
|
:- type simple_expr(T)
|
|
---> leaf(T)
|
|
; int_const(int)
|
|
; float_const(float)
|
|
; unary(unary_op, simple_expr(T))
|
|
; binary(binary_op, simple_expr(T), simple_expr(T)).
|
|
|
|
% Each test expression returned is guaranteed to be either a unary
|
|
% or binary operator, applied to arguments that are either variables
|
|
% (from the argument list) or constants.
|
|
%
|
|
% Each to be assigned expression is guaranteed to be either in a form
|
|
% acceptable for a test rval, or in the form of a variable.
|
|
|
|
:- inst simple_code
|
|
---> assign(ground, simple_assign_expr)
|
|
; ref_assign(ground, ground)
|
|
; test(simple_test_expr)
|
|
; noop(ground).
|
|
|
|
:- inst simple_arg_expr
|
|
---> leaf(ground)
|
|
; int_const(ground)
|
|
; float_const(ground).
|
|
|
|
:- inst simple_test_expr
|
|
---> unary(ground, simple_arg_expr)
|
|
; binary(ground, simple_arg_expr, simple_arg_expr).
|
|
|
|
:- inst simple_assign_expr
|
|
---> unary(ground, simple_arg_expr)
|
|
; binary(ground, simple_arg_expr, simple_arg_expr)
|
|
; leaf(ground).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
translate_builtin(FullyQualifiedModule, PredName, ProcId, Args, Code) :-
|
|
proc_id_to_int(ProcId, ProcInt),
|
|
is_std_lib_module_name(FullyQualifiedModule, ModuleName),
|
|
builtin_translation(ModuleName, PredName, ProcInt, Args, Code).
|
|
|
|
:- pred builtin_translation(string::in, string::in, int::in, list(T)::in,
|
|
simple_code(T)::out(simple_code)) is semidet.
|
|
|
|
builtin_translation("private_builtin", "trace_get_io_state", 0, [X],
|
|
noop([X])).
|
|
builtin_translation("private_builtin", "trace_set_io_state", 0, [_X],
|
|
noop([])).
|
|
|
|
builtin_translation("private_builtin", "store_at_ref", 0, [X, Y],
|
|
ref_assign(X, Y)).
|
|
builtin_translation("private_builtin", "store_at_ref_impure", 0, [X, Y],
|
|
ref_assign(X, Y)).
|
|
|
|
% Note that the code we generate for unsafe_type_cast is not type-correct.
|
|
% Back-ends that require type-correct intermediate code (e.g. the MLDS
|
|
% back-end) must handle unsafe_type_cast separately, rather than by calling
|
|
% builtin_translation.
|
|
builtin_translation("private_builtin", "unsafe_type_cast", 0, [X, Y],
|
|
assign(Y, leaf(X))).
|
|
builtin_translation("builtin", "unsafe_promise_unique", 0, [X, Y],
|
|
assign(Y, leaf(X))).
|
|
|
|
builtin_translation("private_builtin", "builtin_int_gt", 0, [X, Y],
|
|
test(binary(int_gt, leaf(X), leaf(Y)))).
|
|
builtin_translation("private_builtin", "builtin_int_lt", 0, [X, Y],
|
|
test(binary(int_lt, leaf(X), leaf(Y)))).
|
|
|
|
builtin_translation("private_builtin", "builtin_compound_eq", 0, [X, Y],
|
|
test(binary(compound_eq, leaf(X), leaf(Y)))).
|
|
builtin_translation("private_builtin", "builtin_compound_lt", 0, [X, Y],
|
|
test(binary(compound_lt, leaf(X), leaf(Y)))).
|
|
|
|
builtin_translation("term_size_prof_builtin", "term_size_plus", 0, [X, Y, Z],
|
|
assign(Z, binary(int_add, leaf(X), leaf(Y)))).
|
|
|
|
builtin_translation("int", "+", 0, [X, Y, Z],
|
|
assign(Z, binary(int_add, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "+", 1, [X, Y, Z],
|
|
assign(X, binary(int_sub, leaf(Z), leaf(Y)))).
|
|
builtin_translation("int", "+", 2, [X, Y, Z],
|
|
assign(Y, binary(int_sub, leaf(Z), leaf(X)))).
|
|
builtin_translation("int", "plus", 0, [X, Y, Z],
|
|
assign(Z, binary(int_add, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "-", 0, [X, Y, Z],
|
|
assign(Z, binary(int_sub, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "-", 1, [X, Y, Z],
|
|
assign(X, binary(int_add, leaf(Y), leaf(Z)))).
|
|
builtin_translation("int", "-", 2, [X, Y, Z],
|
|
assign(Y, binary(int_sub, leaf(X), leaf(Z)))).
|
|
builtin_translation("int", "minus", 0, [X, Y, Z],
|
|
assign(Z, binary(int_sub, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "*", 0, [X, Y, Z],
|
|
assign(Z, binary(int_mul, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "times", 0, [X, Y, Z],
|
|
assign(Z, binary(int_mul, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "unchecked_quotient", 0, [X, Y, Z],
|
|
assign(Z, binary(int_div, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "unchecked_rem", 0, [X, Y, Z],
|
|
assign(Z, binary(int_mod, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "unchecked_left_shift", 0, [X, Y, Z],
|
|
assign(Z, binary(unchecked_left_shift, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "unchecked_right_shift", 0, [X, Y, Z],
|
|
assign(Z, binary(unchecked_right_shift, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "/\\", 0, [X, Y, Z],
|
|
assign(Z, binary(bitwise_and, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "\\/", 0, [X, Y, Z],
|
|
assign(Z, binary(bitwise_or, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "xor", 0, [X, Y, Z],
|
|
assign(Z, binary(bitwise_xor, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "xor", 1, [X, Y, Z],
|
|
assign(Y, binary(bitwise_xor, leaf(X), leaf(Z)))).
|
|
builtin_translation("int", "xor", 2, [X, Y, Z],
|
|
assign(X, binary(bitwise_xor, leaf(Y), leaf(Z)))).
|
|
builtin_translation("int", "+", 0, [X, Y],
|
|
assign(Y, leaf(X))).
|
|
builtin_translation("int", "-", 0, [X, Y],
|
|
assign(Y, binary(int_sub, int_const(0), leaf(X)))).
|
|
builtin_translation("int", "\\", 0, [X, Y],
|
|
assign(Y, unary(bitwise_complement, leaf(X)))).
|
|
|
|
builtin_translation("int", ">", 0, [X, Y],
|
|
test(binary(int_gt, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "<", 0, [X, Y],
|
|
test(binary(int_lt, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", ">=", 0, [X, Y],
|
|
test(binary(int_ge, leaf(X), leaf(Y)))).
|
|
builtin_translation("int", "=<", 0, [X, Y],
|
|
test(binary(int_le, leaf(X), leaf(Y)))).
|
|
|
|
builtin_translation("float", "+", 0, [X, Y, Z],
|
|
assign(Z, binary(float_plus, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", "-", 0, [X, Y, Z],
|
|
assign(Z, binary(float_minus, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", "*", 0, [X, Y, Z],
|
|
assign(Z, binary(float_times, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", "unchecked_quotient", 0, [X, Y, Z],
|
|
assign(Z, binary(float_divide, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", "+", 0, [X, Y],
|
|
assign(Y, leaf(X))).
|
|
builtin_translation("float", "-", 0, [X, Y],
|
|
assign(Y, binary(float_minus, float_const(0.0), leaf(X)))).
|
|
|
|
builtin_translation("float", ">", 0, [X, Y],
|
|
test(binary(float_gt, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", "<", 0, [X, Y],
|
|
test(binary(float_lt, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", ">=", 0, [X, Y],
|
|
test(binary(float_ge, leaf(X), leaf(Y)))).
|
|
builtin_translation("float", "=<", 0, [X, Y],
|
|
test(binary(float_le, leaf(X), leaf(Y)))).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module builtin_ops.
|
|
%-----------------------------------------------------------------------------%
|