diff --git a/csrc/float_fix.cc b/csrc/float_fix.cc new file mode 100644 index 00000000..4a106bb7 --- /dev/null +++ b/csrc/float_fix.cc @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include + + +// returns the bits in x[high:low] in the lowest positions +uint64_t BitRange(uint64_t x, int high, int low) { + int high_gap = 64 - high; + return x << high_gap >> (low + high_gap); +} + + +// 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 recoded_float = raw_input & 0x1ffffffff; // lower 33 bits + uint64_t sign = BitRange(recoded_float, 31, 31); + uint64_t exp_in = BitRange(recoded_float, 30, 22); + uint64_t sig_in = BitRange(recoded_float, 21, 0); + + bool is_high_subnormal_in = BitRange(exp_in, 6, 0) < 2; + bool is_subnormal = (BitRange(exp_in, 8, 6) == 1) || + ((BitRange(exp_in, 8, 7) == 1) && is_high_subnormal_in); + bool is_normal = ((BitRange(exp_in, 8, 7) == 1) && !is_high_subnormal_in) || + (BitRange(exp_in, 8, 7) == 2); + bool is_special = BitRange(exp_in, 8, 7) == 3; + bool is_NaN = is_special && BitRange(exp_in, 6, 6); + + uint64_t denorm_shift_dist = 2 - BitRange(exp_in, 4, 0); + uint64_t subnormal_sig_out = (0x400000 | sig_in) >> denorm_shift_dist; + uint64_t normal_exp_out = BitRange(exp_in, 7, 0) - 129; + + uint64_t exp_out = is_normal ? normal_exp_out : (is_special ? 255 : 0); + uint64_t sig_out = is_normal || is_NaN ? sig_in : + is_subnormal ? subnormal_sig_out : 0; + + 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)); + return raw_output64; +} + + +// checks if possibly recoded float inside double if upper 31 bits set +bool NestedFloatPossible(uint64_t raw_input) { + const uint64_t mask = 0xfffffffe00000000; + return (raw_input & mask) == mask; +} + + +// best effort at replacing floats with unrecoded versions +void DiffAndFix(std::string rocket_filename, std::string lspike_filename) { + std::ifstream rocket_log(rocket_filename); + if (!rocket_log.is_open()) { + std::cout << "Couldn't open file " << rocket_filename << std::endl; + std::exit(-2); + } + std::ifstream lspike_log(lspike_filename); + if (!lspike_log.is_open()) { + std::cout << "Couldn't open file " << lspike_filename << std::endl; + std::exit(-2); + } + std::stringstream ss; + ss << std::hex; + std::string rocket_line, lspike_line; + while(getline(rocket_log,rocket_line) && getline(lspike_log,lspike_line)) { + if ((rocket_line != lspike_line) && // mismatch and includes fp inst + (rocket_line.find(" f") != std::string::npos)) { + std::string fp_wb_str = rocket_line.substr(40, 16); + uint64_t raw_fp; + ss << fp_wb_str; + ss >> raw_fp; + if (NestedFloatPossible(raw_fp)) { + snprintf(const_cast(rocket_line.data()) + 40, 17, + "%016" PRIx64, UnrecodeFloatFromDouble(raw_fp)); + } + } + printf("%s\n", rocket_line.c_str()); + } + rocket_log.close(); + lspike_log.close(); +} + + +int main(int argc, char** argv) { + if (argc < 3) { + std::cout << "Usage: float_fix rocket_output lspike_output" << std::endl; + return -1; + } + DiffAndFix(std::string(argv[1]), std::string(argv[2])); + return 0; +}