faster and more conservative float_fix
This commit is contained in:
parent
7e25b1ce03
commit
de81762f7c
@ -1,21 +1,59 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
// returns the bits in x[high:low] in the lowest positions
|
// float_fix - Scott Beamer, 2015
|
||||||
|
|
||||||
|
// This program post-processes commit logs from rocket-chip to make it easier
|
||||||
|
// to diff against commit logs from spike. Rocket internally uses recoded
|
||||||
|
// floating point numbers, but this is normally hidden because the commit
|
||||||
|
// logging tool unrecodes (undoes the recoding) those numbers. This tool is for
|
||||||
|
// the corner case (single-precision float stored and loaded from memory as a
|
||||||
|
// double) when the commit logging tool is unable to recode properly on its
|
||||||
|
// own. Given both a rocket commit log (already processed by comlog) and commit
|
||||||
|
// log from spike, this tools attempts to fix that corner case. This tool will
|
||||||
|
// only overwrite the log to hold the unrecoded float if that change will cause
|
||||||
|
// it to match with the spike log (conservative).
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the bits in x[high:low] in the lowest positions
|
||||||
uint64_t BitRange(uint64_t x, int high, int low) {
|
uint64_t BitRange(uint64_t x, int high, int low) {
|
||||||
int high_gap = 64 - high;
|
int high_gap = 64 - high;
|
||||||
return x << high_gap >> (low + high_gap);
|
return x << high_gap >> (low + high_gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// will "unrecode" a single float within a double
|
// Returns uint64_t from the hex encoding within s offset by index
|
||||||
// uses magic numbers since can only handle float
|
uint64_t UIntFromHexSubstring(std::string s, int index) {
|
||||||
// logic from berkeley-hardfloat/src/main/scala/recodedFloatNToFloatN.scala
|
uint64_t x = strtoull(s.c_str() + index, nullptr, 16);
|
||||||
|
assert(errno == 0);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Is commit line for a fld instruction?
|
||||||
|
bool LineIsFLDInst(std::string line) {
|
||||||
|
uint32_t inst_bits = UIntFromHexSubstring(line, 22);
|
||||||
|
uint32_t width_field = (inst_bits >> 12) & 7;
|
||||||
|
uint32_t opcode_field = inst_bits & 127;
|
||||||
|
return (width_field == 3) && (opcode_field == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Is number possibly a recoded float inside double (upper 31 bits set)?
|
||||||
|
bool NestedFloatPossible(uint64_t raw_input) {
|
||||||
|
const uint64_t mask = 0xfffffffe00000000;
|
||||||
|
return (raw_input & mask) == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Unrecodes a single float within a double
|
||||||
|
// uses magic numbers since can only handle float
|
||||||
|
// logic from berkeley-hardfloat/src/main/scala/recodedFloatNToFloatN.scala
|
||||||
uint64_t UnrecodeFloatFromDouble(uint64_t raw_input) {
|
uint64_t UnrecodeFloatFromDouble(uint64_t raw_input) {
|
||||||
uint64_t recoded_float = raw_input & 0x1ffffffff; // lower 33 bits
|
uint64_t recoded_float = raw_input & 0x1ffffffff; // lower 33 bits
|
||||||
uint64_t sign = BitRange(recoded_float, 31, 31);
|
uint64_t sign = BitRange(recoded_float, 31, 31);
|
||||||
@ -39,23 +77,17 @@ uint64_t UnrecodeFloatFromDouble(uint64_t raw_input) {
|
|||||||
is_subnormal ? subnormal_sig_out : 0;
|
is_subnormal ? subnormal_sig_out : 0;
|
||||||
|
|
||||||
uint64_t raw_output64 = (sign << 63) | (exp_out << 23) | sig_out;
|
uint64_t raw_output64 = (sign << 63) | (exp_out << 23) | sig_out;
|
||||||
// make sure nothing leaked over the top
|
// assert((raw_output64 & 0xffffffff00000000) == uint64_t(0));
|
||||||
assert((raw_output64 & 0xffffffff00000000) == uint64_t(0));
|
// If this is not a recoded float, this will return gibberish, however,
|
||||||
|
// the output will not match spike and thus the replacement will not happen.
|
||||||
return raw_output64;
|
return raw_output64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// checks if possibly recoded float inside double (upper 31 bits set)
|
// Best effort at replacing the float writeback with unrecoded version
|
||||||
bool NestedFloatPossible(uint64_t raw_input) {
|
// will only replace if (all of following met):
|
||||||
const uint64_t mask = 0xfffffffe00000000;
|
|
||||||
return (raw_input & mask) == mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// best effort at replacing the float writeback with unrecoded version
|
|
||||||
// will only replace if (all of following met):
|
|
||||||
// - log lines differ between rocket and lspike
|
// - log lines differ between rocket and lspike
|
||||||
// - log line contains a floating point inst
|
// - log line is a fld instruction
|
||||||
// - unrecoding the writeback data as a single float makes them match
|
// - unrecoding the writeback data as a single float makes them match
|
||||||
void DiffAndFix(std::string rocket_filename, std::string lspike_filename) {
|
void DiffAndFix(std::string rocket_filename, std::string lspike_filename) {
|
||||||
std::ifstream rocket_log(rocket_filename);
|
std::ifstream rocket_log(rocket_filename);
|
||||||
@ -68,17 +100,12 @@ void DiffAndFix(std::string rocket_filename, std::string lspike_filename) {
|
|||||||
std::cout << "Couldn't open file " << lspike_filename << std::endl;
|
std::cout << "Couldn't open file " << lspike_filename << std::endl;
|
||||||
std::exit(-2);
|
std::exit(-2);
|
||||||
}
|
}
|
||||||
std::stringstream ss;
|
|
||||||
ss << std::hex;
|
|
||||||
std::string rocket_line, lspike_line;
|
std::string rocket_line, lspike_line;
|
||||||
while (getline(rocket_log,rocket_line) && getline(lspike_log,lspike_line)) {
|
while (getline(rocket_log, rocket_line)) {
|
||||||
if ((rocket_line != lspike_line) &&
|
if (getline(lspike_log, lspike_line) && (rocket_line != lspike_line) &&
|
||||||
(rocket_line.find(" f") != std::string::npos)) {
|
LineIsFLDInst(rocket_line)) {
|
||||||
std::string fixed_line(rocket_line.c_str()); // deep copy
|
std::string fixed_line(rocket_line.c_str()); // deep copy
|
||||||
std::string fp_wb_str = fixed_line.substr(40, 16);
|
uint64_t raw_fp = UIntFromHexSubstring(fixed_line, 40);
|
||||||
uint64_t raw_fp;
|
|
||||||
ss << fp_wb_str;
|
|
||||||
ss >> raw_fp;
|
|
||||||
if (NestedFloatPossible(raw_fp)) {
|
if (NestedFloatPossible(raw_fp)) {
|
||||||
snprintf(const_cast<char*>(fixed_line.data()) + 40, 17,
|
snprintf(const_cast<char*>(fixed_line.data()) + 40, 17,
|
||||||
"%016" PRIx64, UnrecodeFloatFromDouble(raw_fp));
|
"%016" PRIx64, UnrecodeFloatFromDouble(raw_fp));
|
||||||
@ -98,7 +125,6 @@ int main(int argc, char** argv) {
|
|||||||
std::cout << "Usage: float_fix rocket_output lspike_output" << std::endl;
|
std::cout << "Usage: float_fix rocket_output lspike_output" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// std::cout << NestedFloatPossible(0xf0f0f0ff0f000000) << std::endl;
|
|
||||||
DiffAndFix(std::string(argv[1]), std::string(argv[2]));
|
DiffAndFix(std::string(argv[1]), std::string(argv[2]));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user