Hello,
I noticed that on -current ECL, using the same OPTIMIZE
SPEED/SAFETY/DEBUG levels
(optimize (speed 3) (safety 1) (debug 1))
When using the LOOP macro with variables known to be FIXNUM, the
increment can be optimized inline using C + directly without further
checks. However, if using INCF or SETF/1+, an explicit call to
ecl_one_plus() is generated, even if the variable is known as a FIXNUM.
Initially, I thought that it was because the compiler could infer the
upper value the variable would reach (in which case it's a great
optimization), but I noticed that even on variables without an upper
bound (i.e. for i of-type fixnum from 0), inline + is also used.
So this made me wonder: is ecl_one_plus() used for safety at that
safety level (1) because of potential wrapping in the INCF/1+ case? If
so, shouldn't LOOP also use ecl_one_plus() at that same safety level?
At SAFETY 0 DEBUG 0 SPEED 3, both INCF and LOOP get inlined, yet the
SETF/1+ case still uses ecl_plus_one().
(Attached is example code and indented C results)
Thanks again,
--
Matt
(declaim (optimize (speed 3) (safety 1) (debug 1)))
(defun test1 ()
(loop
for i of-type fixnum from 0
do
(when (> 9 i)
(finish-loop))))
(defun test2 ()
(let ((i 0))
(declare (type fixnum i))
(loop
do
(when (> 9 i)
(finish-loop))
(incf i))))
(defun test3 ()
(let ((i 0))
(declare (type fixnum i))
(loop
do
(when (> 9 i)
(finish-loop))
(setf i (1+ i)))))
/* Compiler: ECL 10.7.1 */
/* Date: 2010/12/24 01:11 (yyyy/mm/dd) */
/* Machine: NetBSD 5.1 i386 */
/* Source: /tmp/test.lisp */
#include <ecl/ecl-cmp.h>
#include "test.h"
/* function definition for TEST1 */
/* optimize speed 3, debug 1, space 0, safety 1 */
static cl_object
L1test1()
{
VT2 VLEX2 CLSR2 STCK2
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
{
TTL:
{
cl_fixnum V1; /* I */
V1 = 0;
L3: ;
if (!((9) > (V1))) {
goto L6;
}
(void) ecl_function_dispatch(cl_env_copy, VV[4]) (0) /*
FINISH-LOOP */ ;
goto L4;
L6: ;
goto L4;
L4: ;
V1 = (V1) + 1;
goto L3;
}
}
}
/* function definition for TEST2 */
/* optimize speed 3, debug 1, space 0, safety 1 */
static cl_object
L2test2()
{
VT3 VLEX3 CLSR3 STCK3
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
{
TTL:
{
cl_fixnum V1; /* I */
V1 = 0;
L3: ;
if (!((9) > (V1))) {
goto L7;
}
(void) ecl_function_dispatch(cl_env_copy, VV[4]) (0) /*
FINISH-LOOP */ ;
goto L5;
L7: ;
goto L5;
L5: ;
V1 = ecl_to_fixnum(ecl_plus(MAKE_FIXNUM(V1),
MAKE_FIXNUM(1)));
goto L3;
}
}
}
/* function definition for TEST3 */
/* optimize speed 3, debug 1, space 0, safety 1 */
static cl_object
L3test3()
{
VT4 VLEX4 CLSR4 STCK4
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
{
TTL:
{
cl_fixnum V1; /* I */
V1 = 0;
L3: ;
if (!((9) > (V1))) {
goto L7;
}
(void) ecl_function_dispatch(cl_env_copy, VV[4]) (0) /*
FINISH-LOOP */ ;
goto L5;
L7: ;
goto L5;
L5: ;
{
cl_object V2;
V2 = ecl_one_plus(MAKE_FIXNUM(V1));
V1 = ecl_to_fixnum(V2);
}
goto L3;
}
}
}
#include "test.data"
#ifdef __cplusplus
extern "C"
#endif
ECL_DLLEXPORT void
init_fas_CODE(cl_object flag)
{
VT1 VLEX1 CLSR1 STCK1
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
cl_object *VVtemp;
if (!FIXNUMP(flag)) {
Cblock = flag;
#ifndef ECL_DYNAMIC_VV
flag->cblock.data = VV;
#endif
flag->cblock.data_size = VM;
flag->cblock.temp_data_size = VMtemp;
flag->cblock.data_text = compiler_data_text;
flag->cblock.data_text_size = compiler_data_text_size;
flag->cblock.cfuns_size = compiler_cfuns_size;
flag->cblock.cfuns = compiler_cfuns;
flag->cblock.source =
make_constant_base_string("/tmp/test.lisp");
return;
}
#ifdef ECL_DYNAMIC_VV
VV = Cblock->cblock.data;
#endif
Cblock->cblock.data_text = "@EcLtAg:init_fas_CODE@";
VVtemp = Cblock->cblock.temp_data;
{
cl_object V1;
cl_object V2;
V1 = Cnil;
V2 = VVtemp[0];
L6: ;
if (!(V2 == Cnil)) {
goto L10;
}
goto L7;
L10: ;
goto L8;
L8: ;
V1 = ECL_CONS_CAR(V2);
V2 = ECL_CONS_CDR(V2);
(void) ecl_function_dispatch(cl_env_copy, ECL_SYM("PROCLAIM",
664)) (1, V1);
goto L6;
L7: ;
goto L2;
}
L2: ;
ecl_cmp_defun(VV[3]);
ecl_cmp_defun(VV[5]);
ecl_cmp_defun(VV[6]);
}
(declaim (optimize (speed 3) (safety 0) (debug 0)))
(defun test1 ()
(loop
for i of-type fixnum from 0))
(defun test2 ()
(let ((i 0))
(declare (type fixnum i))
(loop
do
(incf i))))
(defun test3 ()
(let ((i 0))
(declare (type fixnum i))
(loop
do
(setf i (1+ i)))))
/* Compiler: ECL 10.7.1 */
/* Date: 2010/12/24 01:19 (yyyy/mm/dd) */
/* Machine: NetBSD 5.1 i386 */
/* Source: /tmp/test2.lisp */
#include <ecl/ecl-cmp.h>
#include "test2.h"
/* function definition for TEST1 */
/* optimize speed 3, debug 0, space 0, safety 0 */
static cl_object
L1test1()
{
VT2 VLEX2 CLSR2 STCK2
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
TTL:
{
cl_fixnum V1; /* I */
V1 = 0;
L3: ;
V1 = (V1) + 1;
goto L3;
}
}
/* function definition for TEST2 */
/* optimize speed 3, debug 0, space 0, safety 0 */
static cl_object
L2test2()
{
VT3 VLEX3 CLSR3 STCK3
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
TTL:
{
cl_fixnum V1; /* I */
V1 = 0;
L3: ;
V1 = (V1) + (1);
goto L3;
}
}
/* function definition for TEST3 */
/* optimize speed 3, debug 0, space 0, safety 0 */
static cl_object
L3test3()
{
VT4 VLEX4 CLSR4 STCK4
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
TTL:
{
cl_fixnum V1; /* I */
V1 = 0;
L3: ;
{
cl_object V2;
V2 = ecl_one_plus(MAKE_FIXNUM(V1));
V1 = fix(V2);
}
goto L3;
}
}
#include "test2.data"
#ifdef __cplusplus
extern "C"
#endif
ECL_DLLEXPORT void
init_fas_CODE(cl_object flag)
{
VT1 VLEX1 CLSR1 STCK1
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
cl_object *VVtemp;
if (!FIXNUMP(flag)) {
Cblock = flag;
#ifndef ECL_DYNAMIC_VV
flag->cblock.data = VV;
#endif
flag->cblock.data_size = VM;
flag->cblock.temp_data_size = VMtemp;
flag->cblock.data_text = compiler_data_text;
flag->cblock.data_text_size = compiler_data_text_size;
flag->cblock.cfuns_size = compiler_cfuns_size;
flag->cblock.cfuns = compiler_cfuns;
flag->cblock.source =
make_constant_base_string("/tmp/test2.lisp");
return;
}
#ifdef ECL_DYNAMIC_VV
VV = Cblock->cblock.data;
#endif
Cblock->cblock.data_text = "@EcLtAg:init_fas_CODE@";
VVtemp = Cblock->cblock.temp_data;
{
cl_object V1;
cl_object V2;
V1 = Cnil;
V2 = VVtemp[0];
L6: ;
if (!(V2 == Cnil)) {
goto L10;
}
goto L7;
L10: ;
goto L8;
L8: ;
V1 = ECL_CONS_CAR(V2);
V2 = ECL_CONS_CDR(V2);
(void) ecl_function_dispatch(cl_env_copy, ECL_SYM("PROCLAIM",
664)) (1, V1);
goto L6;
L7: ;
goto L2;
}
L2: ;
ecl_cmp_defun(VV[3]);
ecl_cmp_defun(VV[4]);
ecl_cmp_defun(VV[5]);
}
------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and,
should the need arise, upgrade to a full multi-node Oracle RAC database
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Ecls-list mailing list
Ecls-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ecls-list