Difference between revisions of "Arrange timed code.cpp"
From Just in Time
(Created page with "//// Copyright (c) 2013 Danny Havenith //// Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.or...") |
|||
Line 1: | Line 1: | ||
− | //// Copyright (c) 2013 Danny Havenith //// Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // | + | <syntaxhighlight lang="cpp"> |
+ | // | ||
+ | // Copyright (c) 2013 Danny Havenith | ||
+ | // | ||
+ | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
+ | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
+ | // | ||
− | #include <iostream> #include <string> #include <map> #include <vector> #include <algorithm> #include <limits> #include <boost/foreach.hpp> | + | #include <iostream> |
+ | #include <string> | ||
+ | #include <map> | ||
+ | #include <vector> | ||
+ | #include <algorithm> | ||
+ | #include <limits> | ||
+ | #include <boost/foreach.hpp> | ||
− | using namespace std; /// Simple struct that can be used as an input to describe blocks of assembly instructions with jumps and labels struct labelinfo { string label; string jumpto; }; | + | using namespace std; |
+ | /// Simple struct that can be used as an input to describe blocks of assembly instructions with jumps and labels | ||
+ | struct labelinfo { | ||
+ | string label; | ||
+ | string jumpto; | ||
+ | }; | ||
− | /// a contiguous block of assembly instructions. /// This structure holds information about the size of the block, /// all relative jumps that emanate from this block and all labes that /// are defined in this block. struct block { typedef map<string, int> labelmap; int | + | /// a contiguous block of assembly instructions. |
+ | /// This structure holds information about the size of the block, | ||
+ | /// all relative jumps that emanate from this block and all labes that | ||
+ | /// are defined in this block. | ||
+ | struct block | ||
+ | { | ||
+ | typedef map<string, int> labelmap; | ||
+ | int size; | ||
+ | string name; | ||
+ | labelmap labels; | ||
+ | labelmap jumps; | ||
− | + | bool operator<( const block &other) const | |
+ | { | ||
+ | return name < other.name; | ||
+ | } | ||
+ | }; | ||
− | + | /// Parse labelinfo structs and create disjunct blocks. | |
+ | /// This function will traverse the range of labelinfos and create blocks on-the-go. | ||
+ | /// The last statement of a block is recognized by the label "END", whenever this label is encountered all | ||
+ | /// statements so far will be combined in one block and this block will be appended to the result. | ||
+ | vector<block> parse_blocks( labelinfo *begin, labelinfo *end) | ||
+ | { | ||
+ | vector<block> result; | ||
− | + | int current_line = 0; | |
+ | block current_block; | ||
+ | while (begin != end) | ||
+ | { | ||
+ | if (begin->label == "END") | ||
+ | { | ||
+ | current_block.size = current_line + 1; | ||
+ | result.push_back( current_block); | ||
+ | current_line = 0; | ||
+ | current_block = block(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | if (!begin->label.empty()) | ||
+ | { | ||
+ | if (current_line == 0) current_block.name = begin->label; | ||
+ | current_block.labels[begin->label] = current_line; | ||
+ | } | ||
+ | if (!begin->jumpto.empty()) | ||
+ | { | ||
+ | current_block.jumps[begin->jumpto] = current_line; | ||
+ | } | ||
+ | ++current_line; | ||
+ | } | ||
+ | ++begin; | ||
+ | } | ||
+ | return result; | ||
+ | } | ||
− | /// | + | /// Given a sequence of blocks, determine the absolute addresses of the labels that |
+ | /// appear in each block. | ||
+ | block::labelmap map_labels( const vector<block>& blocks) | ||
+ | { | ||
+ | block::labelmap label_addresses; | ||
− | int | + | // determine absolute labels |
+ | int current_block_startaddress = 0; | ||
+ | BOOST_FOREACH( const block &b, blocks) | ||
+ | { | ||
+ | BOOST_FOREACH( const block::labelmap::value_type &label, b.labels) | ||
+ | { | ||
+ | label_addresses[label.first] = label.second | ||
+ | + current_block_startaddress; | ||
+ | } | ||
+ | current_block_startaddress += b.size; | ||
+ | } | ||
− | + | return label_addresses; | |
+ | } | ||
− | // | + | /// Determine whether a sequence of blocks matches the criterium of valid jumps. |
+ | /// This criterium is matched if all jumps are close enough to their destination labels. | ||
+ | /// Close enough, in this case, means that the offset between jump and destination must fall within [-63,64] | ||
+ | /// This function is faster than the calculate_fit() function because it can terminate immediately if it finds a jump | ||
+ | /// that does not qualify. | ||
+ | bool is_fit( const vector<block> &blocks) | ||
+ | { | ||
+ | block::labelmap label_addresses = map_labels(blocks); | ||
− | return | + | // see if all jumps are in range. |
+ | int current_block_startaddress = 0; | ||
+ | BOOST_FOREACH( const block &b, blocks) | ||
+ | { | ||
+ | BOOST_FOREACH( const block::labelmap::value_type &jump, b.jumps) | ||
+ | { | ||
+ | int offset = label_addresses[jump.first] - (jump.second + current_block_startaddress); | ||
+ | if (offset > 64 || offset < -63) return false; | ||
+ | } | ||
+ | current_block_startaddress += b.size; | ||
+ | } | ||
− | + | return true; | |
+ | } | ||
− | // | + | /// This is largely a copy of the is_fit() function with some changes. Instead of returning a fit/not-fit boolean, |
+ | /// this function returns a score that is calculated as the maximum (absolute) jump distance. | ||
+ | /// This function is slightly less efficient than that is_fit() function, because it needss to complete the | ||
+ | /// calculation, even if the score is higher than the fitness criterium. | ||
+ | int calculate_fit( const vector<block> &blocks) | ||
+ | { | ||
+ | block::labelmap label_addresses = map_labels( blocks); | ||
− | + | // calculate the maximum jump offset in this sequence of blocks. | |
+ | int max_offset = 0; | ||
+ | int current_block_startaddress = 0; | ||
+ | BOOST_FOREACH( const block &b, blocks) | ||
+ | { | ||
+ | BOOST_FOREACH( const block::labelmap::value_type &jump, b.jumps) | ||
+ | { | ||
+ | int offset = label_addresses[jump.first] - (jump.second + current_block_startaddress); | ||
+ | if (offset > max_offset) max_offset = offset; | ||
+ | if (-offset > max_offset) max_offset = -offset; | ||
+ | } | ||
+ | current_block_startaddress += b.size; | ||
+ | } | ||
− | + | return max_offset; | |
+ | } | ||
− | // | + | /// Description of the code blocks. This was created with some spreadsheet magic from the original code spreadsheet |
+ | /// because I was too lazy to implement input text parsing. | ||
+ | labelinfo labels[] = { | ||
+ | { "M2", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "H1"}, | ||
+ | { "", ""}, | ||
+ | { "", "L16"}, | ||
+ | { "", ""}, | ||
+ | { "L9", ""}, | ||
+ | { "", ""}, | ||
+ | { "L5", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "L1"}, | ||
+ | { "", ""}, | ||
+ | { "", "M1"}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "L4"}, | ||
+ | { "", ""}, | ||
+ | { "L12", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "L1", ""}, | ||
+ | { "", "M2"}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "L8"}, | ||
+ | { "", ""}, | ||
+ | { "L15", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "L10", ""}, | ||
+ | { "", "M3"}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "L12"}, | ||
+ | { "", ""}, | ||
+ | { "L4", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "M4", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "H1"}, | ||
+ | { "", ""}, | ||
+ | { "", "L9"}, | ||
+ | { "", ""}, | ||
+ | { "L16", ""}, | ||
+ | { "", ""}, | ||
+ | { "L13", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "L10"}, | ||
+ | { "", ""}, | ||
+ | { "", "M4"}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "L15"}, | ||
+ | { "", ""}, | ||
+ | { "L8", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "M1", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "H2"}, | ||
+ | { "", ""}, | ||
+ | { "", "L9"}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "M3", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", "H2"}, | ||
+ | { "", ""}, | ||
+ | { "", "L16"}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "H1", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | { "H2", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "", ""}, | ||
+ | { "END", ""}, | ||
+ | }; | ||
− | + | /// Print out the optimum sequence of code blocks (=with minimum max jump distance). | |
+ | /// This function will simply iterate over all 40K permutations of 8 blocks and calculate the score for each | ||
+ | /// permutation. | ||
+ | int main() | ||
+ | { | ||
+ | vector<block> blocks = parse_blocks( labels, labels + sizeof labels/sizeof labels[0] ); | ||
+ | sort( blocks.begin(), blocks.end()); | ||
− | + | BOOST_FOREACH( const block &b, blocks) | |
+ | { | ||
+ | cout << b.name << "\n"; | ||
+ | } | ||
− | + | vector<block> best_blocks; | |
+ | int min_offset = numeric_limits<int>::max(); | ||
+ | do | ||
+ | { | ||
+ | int new_offset = calculate_fit( blocks); | ||
+ | if (new_offset < min_offset) | ||
+ | { | ||
+ | best_blocks = blocks; | ||
+ | min_offset = new_offset; | ||
+ | cout << min_offset << ", "; | ||
+ | } | ||
+ | } while (next_permutation( blocks.begin(), blocks.end())); | ||
− | |||
− | + | if (is_fit(best_blocks)) | |
+ | { | ||
+ | cout << "\nSuccess:\n"; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | cout << "\nNothing\n"; | ||
+ | } | ||
− | + | BOOST_FOREACH( const block &b, best_blocks) | |
+ | { | ||
+ | cout << b.name << "\n"; | ||
+ | } | ||
− | + | return 0; | |
+ | } | ||
− | + | </syntaxhighlight> |
Revision as of 16:38, 12 February 2013
//
// Copyright (c) 2013 Danny Havenith
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <limits>
#include <boost/foreach.hpp>
using namespace std;
/// Simple struct that can be used as an input to describe blocks of assembly instructions with jumps and labels
struct labelinfo {
string label;
string jumpto;
};
/// a contiguous block of assembly instructions.
/// This structure holds information about the size of the block,
/// all relative jumps that emanate from this block and all labes that
/// are defined in this block.
struct block
{
typedef map<string, int> labelmap;
int size;
string name;
labelmap labels;
labelmap jumps;
bool operator<( const block &other) const
{
return name < other.name;
}
};
/// Parse labelinfo structs and create disjunct blocks.
/// This function will traverse the range of labelinfos and create blocks on-the-go.
/// The last statement of a block is recognized by the label "END", whenever this label is encountered all
/// statements so far will be combined in one block and this block will be appended to the result.
vector<block> parse_blocks( labelinfo *begin, labelinfo *end)
{
vector<block> result;
int current_line = 0;
block current_block;
while (begin != end)
{
if (begin->label == "END")
{
current_block.size = current_line + 1;
result.push_back( current_block);
current_line = 0;
current_block = block();
}
else
{
if (!begin->label.empty())
{
if (current_line == 0) current_block.name = begin->label;
current_block.labels[begin->label] = current_line;
}
if (!begin->jumpto.empty())
{
current_block.jumps[begin->jumpto] = current_line;
}
++current_line;
}
++begin;
}
return result;
}
/// Given a sequence of blocks, determine the absolute addresses of the labels that
/// appear in each block.
block::labelmap map_labels( const vector<block>& blocks)
{
block::labelmap label_addresses;
// determine absolute labels
int current_block_startaddress = 0;
BOOST_FOREACH( const block &b, blocks)
{
BOOST_FOREACH( const block::labelmap::value_type &label, b.labels)
{
label_addresses[label.first] = label.second
+ current_block_startaddress;
}
current_block_startaddress += b.size;
}
return label_addresses;
}
/// Determine whether a sequence of blocks matches the criterium of valid jumps.
/// This criterium is matched if all jumps are close enough to their destination labels.
/// Close enough, in this case, means that the offset between jump and destination must fall within [-63,64]
/// This function is faster than the calculate_fit() function because it can terminate immediately if it finds a jump
/// that does not qualify.
bool is_fit( const vector<block> &blocks)
{
block::labelmap label_addresses = map_labels(blocks);
// see if all jumps are in range.
int current_block_startaddress = 0;
BOOST_FOREACH( const block &b, blocks)
{
BOOST_FOREACH( const block::labelmap::value_type &jump, b.jumps)
{
int offset = label_addresses[jump.first] - (jump.second + current_block_startaddress);
if (offset > 64 || offset < -63) return false;
}
current_block_startaddress += b.size;
}
return true;
}
/// This is largely a copy of the is_fit() function with some changes. Instead of returning a fit/not-fit boolean,
/// this function returns a score that is calculated as the maximum (absolute) jump distance.
/// This function is slightly less efficient than that is_fit() function, because it needss to complete the
/// calculation, even if the score is higher than the fitness criterium.
int calculate_fit( const vector<block> &blocks)
{
block::labelmap label_addresses = map_labels( blocks);
// calculate the maximum jump offset in this sequence of blocks.
int max_offset = 0;
int current_block_startaddress = 0;
BOOST_FOREACH( const block &b, blocks)
{
BOOST_FOREACH( const block::labelmap::value_type &jump, b.jumps)
{
int offset = label_addresses[jump.first] - (jump.second + current_block_startaddress);
if (offset > max_offset) max_offset = offset;
if (-offset > max_offset) max_offset = -offset;
}
current_block_startaddress += b.size;
}
return max_offset;
}
/// Description of the code blocks. This was created with some spreadsheet magic from the original code spreadsheet
/// because I was too lazy to implement input text parsing.
labelinfo labels[] = {
{ "M2", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "H1"},
{ "", ""},
{ "", "L16"},
{ "", ""},
{ "L9", ""},
{ "", ""},
{ "L5", ""},
{ "", ""},
{ "", "L1"},
{ "", ""},
{ "", "M1"},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "L4"},
{ "", ""},
{ "L12", ""},
{ "", ""},
{ "", ""},
{ "END", ""},
{ "L1", ""},
{ "", "M2"},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "L8"},
{ "", ""},
{ "L15", ""},
{ "", ""},
{ "", ""},
{ "END", ""},
{ "L10", ""},
{ "", "M3"},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "L12"},
{ "", ""},
{ "L4", ""},
{ "", ""},
{ "", ""},
{ "END", ""},
{ "M4", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "H1"},
{ "", ""},
{ "", "L9"},
{ "", ""},
{ "L16", ""},
{ "", ""},
{ "L13", ""},
{ "", ""},
{ "", ""},
{ "", "L10"},
{ "", ""},
{ "", "M4"},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "L15"},
{ "", ""},
{ "L8", ""},
{ "", ""},
{ "", ""},
{ "END", ""},
{ "M1", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "H2"},
{ "", ""},
{ "", "L9"},
{ "", ""},
{ "END", ""},
{ "M3", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", "H2"},
{ "", ""},
{ "", "L16"},
{ "", ""},
{ "END", ""},
{ "H1", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "END", ""},
{ "H2", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "", ""},
{ "END", ""},
};
/// Print out the optimum sequence of code blocks (=with minimum max jump distance).
/// This function will simply iterate over all 40K permutations of 8 blocks and calculate the score for each
/// permutation.
int main()
{
vector<block> blocks = parse_blocks( labels, labels + sizeof labels/sizeof labels[0] );
sort( blocks.begin(), blocks.end());
BOOST_FOREACH( const block &b, blocks)
{
cout << b.name << "\n";
}
vector<block> best_blocks;
int min_offset = numeric_limits<int>::max();
do
{
int new_offset = calculate_fit( blocks);
if (new_offset < min_offset)
{
best_blocks = blocks;
min_offset = new_offset;
cout << min_offset << ", ";
}
} while (next_permutation( blocks.begin(), blocks.end()));
if (is_fit(best_blocks))
{
cout << "\nSuccess:\n";
}
else
{
cout << "\nNothing\n";
}
BOOST_FOREACH( const block &b, best_blocks)
{
cout << b.name << "\n";
}
return 0;
}