<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Transforming Low-Level Variants of Greatest Com mon Divisor Algorithm: A Case Study</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Doni Pracner</string-name>
          <email>doni.pracner@dmi.uns.ac.rs</email>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
          <xref ref-type="aff" rid="aff2">2</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Nataša Sukur</string-name>
          <email>natasa.sukur@dmi.uns.ac.rs</email>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
          <xref ref-type="aff" rid="aff2">2</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>21000 Novi Sad</institution>
          ,
          <country country="RS">Serbia</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Automated Maintenance</institution>
          ,
          <addr-line>Hill Climbing, Fitness Function</addr-line>
          ,
          <country>Greatest Common Divisor</country>
        </aff>
        <aff id="aff2">
          <label>2</label>
          <institution>University of Novi Sad, Faculty of Sciences, Department of Mathematics and Informatics</institution>
          ,
          <addr-line>Trg Dositeja Obradovića 4</addr-line>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2022</year>
      </pub-date>
      <abstract>
        <p>transformations. A large portion of maintenance efort is spent in understanding the logic of the original code. Our research presents an option to automatically transform a low-level program into a semantically equivalent version with high-level structures. Making the code more understandable with high-level structures can lead to faster and easier maintenance. This paper presents a case study on several implementations of the greatest common divisor in two low-level languages (assembly and MicroJava bytecode) and their SQAMIA 2022: Workshop on Software Quality, Analysis, Monitoring, Improvement, and Applications, September 11-14, ∗Corresponding author.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Introduction</title>
      <p>One of the most significant properties of software is its need to change due to new requirements
or changes of the environment. By constantly changing a software product, the need for
maintenance becomes more and more important, but at the same time more and more challenging.
However, the maintainers are often left with low-level code or binaries as the only source of
information about the program. Trying to understand the code and maintain it according to the
needs can be a very costly process in the sense of necessary time and efort. This process often
also relies on the experience and skills of the maintainer, which opens possibilities for additional
errors. New developers are generally only trained in high-level languages, emphasising the
problem. One solution for this is automation of the entire process by using helper tools which
would make the original software more readable without causing new faults (of course given
that the tools themselves are not faulty).</p>
      <p>
        The research presented in this paper is based on FermaT transformation system and WSL
(Wide Spectrum Language) [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], strongly based around the idea of software maintenance. In this
paper, translation and semantics preserving transformations are applied to the input low-level
code in an automated manner. The goal of this automated process in general is to derive higher
level structures from the low-level code.
https://perun.pmf.uns.ac.rs/pracner/ (D. Pracner)
      </p>
      <p>© 2022 Copyright for this paper by its authors. Use permitted under Creative Commons License Attribution 4.0 International (CC BY 4.0).
CEUR</p>
      <p>This paper presents a case study on several implementations of the Euclidean algorithm
(greatest common divisor), both in MicroJava bytecode and assembly. Being one of the first
algorithms, it seems suitable to be one of the initial case studies of this research. The same
automated transformation process has been applied to each of these samples and the results of
the experiments have been presented.</p>
      <p>The rest of the paper is organised as follows: Section 2 presents the case study of this paper,
the greatest common divisor algorithm; in Section 3 the foundations of this work and the
automated transformation process are explained; in Section 4 the related work is presented;
Section 5 introduces the experiments and the results of this research and finally, in Section 6 we
present the conclusions and the future work based on the observations made on current results.</p>
    </sec>
    <sec id="sec-2">
      <title>2. Greatest Common Divisor Algorithm</title>
      <p>
        The greatest common divisor algorithm (further referred to as GCD), or Euclidean algorithm is
considered to be one of the oldest nontrivial algorithms recorded. Its first written occurrence
was in Euclid’s Elements and it explains the calculation of the greatest common divisor of two
numbers [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ][
        <xref ref-type="bibr" rid="ref3">3</xref>
        ].
      </p>
      <p>
        The easiest and most natural approach to finding the GCD of two numbers would be to factor
both numbers and then multiply the common factors, raised to according powers. However, this
is far from the most eficient way of calculating the GCD and the Euclidean algorithm solves it
in a more eficient manner [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ].
      </p>
      <p>The original Euclidean algorithm is based on continuous subtraction. If A and B are two
positive integers, their greatest common divisor can be found by continuously subtracting
smaller from the larger value until they are equal. After the process is finished, any of the two
numbers can be returned as the result.</p>
      <p>The algorithm can also be represented as repeated calculation of the remainder of one number
divided by another. The result is reached once the remainder is 0, and the repeated subtraction
of the original algorithm can simply be replaced by remainder calculation in this improved
version.</p>
    </sec>
    <sec id="sec-3">
      <title>3. Automated Transformations</title>
      <p>
        Current demands for software development are that it is delivered in the shortest time possible,
yet still with high level of quality and reliability. In order to preserve the reliability of the
software product, it is important to find means which would assure reliability throughout
diferent stages of the development process. As a solution to this problem, formal methods can
be used. Formal methods can be very useful for the overall reliability of software, since they can
be applied in diferent stages of software development and to diferent software artefacts [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ].
      </p>
      <p>
        WSL is a language used for reverse engineering of sequential systems [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ]. It is based on formal
methods and together with FermaT program transformation system, it makes a platform for
successful reverse and forward engineering. The idea of program transformations is some sort
of cost reduction, for example in terms of performance, memory usage or portability. FermaT’s
main feature is the support for transformations which are formal and semantics preserving [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ].
      </p>
      <p>WSL stands for Wide Spectrum Language, which describes its wide usage from abstract
specifications to concrete runnable implementations. Apart from standard language constructs,
WSL has another important extension, MetaWSL, used for writing code transformations in
the language itself. Transformations are included in the system and their correctness can be
automatically checked. Transformations can be of great use in processes such as creating
programs from specifications, analysing programs and their properties or getting specifications
from reverse engineering of programs.</p>
      <p>Action systems are a special structure in WSL. It was designed to be able to emulate jumps
and goto statements that are common to low-level programs. It consists of a collection of
parameter-less procedures. One of them is marked as the start procedure and they can call each
other with no limits. Once a procedure is finished, the control is returned to the call site. The
only exception to this is the reserved name Z, a call to which immediately ends the execution of
the whole action system. There can be multiple action systems in a program, and the flow of
the program normally continues with the next statement when an action system terminates.
There are three types of systems in relation to how the calls are used. The first one are recursive
action systems, in which all of the calls return, and the system is terminated when the starting
action terminates. The second one are the regular action systems in which the system is always
terminated by a call to Z and none of the calls return to their sites. This type is important for
many transformations, since this special property can be used for simplifications. The third
type are the hybrid ones, which are a mix of the previous two, or, in other words, any that don’t
fall into the previous categories.</p>
      <p>
        Two tools were developed by the authors for translation of the original low-level code to
WSL – asm2wsl, which translates a subset of x86 assembly in the MASM/TASM dialect [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] and
mjc2wsl, which translates MicroJava bytecode [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ]. Both of these tools replicate the operational
semantics of the original processor/virtual machine. This is achieved through a set of additional
variables that represent the state of the machine, such as registers, flags and stacks. The first
tool is a bit limited when it comes to the span of assembly programs it can handle. For instance
there is an assumption that only labels are jump targets. It also recognises some special macro
names for inputs and outputs, instead of dealing with interrupts directly. The WSL translation
consists of a regular action system in which actions mostly start where the labels were, and
the final statement is a call to Z. On the other hand, mjc2wsl translates practically any valid
program for the MicroJava virtual machine. It generates a recursive action system, in which
every original operation has an action associated with its address. This enables more flexible
jumps.
      </p>
      <p>
        Transformations can be applied manually, by relying on one’s experience and expertise or
automatically, by using an existing helper tool [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ]. This tool automates the process, starting
from the translated original low-level code and resulting in higher level code, improved in terms
of its structure and understandability. This automation tool is based around the hill climbing
algorithm.
      </p>
      <p>
        Hill climbing [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ] is a search algorithm. It gets its name due to its approach and logic – it
tries to move in the direction of increasing value, that is, towards better solutions. That is
accomplished by starting from an arbitrary solution and making changes to it in order to reach
a better one. This way, the process constantly moves “uphill”, with the best solution being
the hilltop. Finding the best solution means that no immediate neighbour has a better value.
This also means that the algorithm has an implicit problem of ending up in local optimums. In
this use case, the algorithm tries to apply transformations to a program and if the program is
improved based on some criteria, it is kept as a base for further transformation. The process
applies transformations to the code as long as they are leading to better programs. The end of
the process means that the “best” program has been reached and that application of additional
transformations will not result in a better one.
      </p>
      <p>
        After a transformation has been applied in the hill climbing process, the quality of the
potential solution is measured by a fitness function . The term draws its origin from evolutionary
computing. Generally speaking, the role of a fitness function is to define qualities which should
be met by a population. It defines the criteria for selection, which also means that it defines the
meaning of improvement. In terms of problem-solving, it represents the task which is solved in
evolutionary manner [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ].
      </p>
      <p>
        The fitness function indicates if the newly created solution shows an improvement, which
from the computing point of view means that it has better qualities for solving the problem at
hand. For this purpose, a simpler and more understandable program is the better one. Since the
iftness function represents the quality of a program as numeric values, the first choice are various
metric values. These metrics can be good indicators whether a solution is better structured
and therefore more understandable. In our previous work [
        <xref ref-type="bibr" rid="ref12">12</xref>
        ], it was shown that selecting
diferent fitness functions on the same input programs leads to diferent end results. One of the
important observations of this work was that the the best results were not accomplished by a
single fitness function across all input programs. Based on that, the conclusion was that the
selection of the fitness function should probably vary based on the properties of the samples.
The experiments were run with structure metric by default, which is a custom weighted metric
for WSL, but diferent fitness functions were also used.
      </p>
      <p>Both of the translation tools, as well as the transformation program are available under the
terms of the GNU Public Licence on the project site1.</p>
    </sec>
    <sec id="sec-4">
      <title>4. Related Work</title>
      <p>
        Although using hill climbing and fitness functions for automated reengineering is not so
widespread, there have been some tools and papers which share some of the ideas and objectives.
Hill climbing has not been frequently used for automatic program repair, however this approach
has been considered by Arcuri and Yao in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ]. There has not been a lot of confidence in this
idea, since the algorithm shows tendency to gravitate towards local optimums. Hill climbing
was also compared to diferent approaches for solving similar problems and as a result, genetic
algorithms showed as better [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ]. However, this approach is diferent than the one described
in this paper, since the order of transformations was being optimised in search for a better
solution.
      </p>
      <p>
        Fitness functions have shown as useful in automated software repair for C programs [
        <xref ref-type="bibr" rid="ref15">15</xref>
        ] as
well as assembly [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ]. Later on, that research resulted with the possibility to be applied to any
kind of code [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ]. There has also been research which further confirms our hypothesis that the
selection of the fitness function should vary based on the problem which it solves. The topic of
that research is automated bug detection [
        <xref ref-type="bibr" rid="ref18 ref19">18, 19</xref>
        ] and tries to give guidance how to create them
and get the best results.
      </p>
      <p>
        FermaT has previously been successfully used in several industrial projects, where the original
assembly code was transformed to C and COBOL code. However, this process was significantly
adapted to the specific problems it was solving, unlike the hill climbing process which is always
the same and fully automated [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ].
      </p>
    </sec>
    <sec id="sec-5">
      <title>5. Transforming GCD Programs</title>
      <sec id="sec-5-1">
        <title>5.1. Manual Application of Transformations</title>
        <p>Using FermaT (possibly with a helper tool like FME), an experienced maintainer can raise the
level of abstraction of low-level code. An example can be a direct implementation of subtracting
the smaller number from the larger until they are the same in assembly, shown in Figure 1.
It features macros with specific names that get recognised by the translator, as mentioned
before. When this code is translated into WSL using asm2wsl it will expand into about 50
statements, which is an expected increase. A rather optimal path could be to apply the following
transformations: Remove Redundant Vars, Flag Removal, Collapse Action System, Floop to while,
Constant Propagation. The end result is a very clear implementation of Euclid’s algorithm in
only 5 statements, shown in Figure 2. Note that the pretty printer for WSL is not in a C-like
style, but leans much more toward a LISP-like indention, where the closing of a branching or a
loop will be at the end of the block, on the same line, not in a new line on the same level as the
opening.</p>
        <p>start:
mov
mov
compare:
cmp
je
ja
sub
jmp
greater:
sub
jmp
ax,12
bx,8
ax,bx
exit ;exit since they’re equal
greater
bx,ax
compare
ax,bx
compare
exit:
;exit out of the program
print_num ax
end_execution</p>
        <p>Of course, since this is a program with hard coded starting values, the result is also always
the same. Further simplification if possible by using Unroll loop and Constant propagation
transformations repeatedly to just assign the final value 4 to ax and bx, and then even further
into a simple PRINFLUSH(4).</p>
        <p>Reaching this optimal path requires a lot of expertise from the maintainer and although very
VAR &lt; ax := 12, bx := 8 &gt;:
WHILE ax &lt;&gt; bx DO</p>
        <p>IF ax &gt;= bx THEN ax := ax - bx ELSE bx := bx - ax FI
OD;</p>
        <p>PRINFLUSH(ax) ENDVAR
good final results could be achieved by manual selection and application of transformations, it is
usually a much better option to use automated tools for these kinds of activities. Although the
automated process might not reach the best solution using the same path as an expert would,
the manual approach is in general less eficient by far in terms of the cost of the process.</p>
      </sec>
      <sec id="sec-5-2">
        <title>5.2. Automated Transformation Selection</title>
        <p>There are several variants of the algorithm implementation that were used in these experiments.
Some are written in assembly, and some in MicroJava and then compiled into bytecode. Many
of these programs come in pairs, a variant with predefined values (i.e., hard coded) and a variant
with user input for ax and bx. These are then usually marked with sufixes predef and input,
respectively.</p>
        <p>The first variant that will be presented is the one that was already discussed for a manual
approach to transformations (Figure 1). The hill climbing process will automatically transform
the program into the same version as already shown in Figure 2. It will do so by automatically
ifnding and applying 27 transformations. This is a lot more than with the manual approach, but
those were hand picked and targeted very precisely, and some of them are very complex, while
here there is a lot of smaller and cheaper transformations for the same end result. During the
process about 2300 transformations are tried, which took less than half a second on a 3GHz
Intel processor.</p>
        <p>
          The process that ran with the default structure metric as the fitness function did not simplify
the program further into a simple print, which was shown in the manual transformation example.
This is due to the fact that unrolling the loop increases the metric of the new program, and
it is therefore discarded by the process. In this case it would be required to look ahead 4
transformations to achieve an improvement of the fitness of the program. The problem, of
course, is that in a general case it is undecidable to know how many steps are required, or
indeed if there is a finite number of steps that would lead to an improvement, since this is a
variation of the halting problem [
          <xref ref-type="bibr" rid="ref20">20</xref>
          ].
        </p>
        <p>Another variant of this program is with user inputs, instead of hard coded values. Macros
are used for input operations, to avoid the specifics of interupts. The increase in the number
of statements in the translated program is about ten. The transformed version of the program
with inputs is shown in Figure 3. There are somewhat verbose parts that load the user input,
but the core part of the algorithm is exactly the same as in the predef version. The process
selected 34 transformations to achieve this version, which is inline with the slight increase of
statements. On the other hand it tried almost 6000 transformations for this program, which is a
significant increase. The time elapsed also doubled to about a second. However, this is natural
for the process since it has a lot more statements to try transformations on.</p>
        <p>PRINFLUSH(”num?$”);
VAR &lt; ax := 0, bx := 0, t_e_m_p := 0 &gt;:
@Read_Line_Proc( VAR t_e_m_p, Standard_Input_Port);
bx := @String_To_Num(t_e_m_p);
PRINT(””);
PRINFLUSH(”num?$”);
@Read_Line_Proc( VAR t_e_m_p, Standard_Input_Port);
PRINT(””);
ax := @String_To_Num(t_e_m_p);
WHILE ax &lt;&gt; bx DO</p>
        <p>IF ax &gt; bx THEN ax := ax - bx ELSE bx := bx - ax FI
OD;
PRINFLUSH(&lt;”res,$”&gt;);</p>
        <p>PRINFLUSH(ax) ENDVAR</p>
        <p>The next experiment was to wrap the algorithm into a procedure, with a single call to it with
predefined values. During the process the procedure gets inlined into the main program, the
end result was the same as with gcd-predef. The increase in the number of transformations was
low for this variant.</p>
        <p>Another variant is a recursive one, with a procedure that will keep subtracting the smaller
from the larger number and call itself until the numbers are the same. A diference to the version
seen in gcd-predef is that this variant always ensures that ax is the larger number by swapping
them when needed, which means that it always subtracts bx from ax. When this version is
automatically transformed, the recursion is reduced to a while loop, as shown in Figure 4. WSL
has a simultaneous assignment environment that can be seen in the Figure. Again, as with the
previous examples, both the predef and input versions get transformed to the same core loop,
and, again, the number of transformations tried with the second version is more than double.</p>
        <p>WHILE ax &lt;&gt; bx DO</p>
        <p>IF ax &lt;= bx</p>
        <p>THEN &lt; ax := bx, bx := ax &gt; FI;
ax := ax - bx OD;</p>
        <p>There are also several versions of the algorithm implemented in MicroJava, again with pairs
of predefined values and user inputs.</p>
        <p>One version is the same as seen in assembly – a while loop with subtraction of the smaller
number from the larger number. This high-level code is then compiled into bytecode, which is
translated into WSL. Unlike asm2wsl which created regular action systems, mjc2wsl creates
recursive action systems, in which every call returns. It is then transformed with the same hill
climbing program. The automatically transformed version (Figure 5) is again a very clear
highlevel loop at the core part of the program, although it does leave a few additional stack operations.
The names of the local variables are not encoded in the compiled files, so they get automated
sequential names. These can mostly be simplified with additional manual transformations. The
main reason they are left in the program is that sometimes the introduction of a VAR block can
be a greater increase in the metrics than the removal of the stack operations.</p>
        <p>Another version is the same as this one, just contained in a procedure. It gets transformed to
the same core code as in Figure 5.</p>
        <p>WHILE mjvm_locals_0 &lt;&gt; mjvm_locals_1 DO</p>
        <p>IF mjvm_locals_0 &gt; mjvm_locals_1</p>
        <p>THEN mjvm_locals_0 := mjvm_locals_0 - mjvm_locals_1 FI;
IF mjvm_locals_0 &lt; mjvm_locals_1</p>
        <p>THEN mjvm_locals_1 := mjvm_locals_1 - mjvm_locals_0 FI</p>
        <p>OD;</p>
        <p>The alternative version of this program, with predefined inputs, can actually be transformed
into a single PRINFLUSH statement – that is the end result is correctly deduced in the process.
This is dependant on the starting predefined values. The current implementation of the process
is able to unroll the loop if there was only one pass through it, for instance for the starting
values of 12 and 8. Already for two passes the metrics do not drop after an unroll, for instance
for 20 and 8, and the result will be the same core code as with the input version.</p>
        <p>This is diferent to the assembler programs since the implementation used two IF branches,
instead of the IF/ELSE that is inherent to the assembly version. This diference is enough for
the metrics to change when the loop is unrolled. An additional MicroJava program with this
other type of branching was tested, and it didn’t get fully simplified either. It is arguable which
of these is “better” high-level code; the first one is clear that there is no middle option and is
explicit about what it does, like a specification should be. The other one is more optimal in
execution since it will not do an additional check.</p>
        <p>Next is a recursive version, shown in Figure 6, where the values are swapped if needed to
ensure a is larger than b. This is the same logic as the recursive assembly program. However,
unlike that version, which was transformed into a WHILE loop (Figure 7), here the process
resulted in a diferent implementation of the same algorithm, with two recursive calls in which
the parameters get subtracted as needed. It was not transformed into a function with a return
value, since the process removed the in between stack operations and the result is only once
put on the stack and only taken from the stack in the main program.</p>
        <p>Other recursive version of the algorithm were also tried. Sadly, they do not get properly
transformed to fully high level code. One problem is that the procedure does not get recognised
as having two parameters, only one of them is transformed, while the other is still passed
through the stack. We believe this is due to the intertwined stack operations that are sometimes
prematurely optimised in the process and are then hard to fit into the expected patterns. It is
int gcd(int a, int b)
int t;
{
}
}
void main()
{
if (a == b)</p>
        <p>return a;
if (a&lt;b) {
t = a;
a = b;
b = t;
}
return gcd(a-b,b);
print(gcd(8,12),3);
somewhat ironic that among these is a MicroJava implementation that is almost the same as
the successful transformation shown in Figure 7.</p>
      </sec>
      <sec id="sec-5-3">
        <title>5.3. Properties of The Process</title>
        <p>Assembly programs get translated to more than 2 times longer WSL programs; the transformed
high-level versions are more than 3 times shorter on average, on these samples. It should also be
noted that this is with assembly programs that have the macro definitions and bodies removed.
If those were included, that ratio of improvement would be even higher.</p>
        <p>MicroJava gets compiled to about 2.5 times more statements, each of which then get translated
to around 4 WSL statements. After the transformations the number of statements is mostly in
line with the original high-level programs, or in other words it is capable of obtaining the same
level of structures.</p>
        <p>
          The length of the process in general rises with the length of the input program, but the
correlation is not a direct one. There are exceptions both ways – some significantly longer
programs can get transformed in the same time, and sometimes short programs will take a long
time to process. Transformations with better end results are often achieved in less time. In
general, if a program is successfully transformed and simplified there are less places to test
future transformations on [
          <xref ref-type="bibr" rid="ref12 ref21">21, 12</xref>
          ], thus finishing faster.
        </p>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>6. Conclusions</title>
      <p>One of the most important tasks in software maintenance is the understanding of the program
at hand. This can especially be hard with low-level implementations. In this paper an approach
to automated restructuring into a high-level version of the same program is presented. It relies
on FermaT transformation system and WSL language, and its support for semantics preserving
transformations. Two tools are in charge of translation of the low-level code to WSL, asm2wsl
and mjc2wsl. The process is fully automated and is based around a hill climbing algorithm
which advances towards the best solution with a fitness function as the measure of quality. All
the tools are open source and available under the GNU Public Licence. The presented process
consists of several steps and independent tools. It can be applied to a number of diferent
maintenance tasks. Since the process is flexible it can be easily adapted or integrated into other
processes.</p>
      <p>The focus of this paper is a case study of several implementations in two diferent languages
of the oldest written algorithm, greatest common divisor. Several versions got automatically
transformed into practically the same high-level code. Even though some of these versions
used loops and some used recursive procedures, some were regular action systems, and some
recursive, and that the programs that translate them have other diferences as well, they all get
transformed with the same hill climbing program.</p>
      <p>A notable transformation was made, in which one implementation of the algorithm got
automatically transformed into another. The starting version was a MicroJava recursive
implementation that swaps the values of the parameters when needed. The result was an implementation
that has two calls and changes which parameters are passed into them (Figure 7).</p>
      <p>On the other hand, some other recursive versions of MicroJava programs were not as much
of a success. They do get transformed into a higher level and are easier to understand but there
are still some low-level stack operations that remained. A maintainer who is somewhat familiar
with the concepts of virtual machines that rely on stacks should be able to fully understand
these.</p>
      <p>Of course, there is a lot of space for expanding this work. More in-depth studies of diferent
algorithms could reveal more about the properties of this process and how it can be improved.
For instance more efort could be put into improving the transformations of stack operation to
parameters and return values to recognise some of the already optimised versions. The order
of the transformations could also be changed to check the possibilities of obtaining better end
results.</p>
      <p>
        In general, a big question is how to formulate a fitness function that will be as universal as
possible to define a program as being more understandable. In our experiments, on diferent
inputs, diferent functions would give better results. Since this is an optimisation problem, the
“no free lunch” theorem [
        <xref ref-type="bibr" rid="ref22">22</xref>
        ] is applicable – for the set of all possible input programs, there
are always examples for which a fitness function would give worse results. On the other hand,
there are some common properties of the input programs that were translated from low-level
sources, so there is hope to at least find good candidates. A lot of what was learned from this can
be invested into further experiments in combining the functions, or even combining multiple
processes.
      </p>
      <p>One of the known issues of the hill climbing algorithm is the tendency towards local optimums.
This can be somewhat countered with starts from multiple random points and picking the best
results from all the runs. Another option that is considered for future processes is to use a
diferent searching algorithm.</p>
    </sec>
    <sec id="sec-7">
      <title>Acknowledgments</title>
      <p>The authors acknowledge financial support of the Ministry of Education, Science and
Technological Development of the Republic of Serbia (Grant No. 451-03-68/2022-14/200125).</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>M.</given-names>
            <surname>Ward</surname>
          </string-name>
          ,
          <article-title>Assembler restructuring in fermat</article-title>
          , in: SCAM, IEEE,
          <year>2013</year>
          , pp.
          <fpage>147</fpage>
          -
          <lpage>156</lpage>
          . doi:http: //dx.doi.org/10.1109/SCAM.
          <year>2013</year>
          .
          <volume>6648196</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <surname>Euclid</surname>
          </string-name>
          , Elements,
          <string-name>
            <surname>Book</surname>
            <given-names>VII</given-names>
          </string-name>
          , -,
          <source>300 BC.</source>
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>D. E.</given-names>
            <surname>Knuth</surname>
          </string-name>
          ,
          <source>The Art of Computer Programming</source>
          , Volume
          <volume>2</volume>
          (3rd Ed.): Seminumerical Algorithms,
          <string-name>
            <surname>Addison-Wesley Longman</surname>
          </string-name>
          Publishing Co., Inc., Boston, MA, USA,
          <year>1997</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>H.</given-names>
            <surname>Cohen</surname>
          </string-name>
          ,
          <string-name>
            <surname>A Course</surname>
          </string-name>
          <source>in Computational Algebraic Number Theory</source>
          , Springer-Verlag, Berlin, Heidelberg,
          <year>1993</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>M.</given-names>
            <surname>Roggenbach</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Cerone</surname>
          </string-name>
          ,
          <string-name>
            <given-names>B.-H.</given-names>
            <surname>Schlinglof</surname>
          </string-name>
          ,
          <string-name>
            <given-names>G.</given-names>
            <surname>Schneider</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S. A.</given-names>
            <surname>Shaikh</surname>
          </string-name>
          ,
          <source>Formal Methods for Software Engineering: Languages, Methods, Application Domains, Texts in Theoretical Computer Science. An EATCS Series</source>
          , Springer Cham,
          <year>2022</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>M.</given-names>
            <surname>Ward</surname>
          </string-name>
          ,
          <source>Proving Program Refinements and Transformations, Ph.D. thesis</source>
          , Oxford University,
          <year>1989</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>D.</given-names>
            <surname>Pracner</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Z.</given-names>
            <surname>Budimac</surname>
          </string-name>
          ,
          <article-title>Restructuring assembly code using formal transformations</article-title>
          , in: T. E. Simos (Ed.),
          <source>Proc. of Symposium on Computer Languages, Implementations and Tools (SCLIT</source>
          <year>2011</year>
          )
          <article-title>held within ICNAAM 2011</article-title>
          , volume
          <volume>1389</volume>
          <source>of AIP proceedings</source>
          ,
          <year>2011</year>
          , pp.
          <fpage>845</fpage>
          -
          <lpage>848</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>D.</given-names>
            <surname>Pracner</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Z.</given-names>
            <surname>Budimac</surname>
          </string-name>
          ,
          <article-title>Transforming low-level languages using FermaT and WSL</article-title>
          , in: Z.
          <string-name>
            <surname>Budimac</surname>
          </string-name>
          (Ed.),
          <source>Proceedings of the 2nd Workshop on Software Quality Analysis, Monitoring, Improvement, and Applications</source>
          , volume
          <volume>1053</volume>
          <source>of CEUR-WS.org</source>
          ,
          <year>2013</year>
          , pp.
          <fpage>71</fpage>
          -
          <lpage>78</lpage>
          . URL: http://ceur-ws.
          <source>org/</source>
          Vol-
          <volume>1053</volume>
          /.
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>D.</given-names>
            <surname>Pracner</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Z.</given-names>
            <surname>Budimac</surname>
          </string-name>
          ,
          <article-title>Enabling code transformations with FermaT on simplified bytecode</article-title>
          ,
          <source>Journal of Software: Evolution and Process</source>
          <volume>29</volume>
          (
          <year>2017</year>
          )
          <article-title>e1857-n/a</article-title>
          . URL: http://dx.doi.org/10. 1002/smr.
          <year>1857</year>
          . doi:
          <volume>10</volume>
          .1002/smr.
          <year>1857</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>S. J.</given-names>
            <surname>Russell</surname>
          </string-name>
          ,
          <string-name>
            <given-names>P.</given-names>
            <surname>Norvig</surname>
          </string-name>
          ,
          <article-title>Artificial intelligence: a modern approach</article-title>
          , Malaysia; Pearson Education Limited„
          <year>2016</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <given-names>A. E.</given-names>
            <surname>Eiben</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J. E.</given-names>
            <surname>Smith</surname>
          </string-name>
          , et al.,
          <article-title>Introduction to evolutionary computing</article-title>
          , volume
          <volume>53</volume>
          , Springer,
          <year>2003</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <given-names>N.</given-names>
            <surname>Sukur</surname>
          </string-name>
          ,
          <string-name>
            <given-names>D.</given-names>
            <surname>Pracner</surname>
          </string-name>
          ,
          <article-title>Evaluating fitness functions for automated code transformations</article-title>
          , in: Z.
          <string-name>
            <surname>Budimac</surname>
          </string-name>
          (Ed.),
          <source>SQAMIA</source>
          <year>2018</year>
          , 7th Workshop of Software Quality, Analysis, Monitoring, Improvement, and
          <string-name>
            <surname>Applications</surname>
          </string-name>
          , Faculty of Sciences, University of Novi Sad, Serbia,
          <year>2018</year>
          , pp.
          <volume>18</volume>
          :
          <fpage>01</fpage>
          -
          <lpage>18</lpage>
          :
          <fpage>08</fpage>
          . URL: http://ceur-ws.
          <source>org/</source>
          Vol-
          <volume>2217</volume>
          /.
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>A.</given-names>
            <surname>Arcuri</surname>
          </string-name>
          ,
          <string-name>
            <given-names>X.</given-names>
            <surname>Yao</surname>
          </string-name>
          ,
          <article-title>A novel co-evolutionary approach to automatic software bug fixing</article-title>
          , in: Evolutionary Computation,
          <year>2008</year>
          .
          <source>CEC</source>
          <year>2008</year>
          .
          <article-title>(IEEE World Congress on Computational Intelligence)</article-title>
          .
          <source>IEEE Congress on, IEEE</source>
          ,
          <year>2008</year>
          , pp.
          <fpage>162</fpage>
          -
          <lpage>168</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <given-names>D.</given-names>
            <surname>Fatiregun</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Harman</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R. M.</given-names>
            <surname>Hierons</surname>
          </string-name>
          ,
          <article-title>Evolving transformation sequences using genetic algorithms</article-title>
          ,
          <source>in: Source Code Analysis and Manipulation</source>
          , Fourth IEEE International Workshop on,
          <year>2004</year>
          , pp.
          <fpage>65</fpage>
          -
          <lpage>74</lpage>
          . doi:
          <volume>10</volume>
          .1109/SCAM.
          <year>2004</year>
          .
          <volume>11</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <given-names>S.</given-names>
            <surname>Forrest</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.</given-names>
            <surname>Nguyen</surname>
          </string-name>
          ,
          <string-name>
            <given-names>W.</given-names>
            <surname>Weimer</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C.</given-names>
            <surname>Le Goues</surname>
          </string-name>
          ,
          <article-title>A genetic programming approach to automated software repair</article-title>
          ,
          <source>in: Proceedings of the 11th Annual conference on Genetic and evolutionary computation, ACM</source>
          ,
          <year>2009</year>
          , pp.
          <fpage>947</fpage>
          -
          <lpage>954</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          [16]
          <string-name>
            <given-names>E. M.</given-names>
            <surname>Schulte</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Forrest</surname>
          </string-name>
          , W. Weimer,
          <article-title>Automated program repair through the evolution of assembly code</article-title>
          , in: C.
          <string-name>
            <surname>Pecheur</surname>
            ,
            <given-names>J.</given-names>
          </string-name>
          <string-name>
            <surname>Andrews</surname>
          </string-name>
          , E. D. Nitto (Eds.),
          <source>Proceedings of the 25th IEEE/ACM International Conference on Automated Software Engineering (ASE '10)</source>
          , ACM,
          <year>2010</year>
          , pp.
          <fpage>313</fpage>
          -
          <lpage>316</lpage>
          . doi:
          <volume>10</volume>
          .1145/1858996.1859059.
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          [17]
          <string-name>
            <given-names>C.</given-names>
            <surname>Le Goues</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.</given-names>
            <surname>Nguyen</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Forrest</surname>
          </string-name>
          , W. Weimer,
          <article-title>Genprog: A generic method for automatic software repair</article-title>
          ,
          <source>IEEE Trans. Software Eng</source>
          .
          <volume>38</volume>
          (
          <year>2012</year>
          )
          <fpage>54</fpage>
          -
          <lpage>72</lpage>
          . doi:
          <volume>10</volume>
          .1109/TSE.
          <year>2011</year>
          .
          <volume>104</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          [18]
          <string-name>
            <given-names>E.</given-names>
            <surname>Fast</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C.</given-names>
            <surname>Le Goues</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Forrest</surname>
          </string-name>
          , W. Weimer,
          <article-title>Designing better fitness functions for automated program repair</article-title>
          ,
          <source>in: Proceedings of the 12th annual conference on Genetic and evolutionary computation, ACM</source>
          ,
          <year>2010</year>
          , pp.
          <fpage>965</fpage>
          -
          <lpage>972</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          [19]
          <string-name>
            <surname>E. F. de Souza</surname>
            ,
            <given-names>C. L.</given-names>
          </string-name>
          <string-name>
            <surname>Goues</surname>
            ,
            <given-names>C. G.</given-names>
          </string-name>
          <string-name>
            <surname>Camilo-Junior</surname>
          </string-name>
          ,
          <article-title>A novel fitness function for automated program repair based on source code checkpoints</article-title>
          ,
          <source>in: Proceedings of the Genetic and Evolutionary Computation Conference, GECCO '18</source>
          ,
          <string-name>
            <surname>ACM</surname>
          </string-name>
          , New York, NY, USA,
          <year>2018</year>
          , pp.
          <fpage>1443</fpage>
          -
          <lpage>1450</lpage>
          . doi:
          <volume>10</volume>
          .1145/3205455.3205566.
        </mixed-citation>
      </ref>
      <ref id="ref20">
        <mixed-citation>
          [20]
          <string-name>
            <surname>A. M. Turing</surname>
          </string-name>
          ,
          <article-title>On computable numbers, with an application to the entscheidungsproblem</article-title>
          ,
          <source>Proceedings of the London Mathematical Society s2-42</source>
          (
          <year>1937</year>
          )
          <fpage>230</fpage>
          -
          <lpage>265</lpage>
          . doi:
          <volume>10</volume>
          .1112/plms/ s2-
          <fpage>42</fpage>
          .1.230.
        </mixed-citation>
      </ref>
      <ref id="ref21">
        <mixed-citation>
          [21]
          <string-name>
            <given-names>D.</given-names>
            <surname>Pracner</surname>
          </string-name>
          ,
          <article-title>Translation and Transformation of Low Level Programs (Prevođenje i transformisanje programa niskog nivoa</article-title>
          ),
          <source>Ph.D. thesis</source>
          , Faculty of Sciences, University of Novi Sad, Serbia,
          <year>2019</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref22">
        <mixed-citation>
          [22]
          <string-name>
            <given-names>D. H.</given-names>
            <surname>Wolpert</surname>
          </string-name>
          , W. G. Macready,
          <article-title>No free lunch theorems for optimization</article-title>
          ,
          <source>IEEE Transactions on Evolutionary Computation</source>
          <volume>1</volume>
          (
          <year>1997</year>
          )
          <fpage>67</fpage>
          -
          <lpage>82</lpage>
          . doi:
          <volume>10</volume>
          .1109/4235.585893.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>