mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 10:23:46 +00:00
tests/accumulator/*.m:
tests/analysis_*/*.m:
tests/benchmarks*/*.m:
tests/debugger*/*.{m,exp,inp}:
tests/declarative_debugger*/*.{m,exp,inp}:
tests/dppd*/*.m:
tests/exceptions*/*.m:
tests/general*/*.m:
tests/grade_subdirs*/*.m:
tests/hard_coded*/*.m:
Make these tests use four-space indentation, and ensure that
each module is imported on its own line. (I intend to use the latter
to figure out which subdirectories' tests can be executed in parallel.)
These changes usually move code to different lines. For the debugger tests,
specify the new line numbers in .inp files and expect them in .exp files.
178 lines
4.7 KiB
Mathematica
178 lines
4.7 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ts=4 sw=4 et ft=mercury
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% This module tests the loop invariant hoisting optimization.
|
|
% It does so using foreign_procs which abort if called twice:
|
|
% if loop invariant hoisting works, these procedures will only
|
|
% be called once, but if loop invariant hoisting doesn't work,
|
|
% these procedures will abort.
|
|
|
|
% This test checks that we do the basics of loop invariant hoisting.
|
|
|
|
:- module loop_inv_test.
|
|
:- interface.
|
|
:- import_module io.
|
|
|
|
:- pred main(io::di, io::uo) is det.
|
|
|
|
:- implementation.
|
|
:- import_module int.
|
|
:- import_module string.
|
|
|
|
main -->
|
|
io__print("enter three integers, one on each line\n"), io__flush_output,
|
|
io__read_line_as_string(Res1),
|
|
io__read_line_as_string(Res2),
|
|
io__read_line_as_string(Res3),
|
|
( { Res1 = ok(L1), Res2 = ok(L2), Res3 = ok(L3) } ->
|
|
{ N1 = string__det_to_int(string__chomp(L1)) },
|
|
{ N2 = string__det_to_int(string__chomp(L2)) },
|
|
{ N3 = string__det_to_int(string__chomp(L3)) },
|
|
{ loop1(N1, N2, N3, R1) },
|
|
{ loop2(N1, N2, N3, R2) },
|
|
io__print("R1 = "), io__print(R1), io__nl,
|
|
io__print("R2 = "), io__print(R2), io__nl
|
|
;
|
|
io__print("input error"), io__nl
|
|
).
|
|
|
|
% Test that we can do ordinary loop hoisting:
|
|
% p/1 will abort if called twice.
|
|
%
|
|
:- pred loop1(int::in, int::in, int::in, int::out) is det.
|
|
|
|
loop1(N, Inv, Acc0, Acc) :-
|
|
( N =< 0 ->
|
|
Acc = Acc0
|
|
;
|
|
p(Inv, X),
|
|
Acc1 = Acc0 + X,
|
|
loop1(N - 1, Inv, Acc1, Acc)
|
|
).
|
|
|
|
% Test that we can do ordinary loop hoisting, in the case
|
|
% where the invariant predicate is an inlined foreign_proc
|
|
% q/1 will abort if called twice.
|
|
%
|
|
:- pred loop2(int::in, int::in, int::in, int::out) is det.
|
|
|
|
loop2(N, Inv, Acc0, Acc) :-
|
|
( N =< 0 ->
|
|
Acc = Acc0
|
|
;
|
|
q(Inv, X),
|
|
Acc1 = Acc0 + X,
|
|
loop2(N - 1, Inv, Acc1, Acc)
|
|
).
|
|
|
|
:- pragma no_inline(p/2).
|
|
:- pragma inline(q/2).
|
|
|
|
:- pred p(int::in, int::out) is det.
|
|
:- pragma foreign_proc("C",
|
|
p(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
/* Test that p/1 only gets called once. */
|
|
static int num_calls = 0;
|
|
if (num_calls++) {
|
|
MR_fatal_error(""p/1 called more than once"");
|
|
abort();
|
|
}
|
|
|
|
X = Inv + 42;
|
|
").
|
|
:- pragma foreign_code("C#", "static int p_num_calls = 0;").
|
|
:- pragma foreign_proc("C#",
|
|
p(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
/* Test that p/1 only gets called once. */
|
|
if (p_num_calls++ > 0) {
|
|
mercury.runtime.Errors.fatal_error(""p/1 called more than once"");
|
|
}
|
|
|
|
X = Inv + 42;
|
|
").
|
|
:- pragma foreign_code("Java", "static int p_num_calls = 0;").
|
|
:- pragma foreign_proc("Java",
|
|
p(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
/* Test that p/1 only gets called once. */
|
|
if (p_num_calls++ > 0) {
|
|
throw new Error(""p/1 called more than once"");
|
|
}
|
|
|
|
X = Inv + 42;
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
p(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
% Test that p/1 only gets called once.
|
|
case get(p_called) of
|
|
undefined ->
|
|
put(p_called, true);
|
|
_ ->
|
|
throw(""p/1 called more than once"")
|
|
end,
|
|
|
|
X = Inv + 42
|
|
").
|
|
|
|
:- pred q(int::in, int::out) is det.
|
|
:- pragma foreign_proc("C",
|
|
q(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
/* Test that q/1 only gets called once. */
|
|
static int num_calls = 0;
|
|
if (num_calls++) {
|
|
MR_fatal_error(""q/1 called more than once"");
|
|
}
|
|
|
|
X = Inv + 53;
|
|
").
|
|
:- pragma foreign_code("C#", "static int q_num_calls = 0;").
|
|
:- pragma foreign_proc("C#",
|
|
q(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
/* Test that q/1 only gets called once. */
|
|
if (q_num_calls++ > 0) {
|
|
mercury.runtime.Errors.fatal_error(""q/1 called more than once"");
|
|
}
|
|
|
|
X = Inv + 53;
|
|
").
|
|
:- pragma foreign_code("Java", "static int q_num_calls = 0;").
|
|
:- pragma foreign_proc("Java",
|
|
q(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
/* Test that q/1 only gets called once. */
|
|
if (q_num_calls++ > 0) {
|
|
throw new Error(""q/1 called more than once"");
|
|
}
|
|
|
|
X = Inv + 53;
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
q(Inv::in, X::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
% Test that q/1 only gets called once.
|
|
case get(q_called) of
|
|
undefined ->
|
|
put(q_called, true);
|
|
_ ->
|
|
throw(""q/1 called more than once"")
|
|
end,
|
|
|
|
X = Inv + 53
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|