Difference between revisions of "Code Generation Optimization Ideas"

m
m (Simplifying the stack management)
Line 51: Line 51:
 
locs [1] = s;
 
locs [1] = s;
 
locs [2] = NULL;
 
locs [2] = NULL;
protect (locs );
+
protect (locs, 3);
  
 
i = locs [1].count;
 
i = locs [1].count;
Line 68: Line 68:
 
locs  [1] = NULL;
 
locs  [1] = NULL;
 
locs  [2] = NULL;
 
locs  [2] = NULL;
protect (locs );
+
protect (locs , 3);
  
 
i = args [1].count;
 
i = args [1].count;
Line 84: Line 84:
 
EIF_REFERENCE locs [1];
 
EIF_REFERENCE locs [1];
 
locs  [0] = NULL;
 
locs  [0] = NULL;
protect (locs );
+
protect (locs, 1);
 
 
 
i = args [1].count;
 
i = args [1].count;

Revision as of 09:20, 29 January 2008

Various ideas about potential improvements to code generation. Once an idea is implemented and is showing a real improvement it should be removed from this page and a new page should describe the mechanism in details with the available results.

Reducing GC hooks

Code generation should only rely on GC hooks when really needed. For example, currently the code:

f (s: STRING)
	local
		i: INTEGER
	do
		i := s.count
		g (s, i)
	end

would generate a hook for the Current object and s, but has the flow shows there is no need for it.

A more complicated case is the following one:

f (s: STRING)
	local
		i: INTEGER
	do
		i := s.count
		h (s, i)
		g (s, i)
	end

If the call to h is guaranteed to not generate any new objects, then it should be safe to not generate the hooks.

Simplifying the stack management

Currently all the hooks are generated one by one for the Current objects, the arguments, and the locals. The idea is to put all of those in one array/structure allocated on the stack. Then only one GC hook will be generated per routine needing the hooks. The other benefit is that because we allocate only one item at the time, we can simplify the code for handling this stack.

Drawback is that each argument and the Current object needs to be copied on routine entry. So for the Eiffel code:

f (s: STRING)
	local
		i: INTEGER
		l_s: STRING
	do
		i := s.count
		l_s := s.twin
		h (s, i)
		g (s, i)
	end

It looks like:

void f (EIF_REFERENCE Current, EIF_REFERENCE s) {
	EIF_INTEGER i;
	EIF_REFERENCE locs [3];
	locs [0] = Current;
	locs [1] = s;
	locs [2] = NULL;
	protect (locs, 3);
 
	i = locs [1].count;
	locs [2] = ANY_twin (locs [1]);
	h (locs [0], locs [1], i);
	g (locs [0], locs [1], i);
}

A solution to this is that all reference arguments are done via the locs array. Which would look like:

void f (EIF_REFERENCE args [2]) {
	EIF_INTEGER i;
	EIF_REFERENCE locs [3];
	locs  [0] = NULL;
	locs  [1] = NULL;
	locs  [2] = NULL;
	protect (locs , 3);
 
	i = args [1].count;
	locs [0] = ANY_twin (args [1]);
	locs [1] = args [0];
	locs [2] = args [1];
	h (&locs [1], i);
	g (&locs [1], i);
}

That is to say that part of the allocated array on the stack is used for the argument passing. The above could even be simplified to just:

void f (EIF_REFERENCE args [2]) {
	EIF_INTEGER i;
	EIF_REFERENCE locs [1];
	locs  [0] = NULL;
	protect (locs, 1);
 
	i = args [1].count;
	locs [0] = ANY_twin (args [1]);
	h (args, i);
	g (args, i);
}