├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── applications ├── Makefile ├── executable.h ├── implementations.h └── test.cpp ├── baseTypes ├── Makefile ├── cprover_bvt.cpp ├── cprover_bvt.h ├── cprover_common.h ├── cprover_exprt.cpp ├── cprover_exprt.h ├── cvc4_literal.cpp ├── cvc4_literal.h ├── cvc4_symbolic.cpp ├── cvc4_symbolic.h ├── shared.h ├── simpleExecutable.cpp └── simpleExecutable.h ├── core ├── Makefile ├── add.h ├── classify.h ├── compare.h ├── convert.h ├── divide.h ├── fma.h ├── ite.h ├── multiply.h ├── operations.h ├── packing.h ├── remainder.h ├── rounder.h ├── sign.h ├── sqrt.h └── unpackedFloat.h ├── flags └── utils ├── Makefile ├── common.h ├── numberOfRoundingModes.h └── properties.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include flags 2 | SUBDIRS=applications/ baseTypes/ 3 | OBJECTFILES=baseTypes/simpleExecutable.o 4 | LIBFILES=symfpu.a 5 | PROGS=test 6 | 7 | 8 | .PHONY: all subdirs $(SUBDIRS) clean $(PROGS) 9 | 10 | all : subdirs $(LIBFILES) $(PROGS) 11 | 12 | subdirs: $(SUBDIRS) 13 | 14 | $(SUBDIRS): 15 | $(MAKE) -C $@ 16 | 17 | symfpu.a : $(OBJECTFILES) 18 | ar rcs $@ $^ 19 | 20 | clean : 21 | find . -name '*.o' -exec rm {} \; 22 | rm -f $(LIBFILES) $(PROGS) 23 | 24 | test : applications/test.o $(LIBFILES) 25 | $(CXX) $(CXXFLAGS) $^ -o $@ 26 | 27 | cbmcverification : applications/cbmcverification.o $(LIBFILES) 28 | $(CXX) $(CXXFLAGS) $^ -o $@ 29 | 30 | generate : applications/generate.o $(LIBFILES) 31 | $(CXX) $(CXXFLAGS) $^ -o $@ 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SymFPU : The Symbolic Floating Point Unit 2 | ========================================= 3 | 4 | SymFPU is an implementation of the SMT-LIB / IEEE-754 operations in 5 | terms of bit-vector operations. It is templated in terms of the 6 | bit-vectors, propositions, floating-point formats and rounding mode 7 | types used. This allow the same code to be executed as an arbitrary 8 | precision "SoftFloat" library (although it's performance would not be 9 | good) or to be used to build symbolic representation of floating-point 10 | operations suitable for use in "bit-blasting" SMT solvers (you could 11 | also generate circuits from them but again, performance will likely 12 | not be good). 13 | 14 | A considerable amount of effort has gone in to checking that these 15 | encodings are correct and so please do report any discrepancies you 16 | see. 17 | 18 | The library is Free Software licensed under the GPL V3. If this poses 19 | a particular challenge for your application, please contact the author. 20 | 21 | 22 | A Quick Start 23 | ------------- 24 | 25 | 1. Create a "back-end", a class with the following members: 26 | 27 | ``` 28 | class traits { 29 | public : 30 | // The base types to use. 31 | // Must implement the SMT-LIB-like interfaces used by other back-ends 32 | typedef YourBitWidthType bwt; 33 | typedef YourRoundingMode rm; 34 | typedef YourFloatingPointTypeInfo fpt; 35 | typedef YourProposition prop; 36 | typedef YourSignedBitVector sbv; 37 | typedef YourUnsignedBitVector ubv; 38 | 39 | // Return an instance of each rounding mode. 40 | static rm RNE(void); 41 | static rm RNA(void); 42 | static rm RTP(void); 43 | static rm RTN(void); 44 | static rm RTZ(void); 45 | 46 | // Handle various invariants. 47 | // These can be empty to start with. 48 | static void precondition(const bool b) { assert(b); } 49 | static void postcondition(const bool b) { assert(b); } 50 | static void invariant(const bool b) { assert(b); } 51 | static void precondition(const prop &p) {} 52 | static void postcondition(const prop &p) {} 53 | static void invariant(const prop &p) {} 54 | }; 55 | ``` 56 | 57 | If you are stuck; start from one of the existing (symbolic or literal) 58 | ones. `baseTypes/shared.h` gives suitable implementations of `fpt` and 59 | `bwt`, plus if it is executable, you can use bool for prop. 60 | 61 | 62 | 2. Make sure symfpu is on your path and include the following headers: 63 | 64 | ``` 65 | #include "symfpu/core/unpackedFloat.h" 66 | #include "symfpu/core/packing.h" 67 | #include "symfpu/core/add.h" 68 | ``` 69 | 70 | 3. To generate a (32-bit) unsigned bit-vector containing the single 71 | precision addition of two other 32-bit bit-vectors, use the following code: 72 | 73 | ``` 74 | fpt format(8,24); 75 | ubv packed1 = ... // Must be 32-bit. 76 | ubv packed2 = ... // Must be 32-bit. 77 | 78 | uf unpacked1(symfpu::unpack(format, packed1)); 79 | uf unpacked2(symfpu::unpack(format, packed2)); 80 | 81 | uf added(symfpu::add(format, traits::RNE(), unpacked1, unpacked2, prop(true))); 82 | 83 | ubv repacked(symfpu::pack(format, added)); 84 | ``` 85 | 86 | See `applications/implementation.h` for examples of other operations 87 | (although, really, it is pretty similar). 88 | 89 | -------------------------------------------------------------------------------- /applications/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags 2 | CXXFLAGS+=-I../../ 3 | ALL=test.o 4 | 5 | .PHONY : all 6 | 7 | all : $(ALL) 8 | 9 | %.o : %.cpp 10 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 11 | 12 | -------------------------------------------------------------------------------- /applications/executable.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | // DEPRECIATED : USE implementation.h instead 19 | 20 | /* 21 | ** executable.h 22 | ** 23 | ** Martin Brain 24 | ** martin.brain@cs.ox.ac.uk 25 | ** 06/08/14 26 | ** 27 | ** A set of basic functions constructed from the simple executable 28 | ** implementation of bit-vectors. 29 | ** 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "symfpu/core/unpackedFloat.h" 37 | #include "symfpu/core/packing.h" 38 | #include "symfpu/core/sign.h" 39 | #include "symfpu/core/classify.h" 40 | #include "symfpu/core/compare.h" 41 | #include "symfpu/core/multiply.h" 42 | #include "symfpu/core/add.h" 43 | 44 | 45 | 46 | #ifndef SYMFPU_EXECUTABLE 47 | #define SYMFPU_EXECUTABLE 48 | 49 | 50 | 51 | template 52 | class executableTests { 53 | 54 | public : 55 | // Wrapped in a struct to make type scoping easier 56 | // and to save on typenames. 57 | // Object is stateless. 58 | 59 | typedef typename traits::rm rm; 60 | typedef typename traits::bwt bwt; 61 | typedef typename traits::fpt fpt; 62 | typedef typename traits::ubv ubv; 63 | typedef typename traits::prop prop; 64 | typedef symfpu::unpackedFloat uf; 65 | 66 | static bwt bitsInExecBV () { 67 | return sizeof(execBV) * CHAR_BIT; 68 | } 69 | 70 | 71 | 72 | static execBV unpackPack (const fpt &format, const execBV bv) { 73 | ubv packed(bitsInExecBV(),bv); 74 | 75 | uf unpacked(symfpu::unpack(format, packed)); 76 | 77 | ubv repacked(symfpu::pack(format, unpacked)); 78 | 79 | return repacked.contents(); 80 | } 81 | 82 | static execBV unpackPackReference (const fpt &, execBV bv) { 83 | return bv; 84 | } 85 | 86 | 87 | 88 | static execBV negate (const fpt &format, execBV bv) { 89 | ubv packed(bitsInExecBV(),bv); 90 | 91 | uf unpacked(symfpu::unpack(format, packed)); 92 | 93 | uf negated(symfpu::negate(format, unpacked)); 94 | 95 | ubv repacked(symfpu::pack(format, negated)); 96 | 97 | return repacked.contents(); 98 | } 99 | 100 | static execBV negateReference (const fpt &, execBV bv) { 101 | execFloat f = *((execFloat *)&bv); 102 | 103 | f = -f; 104 | 105 | return *((execBV *)&f); 106 | } 107 | 108 | 109 | 110 | static execBV absolute (const fpt &format, execBV bv) { 111 | ubv packed(bitsInExecBV(),bv); 112 | 113 | uf unpacked(symfpu::unpack(format, packed)); 114 | 115 | uf abs(symfpu::absolute(format, unpacked)); 116 | 117 | ubv repacked(symfpu::pack(format, abs)); 118 | 119 | return repacked.contents(); 120 | } 121 | 122 | static execBV absoluteReference (const fpt &, execBV bv) { 123 | execFloat f = *((execFloat *)&bv); 124 | 125 | f = nativeFunctions::abs(f); 126 | 127 | return *((execBV *)&f); 128 | } 129 | 130 | 131 | static bool isNormal (const fpt &format, execBV bv) { 132 | ubv packed(bitsInExecBV(),bv); 133 | 134 | uf unpacked(symfpu::unpack(format, packed)); 135 | 136 | prop result(symfpu::isNormal(format, unpacked)); 137 | 138 | return result; 139 | } 140 | 141 | static bool isNormalReference (const fpt &, execBV bv) { 142 | execFloat f = *((execFloat *)&bv); 143 | 144 | return nativeFunctions::isNormal(f); 145 | } 146 | 147 | 148 | 149 | static bool isSubnormal (const fpt &format, execBV bv) { 150 | ubv packed(bitsInExecBV(),bv); 151 | 152 | uf unpacked(symfpu::unpack(format, packed)); 153 | 154 | prop result(symfpu::isSubnormal(format, unpacked)); 155 | 156 | return result; 157 | } 158 | 159 | static bool isSubnormalReference (const fpt &, execBV bv) { 160 | execFloat f = *((execFloat *)&bv); 161 | 162 | return nativeFunctions::isSubnormal(f); 163 | } 164 | 165 | 166 | 167 | 168 | static bool isZero (const fpt &format, execBV bv) { 169 | ubv packed(bitsInExecBV(),bv); 170 | 171 | uf unpacked(symfpu::unpack(format, packed)); 172 | 173 | prop result(symfpu::isZero(format, unpacked)); 174 | 175 | return result; 176 | } 177 | 178 | static bool isZeroReference (const fpt &, execBV bv) { 179 | execFloat f = *((execFloat *)&bv); 180 | 181 | return nativeFunctions::isZero(f); 182 | } 183 | 184 | 185 | 186 | static bool isInfinite (const fpt &format, execBV bv) { 187 | ubv packed(bitsInExecBV(),bv); 188 | 189 | uf unpacked(symfpu::unpack(format, packed)); 190 | 191 | prop result(symfpu::isInfinite(format, unpacked)); 192 | 193 | return result; 194 | } 195 | 196 | static bool isInfiniteReference (const fpt &, execBV bv) { 197 | execFloat f = *((execFloat *)&bv); 198 | 199 | return nativeFunctions::isInf(f); 200 | } 201 | 202 | 203 | 204 | static bool isNaN (const fpt &format, execBV bv) { 205 | ubv packed(bitsInExecBV(),bv); 206 | 207 | uf unpacked(symfpu::unpack(format, packed)); 208 | 209 | prop result(symfpu::isNaN(format, unpacked)); 210 | 211 | return result; 212 | } 213 | 214 | static bool isNaNReference (const fpt &, execBV bv) { 215 | execFloat f = *((execFloat *)&bv); 216 | 217 | return nativeFunctions::isNaN(f); 218 | } 219 | 220 | 221 | 222 | 223 | static bool isPositive (const fpt &format, execBV bv) { 224 | ubv packed(bitsInExecBV(),bv); 225 | 226 | uf unpacked(symfpu::unpack(format, packed)); 227 | 228 | prop result(symfpu::isPositive(format, unpacked)); 229 | 230 | return result; 231 | } 232 | 233 | static bool isPositiveReference (const fpt &, execBV bv) { 234 | execFloat f = *((execFloat *)&bv); 235 | 236 | return nativeFunctions::isPositive(f); 237 | } 238 | 239 | 240 | 241 | static bool isNegative (const fpt &format, execBV bv) { 242 | ubv packed(bitsInExecBV(),bv); 243 | 244 | uf unpacked(symfpu::unpack(format, packed)); 245 | 246 | prop result(symfpu::isNegative(format, unpacked)); 247 | 248 | return result; 249 | } 250 | 251 | static bool isNegativeReference (const fpt &, execBV bv) { 252 | execFloat f = *((execFloat *)&bv); 253 | 254 | return nativeFunctions::isNegative(f); 255 | } 256 | 257 | 258 | static bool smtlibEqual (const fpt &format, execBV bv1, execBV bv2) { 259 | ubv packed1(bitsInExecBV(),bv1); 260 | ubv packed2(bitsInExecBV(),bv2); 261 | 262 | uf unpacked1(symfpu::unpack(format, packed1)); 263 | uf unpacked2(symfpu::unpack(format, packed2)); 264 | 265 | prop result(symfpu::smtlibEqual(format, unpacked1, unpacked2)); 266 | 267 | return result; 268 | } 269 | 270 | static bool smtlibEqualReference (const fpt &, execBV bv1, execBV bv2) { 271 | execFloat f = *((execFloat *)(&bv1)); 272 | execFloat g = *((execFloat *)(&bv2)); 273 | 274 | return (bv1 == bv2) || (nativeFunctions::isNaN(f) && nativeFunctions::isNaN(g)); 275 | } 276 | 277 | 278 | 279 | static bool ieee754Equal (const fpt &format, execBV bv1, execBV bv2) { 280 | ubv packed1(bitsInExecBV(),bv1); 281 | ubv packed2(bitsInExecBV(),bv2); 282 | 283 | uf unpacked1(symfpu::unpack(format, packed1)); 284 | uf unpacked2(symfpu::unpack(format, packed2)); 285 | 286 | prop result(symfpu::ieee754Equal(format, unpacked1, unpacked2)); 287 | 288 | return result; 289 | } 290 | 291 | 292 | static bool ieee754EqualReference (const fpt &, execBV bv1, execBV bv2) { 293 | execFloat f = *((execFloat *)(&bv1)); 294 | execFloat g = *((execFloat *)(&bv2)); 295 | 296 | return (f == g); 297 | } 298 | 299 | 300 | 301 | static bool lessThan (const fpt &format, execBV bv1, execBV bv2) { 302 | ubv packed1(bitsInExecBV(),bv1); 303 | ubv packed2(bitsInExecBV(),bv2); 304 | 305 | uf unpacked1(symfpu::unpack(format, packed1)); 306 | uf unpacked2(symfpu::unpack(format, packed2)); 307 | 308 | prop result(symfpu::lessThan(format, unpacked1, unpacked2)); 309 | 310 | return result; 311 | } 312 | 313 | static bool lessThanReference (const fpt &, execBV bv1, execBV bv2) { 314 | execFloat f = *((execFloat *)(&bv1)); 315 | execFloat g = *((execFloat *)(&bv2)); 316 | 317 | return (f < g); 318 | } 319 | 320 | 321 | 322 | 323 | 324 | static bool lessThanOrEqual (const fpt &format, execBV bv1, execBV bv2) { 325 | ubv packed1(bitsInExecBV(),bv1); 326 | ubv packed2(bitsInExecBV(),bv2); 327 | 328 | uf unpacked1(symfpu::unpack(format, packed1)); 329 | uf unpacked2(symfpu::unpack(format, packed2)); 330 | 331 | prop result(symfpu::lessThanOrEqual(format, unpacked1, unpacked2)); 332 | 333 | return result; 334 | } 335 | 336 | 337 | static bool lessThanOrEqualReference (const fpt &, execBV bv1, execBV bv2) { 338 | execFloat f = *((execFloat *)(&bv1)); 339 | execFloat g = *((execFloat *)(&bv2)); 340 | 341 | return (f <= g); 342 | } 343 | 344 | 345 | 346 | 347 | static execBV multiply (const fpt &format, const rm &roundingMode, execBV bv1, execBV bv2) { 348 | ubv packed1(bitsInExecBV(),bv1); 349 | ubv packed2(bitsInExecBV(),bv2); 350 | 351 | uf unpacked1(symfpu::unpack(format, packed1)); 352 | uf unpacked2(symfpu::unpack(format, packed2)); 353 | 354 | uf multiplied(symfpu::multiply(format, roundingMode, unpacked1, unpacked2)); 355 | 356 | ubv repacked(symfpu::pack(format, multiplied)); 357 | 358 | return repacked.contents(); 359 | } 360 | 361 | 362 | static execBV multiplyReference (const fpt &, const rm &roundingMode, execBV bv1, execBV bv2) { 363 | execFloat f = *((execFloat *)(&bv1)); 364 | execFloat g = *((execFloat *)(&bv2)); 365 | 366 | fesetround(roundingMode.getValue()); 367 | 368 | execFloat h = f * g; 369 | 370 | return *((execBV *)&h); 371 | } 372 | 373 | static execBV add (const fpt &format, const rm &roundingMode, execBV bv1, execBV bv2) { 374 | ubv packed1(bitsInExecBV(),bv1); 375 | ubv packed2(bitsInExecBV(),bv2); 376 | 377 | uf unpacked1(symfpu::unpack(format, packed1)); 378 | uf unpacked2(symfpu::unpack(format, packed2)); 379 | 380 | uf added(symfpu::add(format, roundingMode, unpacked1, unpacked2, prop(true))); 381 | 382 | ubv repacked(symfpu::pack(format, added)); 383 | 384 | return repacked.contents(); 385 | } 386 | 387 | 388 | static execBV addReference (const fpt &, const rm &roundingMode, execBV bv1, execBV bv2) { 389 | execFloat f = *((execFloat *)(&bv1)); 390 | execFloat g = *((execFloat *)(&bv2)); 391 | 392 | fesetround(roundingMode.getValue()); 393 | 394 | execFloat h = f + g; 395 | 396 | return *((execBV *)&h); 397 | } 398 | 399 | 400 | static execBV sub (const fpt &format, const rm &roundingMode, execBV bv1, execBV bv2) { 401 | ubv packed1(bitsInExecBV(),bv1); 402 | ubv packed2(bitsInExecBV(),bv2); 403 | 404 | uf unpacked1(symfpu::unpack(format, packed1)); 405 | uf unpacked2(symfpu::unpack(format, packed2)); 406 | 407 | uf added(symfpu::add(format, roundingMode, unpacked1, unpacked2, prop(false))); 408 | 409 | ubv repacked(symfpu::pack(format, added)); 410 | 411 | return repacked.contents(); 412 | } 413 | 414 | 415 | static execBV subReference (const fpt &, const rm &roundingMode, execBV bv1, execBV bv2) { 416 | execFloat f = *((execFloat *)(&bv1)); 417 | execFloat g = *((execFloat *)(&bv2)); 418 | 419 | fesetround(roundingMode.getValue()); 420 | 421 | execFloat h = f - g; 422 | 423 | return *((execBV *)&h); 424 | } 425 | 426 | // The SMT-LIB notion of equality 427 | //bool compareFloat (execBV bv1, execBV bv2); 428 | 429 | }; 430 | 431 | 432 | 433 | 434 | #endif 435 | -------------------------------------------------------------------------------- /baseTypes/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags 2 | CXXFLAGS+=-I../../ 3 | ALL=simpleExecutable.o 4 | 5 | .PHONY : all 6 | 7 | all : $(ALL) 8 | 9 | %.o : %.cpp 10 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 11 | 12 | -------------------------------------------------------------------------------- /baseTypes/cprover_bvt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | #include "symfpu/baseTypes/cprover_bvt.h" 19 | 20 | namespace symfpu { 21 | namespace cprover_bvt { 22 | bv_utilst *solver = NULL; 23 | 24 | #define BITS 32 25 | 26 | roundingMode traits::RNE (void) { 27 | return roundingMode(solver->build_constant(0/*ieee_floatt::ROUND_TO_EVEN*/, BITS)); 28 | } 29 | 30 | roundingMode traits::RNA (void) { 31 | return roundingMode(solver->build_constant(4, BITS)); 32 | } 33 | 34 | roundingMode traits::RTP (void) { 35 | return roundingMode(solver->build_constant(2/*ieee_floatt::ROUND_TO_PLUS_INF*/, BITS)); 36 | } 37 | 38 | roundingMode traits::RTN (void) { 39 | return roundingMode(solver->build_constant(1/*ieee_floatt::ROUND_TO_MINUS_INF*/, BITS)); 40 | } 41 | 42 | roundingMode traits::RTZ (void) { 43 | return roundingMode(solver->build_constant(3/*ieee_floatt::ROUND_TO_ZERO*/, BITS)); 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /baseTypes/cprover_bvt.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** cprover_bvt.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 12/04/17 24 | ** 25 | ** Implement bit-vectors by generating CPROVER bit-vectors (bvt) 26 | ** 27 | */ 28 | 29 | // Symfpu headers 30 | #include "../utils/properties.h" 31 | #include "../utils/numberOfRoundingModes.h" 32 | #include "../core/ite.h" 33 | 34 | // CPROVER headers 35 | #include 36 | #include 37 | 38 | // Common components 39 | #include "cprover_common.h" 40 | 41 | #ifndef SYMFPU_CPROVER_BVT 42 | #define SYMFPU_CPROVER_BVT 43 | 44 | namespace symfpu { 45 | namespace cprover_bvt { 46 | 47 | typedef symfpu::cprover_common::bitWidthType bitWidthType; 48 | typedef symfpu::cprover_common::floatingPointTypeInfo floatingPointTypeInfo; 49 | 50 | // Forward declarations 51 | class roundingMode; 52 | class proposition; 53 | template class bitVector; 54 | 55 | // Wrap up the types into one template parameter 56 | class traits { 57 | public : 58 | typedef bitWidthType bwt; 59 | typedef roundingMode rm; 60 | typedef floatingPointTypeInfo fpt; 61 | typedef proposition prop; 62 | typedef bitVector< true> sbv; 63 | typedef bitVector ubv; 64 | 65 | static roundingMode RNE (void); 66 | static roundingMode RNA (void); 67 | static roundingMode RTP (void); 68 | static roundingMode RTN (void); 69 | static roundingMode RTZ (void); 70 | 71 | // Literal invariants 72 | inline static void precondition (const bool b) { assert(b); return; } 73 | inline static void postcondition (const bool b) { assert(b); return; } 74 | inline static void invariant (const bool b) { assert(b); return; } 75 | 76 | // Symbolic invariants 77 | // TODO : Add to the solver 78 | inline static void precondition(const prop &p) { return; } 79 | inline static void postcondition(const prop &p) { return; } 80 | inline static void invariant(const prop &p) { return; } 81 | 82 | }; 83 | 84 | // To simplify the property macros 85 | typedef traits t; 86 | 87 | // TODO : Fix this hack 88 | extern bv_utilst *solver; 89 | 90 | // (_ BitVec 1) version 91 | class proposition : public literalt { 92 | protected : 93 | friend ite; // For ITE 94 | 95 | public : 96 | proposition (const literalt l) : literalt(l) {} 97 | proposition (bool v) : literalt() { 98 | if (v) { 99 | make_true(); 100 | } else { 101 | make_false(); 102 | } 103 | } 104 | proposition (const proposition &old) : literalt(old) {} 105 | 106 | 107 | proposition operator ! (void) const { 108 | return proposition(this->literalt::operator!()); 109 | } 110 | 111 | proposition operator && (const proposition &op) const { 112 | return proposition(solver->prop.land(*this,op)); 113 | } 114 | 115 | proposition operator || (const proposition &op) const { 116 | return proposition(solver->prop.lor(*this,op)); 117 | } 118 | 119 | proposition operator == (const proposition &op) const { 120 | return proposition(solver->prop.lequal(*this,op)); 121 | } 122 | 123 | proposition operator ^ (const proposition &op) const { 124 | return proposition(solver->prop.lxor(*this,op)); 125 | } 126 | 127 | }; 128 | 129 | 130 | 131 | class roundingMode : public bvt { 132 | protected: 133 | friend ite; // For ITE 134 | 135 | public : 136 | roundingMode (const bvt &op) : bvt(op) {} 137 | roundingMode (const unsigned v) : bvt(solver->build_constant(v,32)) {} 138 | roundingMode (const roundingMode &old) : bvt(old) {} 139 | 140 | proposition valid (void) const { 141 | // TODO : Improve... 142 | return true; 143 | } 144 | 145 | proposition operator == (const roundingMode &op) const { 146 | return proposition(solver->equal(*this,op)); 147 | } 148 | 149 | }; 150 | 151 | 152 | 153 | template 154 | class bitVector : public bvt { 155 | protected : 156 | friend bitVector; // To allow conversion between the types 157 | friend ite >; // For ITE 158 | 159 | public : 160 | bitVector (const bitWidthType w, const unsigned v) : bvt(solver->build_constant(v,w)) {} 161 | bitVector (const bvt &old) : bvt(old) {} 162 | bitVector (const proposition &p) { push_back(p); } 163 | bitVector (const bitVector &old) : bvt(old) {} 164 | 165 | bitWidthType getWidth (void) const { 166 | return size(); 167 | } 168 | 169 | 170 | /*** Constant creation and test ***/ 171 | 172 | static bitVector one (const bitWidthType &w) { return bitVector(w,1); } 173 | static bitVector zero (const bitWidthType &w) { return bitVector(w,0); } 174 | static bitVector allOnes (const bitWidthType &w) { return ~zero(w); } 175 | 176 | 177 | inline proposition isAllOnes() const { return proposition(solver->is_all_ones(*this)); } 178 | inline proposition isAllZeros() const { return proposition(solver->is_zero(*this)); } 179 | 180 | static bitVector maxValue (const bitWidthType &w) { 181 | if (isSigned) { 182 | return zero(1).append(allOnes(w-1)); 183 | } else { 184 | return allOnes(w); 185 | } 186 | } 187 | 188 | static bitVector minValue (const bitWidthType &w) { 189 | if (isSigned) { 190 | return allOnes(w); 191 | } else { 192 | return zero(w); 193 | } 194 | } 195 | 196 | 197 | /*** Operators ***/ 198 | inline bitVector operator << (const bitVector &op) const { 199 | return bitVector(solver->shift(*this, bv_utilst::shiftt::LEFT, op)); 200 | } 201 | 202 | inline bitVector operator >> (const bitVector &op) const { 203 | return bitVector(solver->shift(*this, isSigned ? bv_utilst::shiftt::ARIGHT : bv_utilst::shiftt::LRIGHT, op)); 204 | } 205 | 206 | 207 | inline bitVector operator | (const bitVector &op) const { 208 | bitVector bv(*this); 209 | 210 | unsigned width = bv.size(); 211 | for(std::size_t i=0; iprop.lor(bv[i], op[i]); 213 | 214 | return bv; 215 | } 216 | 217 | inline bitVector operator & (const bitVector &op) const { 218 | bitVector bv(*this); 219 | 220 | unsigned width = bv.size(); 221 | for(std::size_t i=0; iprop.land(bv[i], op[i]); 223 | 224 | return bv; 225 | } 226 | 227 | inline bitVector operator + (const bitVector &op) const { 228 | return bitVector(solver->add(*this, op)); 229 | } 230 | 231 | inline bitVector operator - (const bitVector &op) const { 232 | return bitVector(solver->sub(*this, op)); 233 | } 234 | 235 | inline bitVector operator * (const bitVector &op) const { 236 | return bitVector(isSigned ? 237 | solver->signed_multiplier(*this, op) : 238 | solver->unsigned_multiplier(*this, op)); 239 | } 240 | 241 | inline bitVector operator / (const bitVector &op) const { 242 | return bitVector(solver->divider(*this, op, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 243 | } 244 | 245 | inline bitVector operator % (const bitVector &op) const { 246 | return bitVector(solver->remainder(*this, op, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 247 | } 248 | 249 | 250 | inline bitVector operator - (void) const { 251 | return bitVector(solver->negate(*this)); 252 | } 253 | 254 | inline bitVector operator ~ (void) const { 255 | bitVector bv(*this); 256 | 257 | unsigned width = bv.size(); 258 | for(std::size_t i=0; i increment () const { 265 | return bitVector(solver->inc(*this)); 266 | } 267 | 268 | inline bitVector decrement () const { 269 | return *this - bitVector::one(getWidth()); 270 | } 271 | 272 | inline bitVector signExtendRightShift (const bitVector &op) const { 273 | return bitVector(solver->shift(*this, bv_utilst::shiftt::ARIGHT, op)); 274 | } 275 | 276 | 277 | 278 | /*** Modular opertaions ***/ 279 | // No overflow checking so these are the same as other operations 280 | inline bitVector modularLeftShift (const bitVector &op) const { 281 | return *this << op; 282 | } 283 | 284 | inline bitVector modularRightShift (const bitVector &op) const { 285 | return *this >> op; 286 | } 287 | 288 | inline bitVector modularIncrement () const { 289 | return this->increment(); 290 | } 291 | 292 | inline bitVector modularDecrement () const { 293 | return this->decrement(); 294 | } 295 | 296 | inline bitVector modularAdd (const bitVector &op) const { 297 | return *this + op; 298 | } 299 | 300 | inline bitVector modularNegate () const { 301 | return -(*this); 302 | } 303 | 304 | 305 | 306 | 307 | /*** Comparisons ***/ 308 | 309 | inline proposition operator == (const bitVector &op) const { 310 | return proposition(solver->equal(*this, op)); 311 | } 312 | 313 | inline proposition operator <= (const bitVector &op) const { 314 | return proposition(solver->rel(*this, ID_le, op, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 315 | } 316 | 317 | inline proposition operator >= (const bitVector &op) const { 318 | return proposition(solver->rel(*this, ID_ge, op, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 319 | } 320 | 321 | inline proposition operator < (const bitVector &op) const { 322 | return proposition(solver->rel(*this, ID_lt, op, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 323 | } 324 | 325 | inline proposition operator > (const bitVector &op) const { 326 | return proposition(solver->rel(*this, ID_gt, op, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 327 | } 328 | 329 | /*** Type conversion ***/ 330 | // CPROVER bvts make no distinction between signed and unsigned, thus ... 331 | bitVector toSigned (void) const { 332 | return bitVector(*this); 333 | } 334 | bitVector toUnsigned (void) const { 335 | return bitVector(*this); 336 | } 337 | 338 | 339 | 340 | /*** Bit hacks ***/ 341 | 342 | inline bitVector extend (bitWidthType extension) const { 343 | return bitVector(solver->extension(*this, this->size() + extension, isSigned ? bv_utilst::representationt::SIGNED : bv_utilst::representationt::UNSIGNED)); 344 | } 345 | 346 | inline bitVector contract (bitWidthType reduction) const { 347 | bitVector bv(*this); 348 | bv.bvt::resize(bv.size() - reduction); 349 | return bv; 350 | } 351 | 352 | inline bitVector resize (bitWidthType newSize) const { 353 | bitWidthType width = this->getWidth(); 354 | 355 | if (newSize > width) { 356 | return this->extend(newSize - width); 357 | } else if (newSize < width) { 358 | return this->contract(width - newSize); 359 | } else { 360 | return *this; 361 | } 362 | } 363 | 364 | inline bitVector matchWidth (const bitVector &op) const { 365 | PRECONDITION(this->getWidth() <= op.getWidth()); 366 | return this->extend(op.getWidth() - this->getWidth()); 367 | } 368 | 369 | 370 | bitVector append(const bitVector &op) const { 371 | bitVector bv(op); 372 | 373 | bv.insert(bv.end(), this->begin(), this->end()); 374 | 375 | return bv; 376 | } 377 | 378 | // Inclusive of end points, thus if the same, extracts just one bit 379 | bitVector extract(bitWidthType upper, bitWidthType lower) const { 380 | PRECONDITION(upper >= lower); 381 | 382 | bitVector bv(upper-lower + 1, 0); 383 | 384 | for (bitWidthType i = lower; i <= upper; ++i) { 385 | bv[i - lower] = (*this)[i]; 386 | } 387 | 388 | return bv; 389 | } 390 | }; 391 | 392 | }; 393 | 394 | 395 | template <> 396 | struct ite { 397 | static const cprover_bvt::proposition iteOp (const cprover_bvt::proposition &cond, 398 | const cprover_bvt::proposition &l, 399 | const cprover_bvt::proposition &r) { 400 | return cprover_bvt::proposition(symfpu::cprover_bvt::solver->prop.lselect(cond,l,r)); 401 | } 402 | }; 403 | 404 | #define CPROVERBVTITEDFN(T) template <> \ 405 | struct ite { \ 406 | static const T iteOp (const cprover_bvt::proposition &cond, \ 407 | const T &l, \ 408 | const T &r) { \ 409 | assert(l.size() == r.size()); \ 410 | return T(symfpu::cprover_bvt::solver->select(cond,l,r)); \ 411 | } \ 412 | }; 413 | 414 | CPROVERBVTITEDFN(cprover_bvt::traits::rm); 415 | CPROVERBVTITEDFN(cprover_bvt::traits::sbv); 416 | CPROVERBVTITEDFN(cprover_bvt::traits::ubv); 417 | 418 | #undef CPROVERBVTITEDFN 419 | 420 | }; 421 | 422 | #endif 423 | -------------------------------------------------------------------------------- /baseTypes/cprover_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** cprover_common.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 24/06/17 24 | ** 25 | ** Common CPROVER components. 26 | ** 27 | */ 28 | 29 | // CPROVER headers 30 | #include 31 | 32 | #ifndef SYMFPU_CPROVER_COMMON 33 | #define SYMFPU_CPROVER_COMMON 34 | 35 | namespace symfpu { 36 | namespace cprover_common { 37 | 38 | typedef unsigned bitWidthType; 39 | 40 | 41 | class floatingPointTypeInfo : public ieee_float_spect { 42 | protected : 43 | //friend ite; // For ITE 44 | 45 | public : 46 | // CPROVER's format's significand doesn't include the hidden bit 47 | floatingPointTypeInfo(const ieee_float_spect &old) : ieee_float_spect(old) {} 48 | floatingPointTypeInfo(const floatbv_typet &t) : ieee_float_spect(t) {} 49 | floatingPointTypeInfo(unsigned exp, unsigned sig) : ieee_float_spect(sig - 1, exp) {} 50 | floatingPointTypeInfo(const floatingPointTypeInfo &old) : ieee_float_spect(old) {} 51 | 52 | bitWidthType exponentWidth(void) const { return this->e; } 53 | bitWidthType significandWidth(void) const { return this->f + 1; } 54 | 55 | bitWidthType packedWidth(void) const { return this->e + this->f + 1; } 56 | bitWidthType packedExponentWidth(void) const { return this->e; } 57 | bitWidthType packedSignificandWidth(void) const { return this->f; } 58 | }; 59 | 60 | }; 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /baseTypes/cprover_exprt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | #include "symfpu/baseTypes/cprover_exprt.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #define THERE_BE_DRAGONS 28 | 29 | #ifdef THERE_BE_DRAGONS 30 | // GCC needs LINKFLAGS="-rdynamic" to give function names in the backtrace 31 | #include 32 | #include 33 | #endif 34 | 35 | namespace symfpu { 36 | namespace cprover_exprt { 37 | 38 | #define BITS 32 39 | 40 | roundingMode traits::RNE (void) { 41 | return roundingMode(from_integer(0/*ieee_floatt::ROUND_TO_EVEN*/, signedbv_typet(BITS))); 42 | } 43 | 44 | roundingMode traits::RNA (void) { 45 | return roundingMode(from_integer(4, signedbv_typet(BITS))); 46 | } 47 | 48 | roundingMode traits::RTP (void) { 49 | return roundingMode(from_integer(2/*ieee_floatt::ROUND_TO_PLUS_INF*/, signedbv_typet(BITS))); 50 | } 51 | 52 | roundingMode traits::RTN (void) { 53 | return roundingMode(from_integer(1/*ieee_floatt::ROUND_TO_MINUS_INF*/, signedbv_typet(BITS))); 54 | } 55 | 56 | roundingMode traits::RTZ (void) { 57 | return roundingMode(from_integer(3/*ieee_floatt::ROUND_TO_ZERO*/, signedbv_typet(BITS))); 58 | } 59 | 60 | #ifdef THERE_BE_DRAGONS 61 | // The following code is evil and insane 62 | // It exists to add labels in code generated by boolbvt_graph.h 63 | 64 | struct demangledName { 65 | std::string path; 66 | std::string mangledName; 67 | std::string demangledName; 68 | std::string remainder; 69 | }; 70 | 71 | /// Attempts to demangle the function name assuming the glibc 72 | /// format of stack entry: 73 | /// 74 | /// path '(' mangledName '+' offset ') [' address ']\0' 75 | /// 76 | /// \param out: The output stream 77 | /// \param stack_entry: Description of the stack_entry 78 | /// 79 | /// \return True <=> the entry has been successfully demangled and printed. 80 | 81 | static demangledName demangle(const std::string &stack_entry) 82 | { 83 | demangledName return_value = {"Not found", "Not found", "Not found", stack_entry}; 84 | 85 | std::string working(stack_entry); 86 | 87 | std::string::size_type start=working.rfind('('); // Path may contain '(' ! 88 | std::string::size_type end=working.find('+', start); 89 | 90 | return_value.path = working.substr(0, start - 1); 91 | 92 | if(start!=std::string::npos && 93 | end!=std::string::npos && 94 | start+1<=end-1) 95 | { 96 | std::string::size_type length=end-(start+1); 97 | std::string mangled(working.substr(start+1, length)); 98 | return_value.mangledName = mangled; 99 | 100 | int demangle_success=1; 101 | char * demangled = 102 | abi::__cxa_demangle(mangled.c_str(), nullptr, nullptr, &demangle_success); 103 | 104 | if(demangle_success==0) 105 | { 106 | return_value.demangledName = demangled; 107 | } 108 | else 109 | { 110 | return_value.demangledName = "Demangle failed"; 111 | } 112 | } else { 113 | return_value.mangledName = "Mangled name not found"; 114 | return_value.demangledName = "Nothing to demangle"; 115 | } 116 | 117 | return_value.remainder = working.substr(end + 1); 118 | 119 | return return_value; 120 | } 121 | 122 | typedef std::pair creation_context; 123 | 124 | static creation_context find_creation_context (void) { 125 | void * stack[50] = {}; 126 | 127 | std::size_t entries = backtrace(stack, sizeof(stack) / sizeof(void *)); 128 | char **description = backtrace_symbols(stack, entries); 129 | 130 | std::string locationPrefix; 131 | std::string locationPostfix; 132 | 133 | // Start at the right place to avoid the C shim which doesn't decode 134 | #define MAGIC_START 4 135 | 136 | // Avoid the introspection of this code 137 | #define MAGIC_END 3 138 | for(std::size_t i=entries - MAGIC_START; i>MAGIC_END; i--) 139 | { 140 | demangledName d = demangle(description[i]); 141 | 142 | if (d.demangledName.find("symfpu::") == 0 && 143 | // !(d.demangledName.find("symfpu::cprover_exprt") == 0) && 144 | d.demangledName.find("symfpu::ite") == std::string::npos && 145 | d.demangledName.find("symfpu::ITE") == std::string::npos && 146 | d.demangledName.find("symfpu::unpackedFloat") != std::string::npos 147 | ) 148 | { 149 | locationPrefix += "subgraph \"cluster_" + d.demangledName + "\" {\n"; 150 | locationPrefix += "label = \"" + d.demangledName + "\"\n"; 151 | locationPostfix += "}\n"; 152 | } 153 | } 154 | free(description); 155 | 156 | return creation_context(locationPrefix, locationPostfix); 157 | } 158 | 159 | static void apply_creation_context_rec (const creation_context &ct, exprt &e) { 160 | e.set("#creation_open", ct.first); 161 | e.set("#creation_close", ct.second); 162 | 163 | // In some cases multiple exprts have been created between tags. 164 | // Naive recursion is bad! 165 | Forall_operands(e_it, e) 166 | { 167 | if (e_it->get_comments().find("#creation_open") == e_it->get_comments().end()) 168 | apply_creation_context_rec(ct, *e_it); 169 | } 170 | return; 171 | } 172 | 173 | static exprt apply_creation_context (const exprt &e) { 174 | creation_context ct = find_creation_context(); 175 | 176 | exprt ei(e); 177 | 178 | if (ct.first.empty()) 179 | return ei; 180 | 181 | apply_creation_context_rec(ct, ei); 182 | 183 | return ei; 184 | } 185 | 186 | #endif 187 | 188 | exprt proposition::tag (const exprt &e) const { 189 | #ifdef THERE_BE_DRAGONS 190 | if (boolbv_grapht::graph_enable) 191 | return apply_creation_context(e); 192 | #endif 193 | return e; 194 | } 195 | 196 | template 197 | exprt bitVector::tag (const exprt &e) const { 198 | #ifdef THERE_BE_DRAGONS 199 | if (boolbv_grapht::graph_enable) 200 | return apply_creation_context(e); 201 | #endif 202 | return e; 203 | } 204 | 205 | // Instantiate 206 | template exprt bitVector::tag (const exprt &e) const; 207 | template exprt bitVector::tag (const exprt &e) const; 208 | 209 | 210 | #define INLINESIMP 211 | 212 | // Inline simplification as simplify_expr does not scale 213 | 214 | 215 | // Just to reduce the visual clutter 216 | exprt simplify_local_constant_fold (const exprt e) { 217 | if (e.id() == ID_constant) { 218 | return e; 219 | 220 | } else { 221 | /* 222 | exprt check_target(e); 223 | 224 | while (check_target.id() == ID_typecast || 225 | check_target.id() == ID_extractbits) 226 | { 227 | check_target = check_target.op0(); 228 | } 229 | 230 | forall_operands(it, check_target) 231 | */ 232 | forall_operands(it, e) 233 | { 234 | if ((*it).id() != ID_constant) 235 | return e; 236 | } 237 | 238 | symbol_tablet s; 239 | namespacet n(s); 240 | return simplify_expr(e, n); 241 | } 242 | } 243 | 244 | 245 | exprt simplify_if (const if_exprt i) { 246 | const exprt cond(i.cond()); 247 | const exprt true_case(i.true_case()); 248 | const exprt false_case(i.false_case()); 249 | 250 | // Start with the simple ones 251 | if (cond.is_true() || (true_case == false_case)) { 252 | return true_case; 253 | 254 | } else if (cond.is_false()) { 255 | return false_case; 256 | 257 | } else { 258 | // Compact if's 259 | if (true_case.id() == ID_if) { 260 | if_exprt l(to_if_expr(true_case)); 261 | 262 | if (l.true_case() == false_case) { 263 | return simplify_if(if_exprt(and_exprt(cond, not_exprt(l.cond())), 264 | l.false_case(), 265 | false_case)); 266 | } else if (l.false_case() == false_case) { 267 | return simplify_if(if_exprt(and_exprt(cond, l.cond()), 268 | l.true_case(), 269 | false_case)); 270 | } 271 | 272 | } else if (false_case.id() == ID_if) { 273 | if_exprt l(to_if_expr(false_case)); 274 | 275 | if (l.true_case() == true_case) { 276 | return simplify_if(if_exprt(and_exprt(not_exprt(cond), not_exprt(l.cond())), 277 | l.false_case(), 278 | true_case)); 279 | } else if (l.false_case() == true_case) { 280 | return simplify_if(if_exprt(and_exprt(not_exprt(cond), l.cond()), 281 | l.true_case(), 282 | true_case)); 283 | } 284 | } 285 | } 286 | 287 | return i; 288 | } 289 | 290 | exprt proposition::simplify (const exprt &e) const { 291 | #ifndef INLINESIMP 292 | return e; 293 | #endif 294 | exprt r(simplify_local_constant_fold(e)); 295 | if (r.id() == ID_constant) 296 | return r; 297 | 298 | if (e.id() == ID_if) { 299 | exprt s(simplify_if(to_if_expr(e))); 300 | 301 | // Additional simplifications for Boolean things 302 | if (s.id() == ID_if) { 303 | if_exprt i(to_if_expr(s)); 304 | 305 | if (i.true_case().is_true()) { 306 | return simplify(or_exprt(i.cond(), i.false_case())); 307 | 308 | } else if (i.true_case().is_false()) { 309 | return simplify(and_exprt(not_exprt(i.cond()), i.false_case())); 310 | 311 | } else if (i.false_case().is_true()) { 312 | return simplify(or_exprt(not_exprt(i.cond()), i.true_case())); 313 | 314 | } else if (i.false_case().is_false()) { 315 | return simplify(and_exprt(i.cond(), i.true_case())); 316 | 317 | } 318 | 319 | assert(!i.cond().is_constant()); 320 | assert(!i.true_case().is_constant()); 321 | assert(!i.false_case().is_constant()); 322 | } 323 | 324 | return s; 325 | 326 | } else if (e.id() == ID_not) { 327 | if (e.op0().id() == ID_not) { 328 | return simplify(e.op0().op0()); 329 | } 330 | 331 | } else if (e.id() == ID_and) { 332 | exprt::operandst operands(e.operands()); 333 | 334 | size_t i = 0; 335 | while (i < operands.size()) { 336 | if (operands[i].is_true()) { 337 | operands.erase(operands.begin() + i); 338 | 339 | } else if (operands[i].is_false()) { 340 | return operands[i]; 341 | 342 | } else if (operands[i].id() == ID_and) { 343 | exprt::operandst appendMe(operands[i].operands()); 344 | for (size_t j = 0; j < appendMe.size(); ++j) { 345 | operands.push_back(appendMe[j]); 346 | } 347 | operands.erase(operands.begin() + i); 348 | 349 | } else if (operands[i].id() == ID_not && 350 | operands[i].op0().id() == ID_or) { 351 | exprt::operandst negateMe(operands[i].op0().operands()); 352 | for (size_t j = 0; j < negateMe.size(); ++j) { 353 | operands.push_back(not_exprt(negateMe[j])); 354 | } 355 | operands.erase(operands.begin() + i); 356 | 357 | } else { 358 | bool duplicate = false; 359 | 360 | for (size_t j = 0; j < i; ++j) { 361 | if (operands[j] == operands[i]) { 362 | duplicate = true; 363 | break; 364 | } 365 | } 366 | 367 | if (duplicate) { 368 | operands.erase(operands.begin() + i); 369 | } else { 370 | ++i; 371 | } 372 | } 373 | } 374 | 375 | if (operands.size() == 0) { 376 | return true_exprt(); 377 | } else if (operands.size() == 1) { 378 | return operands[0]; 379 | } else { 380 | return conjunction(operands); 381 | } 382 | 383 | } else if (e.id() == ID_or) { 384 | exprt::operandst operands(e.operands()); 385 | 386 | size_t i = 0; 387 | while (i < operands.size()) { 388 | if (operands[i].is_false()) { 389 | operands.erase(operands.begin() + i); 390 | 391 | } else if (operands[i].is_true()) { 392 | return operands[i]; 393 | 394 | } else if (operands[i].id() == ID_or) { 395 | exprt::operandst appendMe(operands[i].operands()); 396 | for (size_t j = 0; j < appendMe.size(); ++j) { 397 | operands.push_back(appendMe[j]); 398 | } 399 | operands.erase(operands.begin() + i); 400 | 401 | } else if (operands[i].id() == ID_not && 402 | operands[i].op0().id() == ID_and) { 403 | exprt::operandst negateMe(operands[i].op0().operands()); 404 | for (size_t j = 0; j < negateMe.size(); ++j) { 405 | operands.push_back(not_exprt(negateMe[j])); 406 | } 407 | operands.erase(operands.begin() + i); 408 | 409 | } else { 410 | bool duplicate = false; 411 | 412 | for (size_t j = 0; j < i; ++j) { 413 | if (operands[j] == operands[i]) { 414 | duplicate = true; 415 | break; 416 | } 417 | } 418 | 419 | if (duplicate) { 420 | operands.erase(operands.begin() + i); 421 | } else { 422 | ++i; 423 | } 424 | } 425 | } 426 | 427 | if (operands.size() == 0) { 428 | return false_exprt(); 429 | } else if (operands.size() == 1) { 430 | return operands[0]; 431 | } else { 432 | return disjunction(operands); 433 | } 434 | 435 | } else if (e.id() == ID_equal) { 436 | if (e.op0() == e.op1()) 437 | return true_exprt(); 438 | } 439 | 440 | return e; 441 | } 442 | 443 | template 444 | exprt bitVector::simplify (const exprt &e) const { 445 | #ifndef INLINESIMP 446 | return e; 447 | #endif 448 | 449 | exprt r(simplify_local_constant_fold(e)); 450 | if (r.id() == ID_constant) 451 | return r; 452 | 453 | if (e.id() == ID_if) { 454 | return simplify_if(to_if_expr(e)); 455 | } 456 | 457 | return e; 458 | } 459 | 460 | // Instantiate 461 | template exprt bitVector::simplify (const exprt &e) const; 462 | template exprt bitVector::simplify (const exprt &e) const; 463 | } 464 | 465 | 466 | // Use improved version of some of the operations 467 | #ifndef SYMFPU_WORDLEVEL_ENCODINGS 468 | template <> 469 | cprover_exprt::traits::ubv orderEncode (const cprover_exprt::traits::ubv &b) { 470 | return orderEncodeBitwise(b); 471 | } 472 | 473 | template <> 474 | stickyRightShiftResult stickyRightShift (const cprover_exprt::traits::ubv &input, const cprover_exprt::traits::ubv &shiftAmount) { 475 | return stickyRightShiftBitwise(input, shiftAmount); 476 | } 477 | #endif 478 | 479 | template <> 480 | void probabilityAnnotation (const cprover_exprt::traits::prop &p, const probability &pr) { 481 | boolbv_symfput::probablity_annotations.insert(std::make_pair(p, pr)); 482 | return; 483 | } 484 | 485 | } 486 | -------------------------------------------------------------------------------- /baseTypes/cprover_exprt.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** cprover_exprt.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 27/06/17 24 | ** 25 | ** Implement bit-vectors by generating CPROVER bit-vectors (bvt) 26 | ** 27 | */ 28 | 29 | // Symfpu headers 30 | #include "../utils/properties.h" 31 | #include "../utils/numberOfRoundingModes.h" 32 | #include "../core/ite.h" 33 | #include "../core/operations.h" 34 | 35 | // CPROVER headers 36 | #include 37 | #include 38 | #include 39 | 40 | // Common components 41 | #include "cprover_common.h" 42 | 43 | #ifndef SYMFPU_CPROVER_EXPRT 44 | #define SYMFPU_CPROVER_EXPRT 45 | 46 | namespace symfpu { 47 | namespace cprover_exprt { 48 | 49 | typedef symfpu::cprover_common::bitWidthType bitWidthType; 50 | typedef symfpu::cprover_common::floatingPointTypeInfo floatingPointTypeInfo; 51 | 52 | // Forward declarations 53 | class roundingMode; 54 | class proposition; 55 | template class bitVector; 56 | 57 | // Wrap up the types into one template parameter 58 | class traits { 59 | public : 60 | typedef bitWidthType bwt; 61 | typedef roundingMode rm; 62 | typedef floatingPointTypeInfo fpt; 63 | typedef proposition prop; 64 | typedef bitVector< true> sbv; 65 | typedef bitVector ubv; 66 | 67 | static roundingMode RNE (void); 68 | static roundingMode RNA (void); 69 | static roundingMode RTP (void); 70 | static roundingMode RTN (void); 71 | static roundingMode RTZ (void); 72 | 73 | // Literal invariants 74 | inline static void precondition (const bool b) { assert(b); return; } 75 | inline static void postcondition (const bool b) { assert(b); return; } 76 | inline static void invariant (const bool b) { assert(b); return; } 77 | 78 | // Symbolic invariants 79 | // TODO : Add to the solver 80 | inline static void precondition(const prop &p) { return; } 81 | inline static void postcondition(const prop &p) { return; } 82 | inline static void invariant(const prop &p) { return; } 83 | 84 | }; 85 | 86 | // To simplify the property macros 87 | typedef traits t; 88 | 89 | 90 | // exprt version using bools 91 | class proposition : public exprt { 92 | protected : 93 | friend ite; // For ITE 94 | 95 | exprt simplify (const exprt &e) const; 96 | exprt tag (const exprt &e) const; 97 | 98 | public : 99 | proposition (const exprt e) : exprt(tag(simplify(e))) {} 100 | proposition (bool v) : exprt(tag(v ? 101 | static_cast(true_exprt()) : 102 | static_cast(false_exprt()) )) {} 103 | proposition (const proposition &old) : exprt(old) {} 104 | 105 | 106 | proposition operator ! (void) const { 107 | return proposition(not_exprt(*this)); 108 | } 109 | 110 | proposition operator && (const proposition &op) const { 111 | return proposition(and_exprt(*this, op)); 112 | } 113 | 114 | proposition operator || (const proposition &op) const { 115 | return proposition(or_exprt(*this, op)); 116 | } 117 | 118 | proposition operator == (const proposition &op) const { 119 | return proposition(equal_exprt(*this, op)); 120 | } 121 | 122 | proposition operator ^ (const proposition &op) const { 123 | return proposition(equal_exprt(*this, not_exprt(op))); 124 | } 125 | }; 126 | 127 | 128 | 129 | class roundingMode : public exprt { 130 | protected: 131 | friend ite; // For ITE 132 | 133 | public : 134 | roundingMode (const exprt &op) : exprt(op) {} 135 | roundingMode (const unsigned v) : exprt(from_integer(v, signedbv_typet(32))) {} 136 | roundingMode (const roundingMode &old) : exprt(old) {} 137 | 138 | proposition valid (void) const { 139 | // TODO : Improve... 140 | return true; 141 | } 142 | 143 | proposition operator == (const roundingMode &op) const { 144 | return proposition(equal_exprt(*this, op)); 145 | } 146 | 147 | }; 148 | 149 | 150 | 151 | template 152 | class bitVector : public exprt { 153 | protected : 154 | friend bitVector; // To allow conversion between the types 155 | friend ite >; // For ITE 156 | 157 | exprt simplify (const exprt &e) const; 158 | exprt tag (const exprt &e) const; 159 | 160 | public : 161 | bitVector (const bitWidthType w, const unsigned v) : 162 | exprt(tag((isSigned) ? from_integer(v, signedbv_typet(w)) : from_integer(v, unsignedbv_typet(w)))) 163 | {} 164 | bitVector (const exprt &e) : exprt(tag(simplify(e))) {} 165 | bitVector (const proposition &p) : exprt(tag((isSigned) ? typecast_exprt(p, signedbv_typet(1)) : typecast_exprt(p, unsignedbv_typet(1)))) {} 166 | bitVector (const bitVector &old) : exprt(old) {} 167 | 168 | bitWidthType getWidth (void) const { 169 | if (isSigned) { 170 | return to_signedbv_type(this->type()).get_width(); 171 | } else { 172 | return to_unsignedbv_type(this->type()).get_width(); 173 | } 174 | } 175 | 176 | 177 | /*** Constant creation and test ***/ 178 | 179 | static bitVector one (const bitWidthType &w) { return bitVector(w,1); } 180 | static bitVector zero (const bitWidthType &w) { return bitVector(w,0); } 181 | static bitVector allOnes (const bitWidthType &w) { return ~zero(w); } 182 | 183 | 184 | inline proposition isAllOnes() const { return (*this) == allOnes(this->getWidth()); } 185 | inline proposition isAllZeros() const { return (*this) == zero(this->getWidth()); } 186 | 187 | static bitVector maxValue (const bitWidthType &w) { 188 | if (isSigned) { 189 | return signedbv_typet(w).largest_expr(); 190 | } else { 191 | return unsignedbv_typet(w).largest_expr(); 192 | } 193 | } 194 | 195 | static bitVector minValue (const bitWidthType &w) { 196 | if (isSigned) { 197 | return signedbv_typet(w).smallest_expr(); 198 | } else { 199 | return unsignedbv_typet(w).smallest_expr(); 200 | } 201 | } 202 | 203 | 204 | /*** Operators ***/ 205 | inline bitVector operator << (const bitVector &op) const { 206 | return bitVector(shl_exprt(*this, op)); 207 | } 208 | 209 | inline bitVector operator >> (const bitVector &op) const { 210 | if (isSigned) { 211 | return bitVector(ashr_exprt(*this, op)); 212 | } else { 213 | return bitVector(lshr_exprt(*this, op)); 214 | } 215 | } 216 | 217 | 218 | inline bitVector operator | (const bitVector &op) const { 219 | return bitVector(bitor_exprt(*this, op)); 220 | } 221 | 222 | inline bitVector operator & (const bitVector &op) const { 223 | return bitVector(bitand_exprt(*this, op)); 224 | } 225 | 226 | inline bitVector operator + (const bitVector &op) const { 227 | return bitVector(plus_exprt(*this, op)); 228 | } 229 | 230 | inline bitVector operator - (const bitVector &op) const { 231 | return bitVector(minus_exprt(*this, op)); 232 | } 233 | 234 | inline bitVector operator * (const bitVector &op) const { 235 | return bitVector(mult_exprt(*this, op)); 236 | } 237 | 238 | inline bitVector operator / (const bitVector &op) const { 239 | return bitVector(div_exprt(*this, op)); 240 | } 241 | 242 | inline bitVector operator % (const bitVector &op) const { 243 | return bitVector(mod_exprt(*this, op)); 244 | } 245 | 246 | 247 | inline bitVector operator - (void) const { 248 | return bitVector(unary_minus_exprt(*this)); 249 | } 250 | 251 | inline bitVector operator ~ (void) const { 252 | return bitVector(bitnot_exprt(*this)); 253 | } 254 | 255 | inline bitVector increment () const { 256 | return bitVector(*this + bitVector::one(getWidth())); 257 | } 258 | 259 | inline bitVector decrement () const { 260 | return bitVector(*this - bitVector::one(getWidth())); 261 | } 262 | 263 | inline bitVector signExtendRightShift (const bitVector &op) const { 264 | return bitVector(ashr_exprt(*this, op)); 265 | } 266 | 267 | 268 | 269 | /*** Modular opertaions ***/ 270 | // No overflow checking so these are the same as other operations 271 | inline bitVector modularLeftShift (const bitVector &op) const { 272 | return *this << op; 273 | } 274 | 275 | inline bitVector modularRightShift (const bitVector &op) const { 276 | return *this >> op; 277 | } 278 | 279 | inline bitVector modularIncrement () const { 280 | return this->increment(); 281 | } 282 | 283 | inline bitVector modularDecrement () const { 284 | return this->decrement(); 285 | } 286 | 287 | inline bitVector modularAdd (const bitVector &op) const { 288 | return *this + op; 289 | } 290 | 291 | inline bitVector modularNegate () const { 292 | return -(*this); 293 | } 294 | 295 | 296 | 297 | 298 | /*** Comparisons ***/ 299 | 300 | inline proposition operator == (const bitVector &op) const { 301 | return proposition(equal_exprt(*this, op)); 302 | } 303 | 304 | inline proposition operator <= (const bitVector &op) const { 305 | return proposition(binary_relation_exprt(*this, ID_le, op)); 306 | } 307 | 308 | inline proposition operator >= (const bitVector &op) const { 309 | return proposition(binary_relation_exprt(*this, ID_ge, op)); 310 | } 311 | 312 | inline proposition operator < (const bitVector &op) const { 313 | return proposition(binary_relation_exprt(*this, ID_lt, op)); 314 | } 315 | 316 | inline proposition operator > (const bitVector &op) const { 317 | return proposition(binary_relation_exprt(*this, ID_gt, op)); 318 | } 319 | 320 | /*** Type conversion ***/ 321 | // CPROVER bvts make no distinction between signed and unsigned, thus ... 322 | bitVector toSigned (void) const { 323 | return bitVector(typecast_exprt(*this, signedbv_typet(getWidth()))); 324 | } 325 | bitVector toUnsigned (void) const { 326 | return bitVector(typecast_exprt(*this, unsignedbv_typet(getWidth()))); 327 | } 328 | 329 | 330 | 331 | /*** Bit hacks ***/ 332 | 333 | inline bitVector extend (bitWidthType extension) const { 334 | if (isSigned) { 335 | return bitVector(typecast_exprt(*this, signedbv_typet(getWidth() + extension))); 336 | } else { 337 | return bitVector(typecast_exprt(*this, unsignedbv_typet(getWidth() + extension))); 338 | } 339 | } 340 | 341 | inline bitVector contract (bitWidthType reduction) const { 342 | if (isSigned) { 343 | return bitVector(typecast_exprt(*this, signedbv_typet(getWidth() - reduction))); 344 | } else { 345 | return bitVector(typecast_exprt(*this, unsignedbv_typet(getWidth() - reduction))); 346 | } 347 | } 348 | 349 | inline bitVector resize (bitWidthType newSize) const { 350 | bitWidthType width = this->getWidth(); 351 | 352 | if (newSize > width) { 353 | return this->extend(newSize - width); 354 | } else if (newSize < width) { 355 | return this->contract(width - newSize); 356 | } else { 357 | return *this; 358 | } 359 | } 360 | 361 | inline bitVector matchWidth (const bitVector &op) const { 362 | PRECONDITION(this->getWidth() <= op.getWidth()); 363 | return this->extend(op.getWidth() - this->getWidth()); 364 | } 365 | 366 | 367 | bitVector append(const bitVector &op) const { 368 | if (isSigned) { 369 | return bitVector(concatenation_exprt(*this, op, signedbv_typet(this->getWidth() + op.getWidth()))); 370 | } else { 371 | return bitVector(concatenation_exprt(*this, op, unsignedbv_typet(this->getWidth() + op.getWidth()))); 372 | } 373 | } 374 | 375 | // Inclusive of end points, thus if the same, extracts just one bit 376 | bitVector extract(bitWidthType upper, bitWidthType lower) const { 377 | PRECONDITION(upper >= lower); 378 | exprt u(bitVector(getWidth(),upper)); 379 | exprt l(bitVector(getWidth(),lower)); 380 | bitWidthType extractedWidth = upper - lower + 1; 381 | 382 | if (isSigned) { 383 | return bitVector(extractbits_exprt(*this, u, l, signedbv_typet(extractedWidth))); 384 | } else { 385 | return bitVector(extractbits_exprt(*this, u, l, unsignedbv_typet(extractedWidth))); 386 | } 387 | } 388 | }; 389 | 390 | }; 391 | 392 | 393 | template <> 394 | struct ite { 395 | static const cprover_exprt::proposition iteOp (const cprover_exprt::proposition &cond, 396 | const cprover_exprt::proposition &l, 397 | const cprover_exprt::proposition &r) { 398 | return cprover_exprt::proposition(if_exprt(cond, l, r)); 399 | } 400 | }; 401 | 402 | #define CPROVERBVTITEDFN(T) template <> \ 403 | struct ite { \ 404 | static const T iteOp (const cprover_exprt::proposition &cond, \ 405 | const T &l, \ 406 | const T &r) { \ 407 | assert(l.type() == r.type()); \ 408 | return T(if_exprt(cond,l,r)); \ 409 | } \ 410 | }; 411 | 412 | CPROVERBVTITEDFN(cprover_exprt::traits::rm); 413 | CPROVERBVTITEDFN(cprover_exprt::traits::sbv); 414 | CPROVERBVTITEDFN(cprover_exprt::traits::ubv); 415 | 416 | #undef CPROVERBVTITEDFN 417 | 418 | // Use improved version of some of the operations 419 | #ifndef SYMFPU_WORDLEVEL_ENCODINGS 420 | template <> 421 | cprover_exprt::traits::ubv orderEncode (const cprover_exprt::traits::ubv &b); 422 | 423 | template <> 424 | stickyRightShiftResult stickyRightShift (const cprover_exprt::traits::ubv &input, const cprover_exprt::traits::ubv &shiftAmount); 425 | #endif 426 | 427 | template <> 428 | void probabilityAnnotation (const cprover_exprt::traits::prop &p, const probability &pr); 429 | 430 | 431 | }; 432 | 433 | #endif 434 | -------------------------------------------------------------------------------- /baseTypes/cvc4_literal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** cvc4_literal.cpp 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 26/01/15 24 | ** 25 | ** Non-templated functions for linking. 26 | ** It's best not to ask how this is built... 27 | ** 28 | */ 29 | 30 | #include "base/cvc4_assert.h" 31 | 32 | // cvc4_literal.h needs definition from util/floatingpoint.h and is included in the middle of it 33 | #include "util/floatingpoint.h" 34 | #include "symfpu/baseTypes/cvc4_literal.h" 35 | 36 | 37 | namespace symfpu { 38 | namespace cvc4_literal { 39 | 40 | // To simplify the property macros 41 | typedef traits t; 42 | 43 | 44 | template 45 | bitVector bitVector::one (const bitWidthType &w) { return bitVector(w,1); } 46 | 47 | template 48 | bitVector bitVector::zero (const bitWidthType &w) { return bitVector(w,0); } 49 | 50 | template 51 | bitVector bitVector::allOnes (const bitWidthType &w) { return ~bitVector::zero(w); } 52 | 53 | template 54 | proposition bitVector::isAllOnes() const {return (*this == bitVector::allOnes(this->getWidth()));} 55 | template 56 | proposition bitVector::isAllZeros() const {return (*this == bitVector::zero(this->getWidth()));} 57 | 58 | 59 | template 60 | bitVector bitVector::maxValue (const bitWidthType &w) { 61 | if (isSigned) { 62 | CVC4BV base(w-1, 0U); 63 | return bitVector((~base).zeroExtend(1)); 64 | } else { 65 | return bitVector::allOnes(w); 66 | } 67 | } 68 | 69 | /* 70 | template <> 71 | bitVector bitVector::maxValue (const bitWidthType &w) { 72 | return bitVector::allOnes(w); 73 | } 74 | */ 75 | 76 | template 77 | bitVector bitVector::minValue (const bitWidthType &w) { 78 | if (isSigned) { 79 | CVC4BV base(w, 1U); 80 | CVC4BV shiftAmount(w, w-1); 81 | CVC4BV result(base.leftShift(shiftAmount)); 82 | return bitVector(result); 83 | } else { 84 | return bitVector::zero(w); 85 | } 86 | } 87 | 88 | 89 | 90 | /*** Operators ***/ 91 | template 92 | bitVector bitVector::operator << (const bitVector &op) const { 93 | return this->CVC4BV::leftShift(op); 94 | } 95 | 96 | template <> 97 | bitVector bitVector::operator >> (const bitVector &op) const { 98 | return this->CVC4BV::arithRightShift(op); 99 | } 100 | 101 | template <> 102 | bitVector bitVector::operator >> (const bitVector &op) const { 103 | return this->CVC4BV::logicalRightShift(op); 104 | } 105 | 106 | 107 | 108 | template 109 | bitVector bitVector::operator | (const bitVector &op) const { return this->CVC4BV::operator|(op); } 110 | 111 | template 112 | bitVector bitVector::operator & (const bitVector &op) const { return this->CVC4BV::operator&(op); } 113 | 114 | template 115 | bitVector bitVector::operator + (const bitVector &op) const { return this->CVC4BV::operator+(op); } 116 | 117 | template 118 | bitVector bitVector::operator - (const bitVector &op) const { return this->CVC4BV::operator-(op); } 119 | 120 | template 121 | bitVector bitVector::operator * (const bitVector &op) const { return this->CVC4BV::operator*(op); } 122 | 123 | template <> 124 | bitVector bitVector::operator / (const bitVector &op) const { return this->CVC4BV::unsignedDivTotal(op); } 125 | 126 | template <> 127 | bitVector bitVector::operator % (const bitVector &op) const { return this->CVC4BV::unsignedRemTotal(op); } 128 | 129 | template 130 | bitVector bitVector::operator - (void) const { return this->CVC4BV::operator-(); } 131 | 132 | template 133 | bitVector bitVector::operator ~ (void) const { return this->CVC4BV::operator~(); } 134 | 135 | template 136 | bitVector bitVector::increment () const { 137 | return *this + bitVector::one(this->getWidth()); 138 | } 139 | 140 | template 141 | bitVector bitVector::decrement () const { 142 | return *this - bitVector::one(this->getWidth()); 143 | } 144 | 145 | template 146 | bitVector bitVector::signExtendRightShift (const bitVector &op) const { 147 | return this->CVC4BV::arithRightShift(CVC4BV(this->getWidth(),op)); 148 | } 149 | 150 | 151 | 152 | /*** Modular opertaions ***/ 153 | // No overflow checking so these are the same as other operations 154 | template 155 | bitVector bitVector::modularLeftShift (const bitVector &op) const { 156 | return *this << op; 157 | } 158 | 159 | template 160 | bitVector bitVector::modularRightShift (const bitVector &op) const { 161 | return *this >> op; 162 | } 163 | 164 | template 165 | bitVector bitVector::modularIncrement () const { 166 | return this->increment(); 167 | } 168 | 169 | template 170 | bitVector bitVector::modularDecrement () const { 171 | return this->decrement(); 172 | } 173 | 174 | template 175 | bitVector bitVector::modularAdd (const bitVector &op) const { 176 | return *this + op; 177 | } 178 | 179 | template 180 | bitVector bitVector::modularNegate () const { 181 | return -(*this); 182 | } 183 | 184 | 185 | 186 | 187 | /*** Comparisons ***/ 188 | 189 | template 190 | proposition bitVector::operator == (const bitVector &op) const { return this->CVC4BV::operator==(op); } 191 | 192 | 193 | template <> 194 | proposition bitVector::operator <= (const bitVector &op) const { 195 | return this->signedLessThanEq(op); 196 | } 197 | 198 | template <> 199 | proposition bitVector::operator >= (const bitVector &op) const { 200 | return !(this->signedLessThan(op)); 201 | } 202 | 203 | template <> 204 | proposition bitVector::operator < (const bitVector &op) const { 205 | return this->signedLessThan(op); 206 | } 207 | 208 | template <> 209 | proposition bitVector::operator > (const bitVector &op) const { 210 | return !(this->signedLessThanEq(op)); 211 | } 212 | 213 | 214 | template <> 215 | proposition bitVector::operator <= (const bitVector &op) const { 216 | return this->unsignedLessThanEq(op); 217 | } 218 | 219 | template <> 220 | proposition bitVector::operator >= (const bitVector &op) const { 221 | return !(this->unsignedLessThan(op)); 222 | } 223 | 224 | template <> 225 | proposition bitVector::operator < (const bitVector &op) const { 226 | return this->unsignedLessThan(op); 227 | } 228 | 229 | template <> 230 | proposition bitVector::operator > (const bitVector &op) const { 231 | return !(this->unsignedLessThanEq(op)); 232 | } 233 | 234 | 235 | 236 | /*** Type conversion ***/ 237 | // CVC4 nodes make no distinction between signed and unsigned, thus ... 238 | template 239 | bitVector bitVector::toSigned (void) const { 240 | return bitVector(*this); 241 | } 242 | 243 | template 244 | bitVector bitVector::toUnsigned (void) const { 245 | return bitVector(*this); 246 | } 247 | 248 | 249 | 250 | /*** Bit hacks ***/ 251 | 252 | template 253 | bitVector bitVector::extend (bitWidthType extension) const { 254 | if (isSigned) { 255 | return this->CVC4BV::signExtend(extension); 256 | } else { 257 | return this->CVC4BV::zeroExtend(extension); 258 | } 259 | } 260 | 261 | template 262 | bitVector bitVector::contract (bitWidthType reduction) const { 263 | PRECONDITION(this->getWidth() > reduction); 264 | 265 | return this->extract((this->getWidth() - 1) - reduction, 0); 266 | } 267 | 268 | template 269 | bitVector bitVector::resize (bitWidthType newSize) const { 270 | bitWidthType width = this->getWidth(); 271 | 272 | if (newSize > width) { 273 | return this->extend(newSize - width); 274 | } else if (newSize < width) { 275 | return this->contract(width - newSize); 276 | } else { 277 | return *this; 278 | } 279 | } 280 | 281 | template 282 | bitVector bitVector::matchWidth (const bitVector &op) const { 283 | PRECONDITION(this->getWidth() <= op.getWidth()); 284 | return this->extend(op.getWidth() - this->getWidth()); 285 | } 286 | 287 | 288 | template 289 | bitVector bitVector::append(const bitVector &op) const { 290 | return this->CVC4BV::concat(op); 291 | } 292 | 293 | // Inclusive of end points, thus if the same, extracts just one bit 294 | template 295 | bitVector bitVector::extract(bitWidthType upper, bitWidthType lower) const { 296 | PRECONDITION(upper >= lower); 297 | return this->CVC4BV::extract(upper, lower); 298 | } 299 | 300 | 301 | // Explicit instantiation 302 | template class bitVector; 303 | template class bitVector; 304 | 305 | 306 | 307 | 308 | roundingMode traits::RNE (void) { return ::CVC4::roundNearestTiesToEven; }; 309 | roundingMode traits::RNA (void) { return ::CVC4::roundNearestTiesToAway; }; 310 | roundingMode traits::RTP (void) { return ::CVC4::roundTowardPositive; }; 311 | roundingMode traits::RTN (void) { return ::CVC4::roundTowardNegative; }; 312 | roundingMode traits::RTZ (void) { return ::CVC4::roundTowardZero; }; 313 | 314 | 315 | // This is a literal back-end so props are actually bools 316 | // so these can be handled in the same way as the internal assertions above 317 | 318 | void traits::precondition(const prop &p) { Assert(p); return; } 319 | void traits::postcondition(const prop &p) { Assert(p); return; } 320 | void traits::invariant(const prop &p) { Assert(p); return; } 321 | 322 | }; 323 | }; 324 | 325 | 326 | -------------------------------------------------------------------------------- /baseTypes/cvc4_literal.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** cvc4_literal.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 12/06/14 24 | ** 25 | ** There are two back-ends for CVC4, one literal and one symbolic. 26 | ** This is due to a quirk of the CVC4 infrastructure. Nodes can 27 | ** contain literals thus anything that is used to implement a literal 28 | ** type cannot contain a node or a massive circular definition 29 | ** snarl-up happens. Thus : two back ends. Not all systems will want 30 | ** or need this. 31 | ** 32 | ** This is the literal back-end which uses CVC4 literal datatypes to 33 | ** perform arbitrary precision floating-point computations. It is to 34 | ** implement the CVC4 literal floating-point type. 35 | ** 36 | ** It is intended to be included *in the middle* of util/floatingpoint.h 37 | ** 38 | */ 39 | 40 | // Symfpu headers 41 | #include "symfpu/utils/properties.h" 42 | #include "symfpu/utils/numberOfRoundingModes.h" 43 | #include "symfpu/core/ite.h" 44 | 45 | // CVC4 headers 46 | 47 | // Do not include util/floatingpoint.h as we are in the middle of it! 48 | //#include "util/floatingpoint.h" 49 | #include "util/bitvector.h" 50 | 51 | 52 | #ifndef SYMFPU_CVC4_LITERAL 53 | #define SYMFPU_CVC4_LITERAL 54 | 55 | #include 56 | 57 | namespace symfpu { 58 | namespace cvc4_literal { 59 | 60 | typedef unsigned bitWidthType; 61 | typedef bool proposition; 62 | typedef ::CVC4::RoundingMode roundingMode; 63 | typedef ::CVC4::FloatingPointSize floatingPointTypeInfo; 64 | 65 | // Forward declaration 66 | template class bitVector; 67 | 68 | // Wrap up the types into one template parameter 69 | class traits { 70 | public : 71 | typedef bitWidthType bwt; 72 | typedef roundingMode rm; 73 | typedef floatingPointTypeInfo fpt; 74 | typedef proposition prop; 75 | typedef bitVector< true> sbv; 76 | typedef bitVector ubv; 77 | 78 | static roundingMode RNE (void); 79 | static roundingMode RNA (void); 80 | static roundingMode RTP (void); 81 | static roundingMode RTN (void); 82 | static roundingMode RTZ (void); 83 | 84 | static void precondition(const prop &p); 85 | static void postcondition(const prop &p); 86 | static void invariant(const prop &p); 87 | }; 88 | 89 | 90 | 91 | 92 | // Type function 93 | template struct signedToLiteralType; 94 | 95 | template <> struct signedToLiteralType< true> { 96 | typedef int literalType; 97 | }; 98 | template <> struct signedToLiteralType { 99 | typedef unsigned int literalType; 100 | }; 101 | 102 | 103 | 104 | template 105 | class bitVector : public ::CVC4::BitVector { 106 | protected : 107 | typedef typename signedToLiteralType::literalType literalType; 108 | typedef ::CVC4::BitVector CVC4BV; 109 | 110 | friend bitVector; // To allow conversion between the types 111 | friend ite >; // For ITE 112 | 113 | 114 | public : 115 | bitVector (const bitWidthType w, const unsigned v) : CVC4BV(w,v) {} 116 | bitVector (const proposition &p) : CVC4BV(1,p ? 1U : 0U) {} 117 | bitVector (const bitVector &old) : CVC4BV(old) {} 118 | bitVector (const CVC4BV &old) : CVC4BV(old) {} 119 | 120 | 121 | bitWidthType getWidth (void) const { 122 | return getSize(); 123 | } 124 | 125 | 126 | /*** Constant creation and test ***/ 127 | 128 | static bitVector one (const bitWidthType &w); 129 | static bitVector zero (const bitWidthType &w); 130 | static bitVector allOnes (const bitWidthType &w); 131 | 132 | proposition isAllOnes() const; 133 | proposition isAllZeros() const; 134 | 135 | static bitVector maxValue (const bitWidthType &w); 136 | static bitVector minValue (const bitWidthType &w); 137 | 138 | 139 | /*** Operators ***/ 140 | bitVector operator << (const bitVector &op) const; 141 | bitVector operator >> (const bitVector &op) const; 142 | 143 | 144 | /* Inherited but ... 145 | * *sigh* if we use the inherited version then it will return a 146 | * CVC4::BitVector which can be converted back to a 147 | * bitVector but isn't done automatically when working 148 | * out types for templates instantiation. ITE is a particular 149 | * problem as expressions and constants no longer derive the 150 | * same type. There aren't any good solutions in C++, we could 151 | * use CRTP but Liana wouldn't appreciate that, so the following 152 | * pointless wrapping functions are needed. 153 | */ 154 | 155 | bitVector operator | (const bitVector &op) const; 156 | bitVector operator & (const bitVector &op) const; 157 | bitVector operator + (const bitVector &op) const; 158 | bitVector operator - (const bitVector &op) const; 159 | bitVector operator * (const bitVector &op) const; 160 | bitVector operator / (const bitVector &op) const; 161 | bitVector operator % (const bitVector &op) const; 162 | bitVector operator - (void) const; 163 | bitVector operator ~ (void) const; 164 | 165 | 166 | bitVector increment () const; 167 | bitVector decrement () const; 168 | bitVector signExtendRightShift (const bitVector &op) const; 169 | 170 | 171 | /*** Modular opertaions ***/ 172 | // No overflow checking so these are the same as other operations 173 | bitVector modularLeftShift (const bitVector &op) const; 174 | bitVector modularRightShift (const bitVector &op) const; 175 | bitVector modularIncrement () const; 176 | bitVector modularDecrement () const; 177 | bitVector modularAdd (const bitVector &op) const; 178 | bitVector modularNegate () const; 179 | 180 | 181 | 182 | /*** Comparisons ***/ 183 | 184 | /* Inherited ... ish ... */ 185 | proposition operator == (const bitVector &op) const; 186 | proposition operator <= (const bitVector &op) const; 187 | proposition operator >= (const bitVector &op) const; 188 | proposition operator < (const bitVector &op) const; 189 | proposition operator > (const bitVector &op) const; 190 | 191 | 192 | /*** Type conversion ***/ 193 | // CVC4 nodes make no distinction between signed and unsigned, thus ... 194 | bitVector toSigned (void) const; 195 | bitVector toUnsigned (void) const; 196 | 197 | 198 | /*** Bit hacks ***/ 199 | 200 | bitVector extend (bitWidthType extension) const; 201 | bitVector contract (bitWidthType reduction) const; 202 | bitVector resize (bitWidthType newSize) const; 203 | bitVector matchWidth (const bitVector &op) const; 204 | bitVector append(const bitVector &op) const; 205 | 206 | // Inclusive of end points, thus if the same, extracts just one bit 207 | bitVector extract(bitWidthType upper, bitWidthType lower) const; 208 | 209 | }; 210 | }; 211 | 212 | #define CVC4LITITEDFN(T) template <> \ 213 | struct ite { \ 214 | static const T & iteOp (const cvc4_literal::proposition &cond, \ 215 | const T &l, \ 216 | const T &r) { \ 217 | if (cond) { \ 218 | return l; \ 219 | } else { \ 220 | return r; \ 221 | } \ 222 | } \ 223 | } 224 | 225 | CVC4LITITEDFN(cvc4_literal::traits::rm); 226 | CVC4LITITEDFN(cvc4_literal::traits::prop); 227 | CVC4LITITEDFN(cvc4_literal::traits::sbv); 228 | CVC4LITITEDFN(cvc4_literal::traits::ubv); 229 | 230 | #undef CVC4LITITEDFN 231 | 232 | }; 233 | 234 | #endif 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /baseTypes/cvc4_symbolic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** cvc4_symbolic.cpp 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 05/01/15 24 | ** 25 | ** Non-templated functions for linking. 26 | ** It's best not to ask how this is built... 27 | ** 28 | */ 29 | 30 | #include "symfpu/baseTypes/cvc4_symbolic.h" 31 | 32 | // CVC4 headers 33 | #include "theory/fp/fp_converter.h" 34 | 35 | namespace symfpu { 36 | namespace cvc4_symbolic { 37 | 38 | roundingMode traits::RNE (void) { return roundingMode(0x01); }; 39 | roundingMode traits::RNA (void) { return roundingMode(0x02); }; 40 | roundingMode traits::RTP (void) { return roundingMode(0x04); }; 41 | roundingMode traits::RTN (void) { return roundingMode(0x08); }; 42 | roundingMode traits::RTZ (void) { return roundingMode(0x10); }; 43 | 44 | 45 | template <> 46 | bitVector bitVector::maxValue (const bitWidthType &w) { 47 | bitVector leadingZero(bitVector::zero(1)); 48 | bitVector base(bitVector::allOnes(w-1)); 49 | 50 | return bitVector(::CVC4::NodeManager::currentNM()->mkNode(::CVC4::kind::BITVECTOR_CONCAT, leadingZero.node, base.node)); 51 | } 52 | 53 | template <> 54 | bitVector bitVector::maxValue (const bitWidthType &w) { 55 | return bitVector::allOnes(w); 56 | } 57 | 58 | template <> 59 | bitVector bitVector::minValue (const bitWidthType &w) { 60 | bitVector leadingOne(bitVector::one(1)); 61 | bitVector base(bitVector::zero(w-1)); 62 | 63 | return bitVector(::CVC4::NodeManager::currentNM()->mkNode(::CVC4::kind::BITVECTOR_CONCAT, leadingOne.node, base.node)); 64 | } 65 | 66 | template <> 67 | bitVector bitVector::minValue (const bitWidthType &w) { 68 | return bitVector::zero(w); 69 | } 70 | 71 | }; 72 | 73 | template <> 74 | cvc4_symbolic::traits::ubv orderEncode (const cvc4_symbolic::traits::ubv &b) { 75 | return orderEncodeBitwise(b); 76 | } 77 | 78 | template <> 79 | stickyRightShiftResult stickyRightShift (const cvc4_symbolic::traits::ubv &input, const cvc4_symbolic::traits::ubv &shiftAmount) { 80 | return stickyRightShiftBitwise(input, shiftAmount); 81 | } 82 | 83 | template <> 84 | void probabilityAnnotation (const cvc4_symbolic::traits::prop &p, const probability &pr) { 85 | ::CVC4::theory::fp::FpConverter::currentConverter->registerProbabilityAnnotation(p.getNode(), pr); 86 | return; 87 | } 88 | 89 | }; 90 | -------------------------------------------------------------------------------- /baseTypes/shared.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** shared.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 11/04/17 24 | ** 25 | ** Things that are used by multiple back-ends. 26 | ** 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #ifndef SYMFPU_SHARED 33 | #define SYMFPU_SHARED 34 | 35 | namespace symfpu { 36 | namespace shared { 37 | 38 | 39 | // Must be able to contain the number of bit used in the bit-vector type to avoid overflow 40 | typedef uint64_t bitWidthType; 41 | 42 | // We can use bools for propositions 43 | typedef bool executable_proposition; 44 | 45 | // In SMT-LIB style -- significand includes hidden bit 46 | class floatingPointTypeInfo { 47 | private : 48 | bitWidthType exponentBits; 49 | bitWidthType significandBits; 50 | 51 | public : 52 | floatingPointTypeInfo (bitWidthType eb, bitWidthType sb) : exponentBits(eb), significandBits(sb) { 53 | assert(eb > 1); // Not precondition as we don't have a traits class to use 54 | assert(sb > 1); 55 | } 56 | 57 | floatingPointTypeInfo (const floatingPointTypeInfo &old) : 58 | exponentBits(old.exponentBits), significandBits(old.significandBits) {} 59 | 60 | floatingPointTypeInfo & operator= (const floatingPointTypeInfo &old) { 61 | this->exponentBits = old.exponentBits; 62 | this->significandBits = old.significandBits; 63 | 64 | return *this; 65 | } 66 | 67 | bitWidthType exponentWidth(void) const { return this->exponentBits; } 68 | bitWidthType significandWidth(void) const { return this->significandBits; } 69 | 70 | 71 | bitWidthType packedWidth(void) const { return this->exponentBits + this->significandBits; } 72 | bitWidthType packedExponentWidth(void) const { return this->exponentBits; } 73 | bitWidthType packedSignificandWidth(void) const { return this->significandBits - 1; } 74 | 75 | 76 | }; 77 | 78 | 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /baseTypes/simpleExecutable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** simpleExecutable.cpp 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 07/08/14 24 | ** 25 | ** The most simple executable implementation of bit-vectors. 26 | ** Limited in the ranges it supports but fast and suitable for reasoning. 27 | ** 28 | */ 29 | 30 | 31 | #include "symfpu/baseTypes/simpleExecutable.h" 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | namespace symfpu { 38 | namespace simpleExecutable { 39 | 40 | 41 | // This would all be much easier if C++ allowed partial specialisation of member templates... 42 | 43 | template <> 44 | bool bitVector::isRepresentable (const bitWidthType w, const int64_t v) { 45 | uint64_t shiftSafe = *((uint64_t *)(&v)); 46 | uint64_t top = (shiftSafe >> w); 47 | uint64_t signbit = shiftSafe & 0x8000000000000000; 48 | int64_t stop = *((int64_t *)(&top)); 49 | return (signbit) ? (stop == bitVector::nOnes(bitVector::maxWidth() - w)) : (stop == 0LL); 50 | } 51 | 52 | template <> 53 | bool bitVector::isRepresentable (const bitWidthType w, const uint64_t v) { 54 | uint64_t top = (v >> w); 55 | return (top == 0); 56 | } 57 | 58 | 59 | template <> 60 | uint64_t bitVector::makeRepresentable (const bitWidthType w, const uint64_t v) { 61 | return v & bitVector::nOnes(w); 62 | } 63 | 64 | template <> 65 | int64_t bitVector::makeRepresentable (const bitWidthType w, const int64_t v) { 66 | if (v <= ((1LL << (w - 1)) - 1) && (-(1LL << (w - 1)) <= v)) { 67 | return v; 68 | } else { 69 | return 0; 70 | } 71 | } 72 | 73 | 74 | template <> 75 | bitVector bitVector::maxValue (const bitWidthType &w) { 76 | PRECONDITION(w != 1); 77 | return bitVector(w, (1ULL << (w - 1)) - 1); 78 | } 79 | 80 | template <> 81 | bitVector bitVector::maxValue (const bitWidthType &w) { 82 | PRECONDITION(w != 1); 83 | return bitVector(w, (1ULL << w) - 1); 84 | } 85 | 86 | template <> 87 | bitVector bitVector::minValue (const bitWidthType &w) { 88 | PRECONDITION(w != 1); 89 | return bitVector(w, -(1ULL << (w - 1))); 90 | } 91 | 92 | template <> 93 | bitVector bitVector::minValue (const bitWidthType &w) { 94 | return bitVector(w, 0); 95 | } 96 | 97 | 98 | template <> 99 | bitVector bitVector::operator- (void) const { 100 | return bitVector(this->width, -this->value); 101 | } 102 | 103 | // Used in addition 104 | template <> 105 | bitVector bitVector::operator- (void) const { 106 | return bitVector(this->width, 107 | bitVector::makeRepresentable(this->width, (~this->value) + 1)); 108 | } 109 | 110 | template <> 111 | bitVector bitVector::operator~ (void) const { 112 | return bitVector(this->width, 113 | bitVector::makeRepresentable(this->width, ~this->value)); 114 | } 115 | 116 | 117 | // This is wrong in the signed case as the sign bit it tracks and the sign bit in int64_t are in different places! 118 | static uint64_t stickyRightShift(const bool value, const bitWidthType width, const uint64_t left, const uint64_t right) { 119 | //uint64_t bitsInWord = bitVector::maxWidth(); 120 | uint64_t newValue = left; 121 | uint64_t stickyBit = 0; 122 | uint64_t signBit = left & (1ULL << (width - 1)); 123 | 124 | if (right <= width) { 125 | for (uint64_t i = 1; i <= width; i <<= 1) { 126 | if (right & i) { 127 | uint64_t iOnes = ((1ULL << i) - 1); 128 | stickyBit |= ((newValue & iOnes) ? 1 : 0); 129 | 130 | // Sign extending shift 131 | if (signBit) { 132 | newValue = (newValue >> i) | (iOnes << (width - i)); 133 | } else { 134 | newValue = (newValue >> i); 135 | } 136 | 137 | } 138 | } 139 | } else { 140 | newValue = (signBit) ? 0xFFFFFFFFFFFFFFFFULL : 0x0; 141 | stickyBit = (left) ? 0x1 : 0x0; 142 | } 143 | 144 | return (value) ? newValue : stickyBit; 145 | } 146 | 147 | 148 | 149 | template <> 150 | bitVector bitVector::signExtendRightShift (const bitVector &op) const { 151 | PRECONDITION(this->width == op.width); 152 | return bitVector(this->width, 153 | bitVector::makeRepresentable(this->width, 154 | stickyRightShift(true, this->width, this->value, op.value))); 155 | } 156 | 157 | template <> 158 | bitVector bitVector::signExtendRightShift (const bitVector &op) const { 159 | PRECONDITION(this->width == op.width); 160 | PRECONDITION(this->width < CHAR_BIT*sizeof(int64_t)); 161 | 162 | int64_t newValue; 163 | 164 | if (this->value < 0) { 165 | newValue = -(-(this->value) >> op.value) + ((this->value & 0x1) ? -1 : 0); // Rounds away 166 | } else { 167 | newValue = this->value >> op.value; 168 | } 169 | 170 | return bitVector(this->width, 171 | bitVector::makeRepresentable(this->width, newValue)); 172 | } 173 | 174 | template<> 175 | bitVector bitVector::modularLeftShift (const bitVector &op) const { 176 | PRECONDITION(this->width == op.width); 177 | return bitVector(this->width, 178 | bitVector::makeRepresentable(this->width, 179 | (op.value >= this->width) ? 0ULL : this->value << op.value)); 180 | } 181 | 182 | template<> 183 | bitVector bitVector::modularRightShift (const bitVector &op) const { 184 | PRECONDITION(this->width == op.width); 185 | return bitVector(this->width, 186 | bitVector::makeRepresentable(this->width, 187 | (op.value >= this->width) ? 0ULL : this->value >> op.value)); 188 | } 189 | 190 | 191 | template <> 192 | bitVector bitVector::modularNegate (void) const { 193 | return bitVector(this->width, 194 | bitVector::makeRepresentable(this->width, ~this->value + 1)); 195 | } 196 | 197 | template <> 198 | bitVector bitVector::modularNegate (void) const { 199 | return bitVector(this->width, 200 | bitVector::makeRepresentable(this->width, -this->value)); 201 | } 202 | 203 | 204 | // Only instantiated for unsigned 205 | template <> 206 | bitVector bitVector::extract(bitWidthType upper, bitWidthType lower) const { 207 | PRECONDITION(this->width > upper); 208 | PRECONDITION(upper >= lower); 209 | 210 | bitWidthType newLength = (upper - lower) + 1; 211 | 212 | return bitVector(newLength, 213 | bitVector::makeRepresentable(newLength, (this->value >> lower))); 214 | } 215 | 216 | template <> 217 | bitVector bitVector::append(const bitVector &op) const { 218 | PRECONDITION(this->width + op.width <= bitVector::maxWidth()); 219 | 220 | return bitVector(this->width + op.width, this->value << op.width | op.value); 221 | } 222 | 223 | 224 | 225 | template <> 226 | bitVector::signedVersion> bitVector::toSigned (void) const { 227 | return bitVector(this->width, *((int64_t *)&this->value)); 228 | } 229 | 230 | template <> 231 | bitVector::unsignedVersion> bitVector::toUnsigned (void) const { 232 | // Note we need to mask out the (sign extensions) of the negative part. 233 | return bitVector(this->width, (*((uint64_t *)&this->value)) & bitVector::nOnes(this->width)); 234 | } 235 | 236 | 237 | roundingMode traits::RNE (void) { return roundingMode(FE_TONEAREST); } 238 | roundingMode traits::RNA (void) { return roundingMode(23); } // Could be better... 239 | roundingMode traits::RTP (void) { return roundingMode(FE_UPWARD); } 240 | roundingMode traits::RTN (void) { return roundingMode(FE_DOWNWARD); } 241 | roundingMode traits::RTZ (void) { return roundingMode(FE_TOWARDZERO); } 242 | 243 | } 244 | 245 | #if 0 246 | template <> 247 | simpleExecutable::traits::ubv orderEncode (const simpleExecutable::traits::ubv &b) { 248 | return orderEncodeBitwise(b); 249 | } 250 | #endif 251 | 252 | } 253 | -------------------------------------------------------------------------------- /baseTypes/simpleExecutable.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** simpleExecutable.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 03/06/14 24 | ** 25 | ** The most simple executable implementation of bit-vectors. 26 | ** Limited in the ranges it supports but fast and suitable for reasoning. 27 | ** 28 | ** Unless otherwise stated, bit operations require all operands to have the 29 | ** same widths and the result will have the same width (SMT-LIB style, 30 | ** but see the 'expanding' instructions below). Also underflow and 31 | ** overflow are considered errors (unlike SMT-LIB but see the 'modular' instructions 32 | ** below) although error checking is not perfect as overflows in the 33 | ** underlying data type can mask errors. 34 | ** 35 | */ 36 | 37 | #include "symfpu/utils/properties.h" 38 | #include "symfpu/core/ite.h" 39 | #include "symfpu/baseTypes/shared.h" 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #ifndef SYMFPU_SIMPLE_EXECUTABLE 46 | #define SYMFPU_SIMPLE_EXECUTABLE 47 | 48 | namespace symfpu { 49 | namespace simpleExecutable { 50 | 51 | typedef symfpu::shared::bitWidthType bitWidthType; 52 | typedef symfpu::shared::executable_proposition proposition; 53 | typedef symfpu::shared::floatingPointTypeInfo floatingPointTypeInfo; 54 | 55 | // Forwards definitions 56 | class roundingMode; 57 | template class bitVector; 58 | 59 | 60 | // This is the class that is used as a template argument 61 | class traits { 62 | public : 63 | typedef bitWidthType bwt; 64 | typedef roundingMode rm; 65 | typedef floatingPointTypeInfo fpt; 66 | typedef proposition prop; 67 | typedef bitVector< int64_t> sbv; 68 | typedef bitVector ubv; 69 | 70 | static roundingMode RNE(void); 71 | static roundingMode RNA(void); 72 | static roundingMode RTP(void); 73 | static roundingMode RTN(void); 74 | static roundingMode RTZ(void); 75 | 76 | // As prop == bool only one set of these is needed 77 | inline static void precondition(const bool b) { assert(b); return; } 78 | inline static void postcondition(const bool b) { assert(b); return; } 79 | inline static void invariant(const bool b) { assert(b); return; } 80 | 81 | }; 82 | 83 | // To simplify the property macros 84 | typedef traits t; 85 | 86 | 87 | 88 | class roundingMode { 89 | private : 90 | int value; 91 | 92 | public : 93 | roundingMode (int v) : value(v) {} 94 | roundingMode (const roundingMode &old) : value(old.value) {} 95 | 96 | roundingMode & operator = (const roundingMode &op) { 97 | this->value = op.value; 98 | return (*this); 99 | } 100 | 101 | proposition operator == (const roundingMode &op) const { 102 | return proposition(this->value == op.value); 103 | } 104 | 105 | // Only for executable back-ends 106 | int getValue (void) const { 107 | return this->value; 108 | } 109 | }; 110 | 111 | 112 | 113 | template struct modifySignedness; 114 | 115 | template <> struct modifySignedness< int64_t> { 116 | typedef uint64_t unsignedVersion; 117 | typedef int64_t signedVersion; 118 | }; 119 | template <> struct modifySignedness { 120 | typedef uint64_t unsignedVersion; 121 | typedef int64_t signedVersion; 122 | }; 123 | 124 | 125 | 126 | template 127 | class bitVector { 128 | protected : 129 | bitWidthType width; 130 | T value; 131 | 132 | static bitWidthType maxWidth (void) { 133 | return sizeof(T)*CHAR_BIT; 134 | } 135 | 136 | static T nOnes (bitWidthType n) { 137 | if (n == 0) { 138 | return 0; 139 | } else { 140 | // Not (1 << n) - 1 to avoid overflow for n = maxWidth() 141 | bitWidthType shift = bitVector::maxWidth() - n; 142 | return ((~0ULL) << shift) >> shift; 143 | } 144 | } 145 | 146 | // Bit vectors should store values in 2's complement using the full width 147 | // (and thus may have significant bits outside the width). 148 | // Thus need to make sure the value stored is representable within 149 | // bit-vectors of the specified width. 150 | static bool isRepresentable (const bitWidthType w, const T v); 151 | 152 | // Modular operations need to reduce operations back to 153 | // something representable. 154 | static T makeRepresentable (const bitWidthType w, const T v); 155 | 156 | 157 | public : 158 | 159 | // Ideally should protect but is used in subnormal rounding 160 | bitVector (const bitWidthType w, const T v) : width(w), value(v) 161 | { 162 | PRECONDITION(width <= bitVector::maxWidth()); 163 | PRECONDITION(0 < width); 164 | PRECONDITION(bitVector::isRepresentable(w,v)); 165 | } 166 | 167 | bitVector (const proposition &p) : width(1), value(p) {} 168 | 169 | bitVector (const bitVector &old) : width(old.width), value(old.value) {} 170 | 171 | // Constructors 172 | // non-det on other instances but not this so that 173 | // instantiation catches this 174 | 175 | 176 | 177 | 178 | bitWidthType getWidth (void) const { 179 | return this->width; 180 | } 181 | 182 | // Would it be better to not have this and only have copy? 183 | bitVector & operator= (const bitVector &op) { 184 | PRECONDITION(op.width == this->width); 185 | 186 | this->value = op.value; 187 | 188 | return (*this); 189 | } 190 | 191 | 192 | /*** Constant creation and test ***/ 193 | 194 | static bitVector one (const bitWidthType &w) { return bitVector(w,1); } 195 | static bitVector zero (const bitWidthType &w) { return bitVector(w,0); } 196 | static bitVector allOnes (const bitWidthType &w) { return bitVector(w,bitVector::nOnes(w)); } 197 | 198 | inline proposition isAllOnes() const {return proposition(((~this->value) & nOnes(this->width)) == 0);} 199 | inline proposition isAllZeros() const {return proposition(this->value == 0);} 200 | 201 | static bitVector maxValue (const bitWidthType &w); 202 | static bitVector minValue (const bitWidthType &w); 203 | 204 | /*** Operators ***/ 205 | // Need to inline the operations where possible 206 | inline bitVector operator << (const bitVector &op) const { 207 | PRECONDITION(this->width == op.width); 208 | PRECONDITION(op.value >= 0U && op.value < (T)this->width); 209 | return bitVector(this->width, this->value << op.value); 210 | } 211 | 212 | inline bitVector operator >> (const bitVector &op) const { 213 | PRECONDITION(this->width == op.width); 214 | PRECONDITION(op.value >= 0U && op.value < (T)this->width); 215 | return bitVector(this->width, this->value >> op.value); 216 | } 217 | 218 | inline bitVector operator | (const bitVector &op) const { 219 | PRECONDITION(this->width == op.width); 220 | return bitVector(this->width, this->value | op.value); 221 | } 222 | 223 | inline bitVector operator & (const bitVector &op) const { 224 | PRECONDITION(this->width == op.width); 225 | return bitVector(this->width, this->value & op.value); 226 | } 227 | 228 | inline bitVector operator + (const bitVector &op) const { 229 | PRECONDITION(this->width == op.width); 230 | return bitVector(this->width, this->value + op.value); 231 | } 232 | 233 | inline bitVector operator - (const bitVector &op) const { 234 | PRECONDITION(this->width == op.width); 235 | return bitVector(this->width, this->value - op.value); 236 | } 237 | 238 | inline bitVector operator * (const bitVector &op) const { 239 | PRECONDITION(this->width == op.width); 240 | return bitVector(this->width, this->value * op.value); 241 | } 242 | 243 | inline bitVector operator / (const bitVector &op) const { 244 | PRECONDITION(op.value != 0); 245 | PRECONDITION(this->width == op.width); 246 | return bitVector(this->width, this->value / op.value); 247 | } 248 | 249 | inline bitVector operator % (const bitVector &op) const { 250 | PRECONDITION(op.value != 0); 251 | PRECONDITION(this->width == op.width); 252 | return bitVector(this->width, this->value % op.value); 253 | } 254 | 255 | bitVector operator - (void) const; 256 | bitVector operator ~ (void) const; 257 | 258 | inline bitVector increment () const { 259 | return bitVector(this->width, this->value + 1); 260 | } 261 | 262 | inline bitVector decrement () const { 263 | return bitVector(this->width, this->value - 1); 264 | } 265 | 266 | bitVector signExtendRightShift (const bitVector &op) const; 267 | 268 | 269 | /*** Modular operations ***/ 270 | bitVector modularLeftShift (const bitVector &op) const; 271 | bitVector modularRightShift (const bitVector &op) const; 272 | 273 | inline bitVector modularIncrement () const { 274 | return bitVector(this->width, 275 | bitVector::makeRepresentable(this->width, this->value + 1)); 276 | } 277 | 278 | inline bitVector modularDecrement () const { 279 | return bitVector(this->width, 280 | bitVector::makeRepresentable(this->width, this->value - 1)); 281 | } 282 | 283 | inline bitVector modularAdd (const bitVector &op) const { 284 | return bitVector(this->width, 285 | bitVector::makeRepresentable(this->width, 286 | this->value + op.value)); 287 | } 288 | 289 | bitVector modularNegate () const; 290 | 291 | 292 | 293 | 294 | /*** Comparisons ***/ 295 | 296 | inline proposition operator == (const bitVector &op) const { 297 | PRECONDITION(this->width == op.width); 298 | return proposition(this->value == op.value); 299 | } 300 | 301 | inline proposition operator <= (const bitVector &op) const { 302 | PRECONDITION(this->width == op.width); 303 | return proposition(this->value <= op.value); 304 | } 305 | 306 | inline proposition operator >= (const bitVector &op) const { 307 | PRECONDITION(this->width == op.width); 308 | return proposition(this->value >= op.value); 309 | } 310 | 311 | inline proposition operator < (const bitVector &op) const { 312 | PRECONDITION(this->width == op.width); 313 | return proposition(this->value < op.value); 314 | } 315 | 316 | inline proposition operator > (const bitVector &op) const { 317 | PRECONDITION(this->width == op.width); 318 | return proposition(this->value > op.value); 319 | } 320 | 321 | 322 | /*** Type conversion ***/ 323 | 324 | bitVector::signedVersion> toSigned (void) const; 325 | bitVector::unsignedVersion> toUnsigned (void) const; 326 | 327 | 328 | 329 | /*** Bit hacks ***/ 330 | 331 | inline bitVector extend (bitWidthType extension) const { 332 | PRECONDITION(this->width + extension <= bitVector::maxWidth()); 333 | 334 | // No extension needed, even in the signed case as already correctly represented 335 | return bitVector(this->width + extension, this->value); 336 | } 337 | 338 | inline bitVector contract (bitWidthType reduction) const { 339 | PRECONDITION(this->width > reduction); 340 | 341 | return bitVector(this->width - reduction, this->value); 342 | } 343 | 344 | inline bitVector resize (bitWidthType newSize) const { 345 | return bitVector(newSize, 346 | bitVector::makeRepresentable(newSize, this->value)); 347 | } 348 | 349 | inline bitVector matchWidth (const bitVector &op) const { 350 | PRECONDITION(this->width <= op.width); 351 | return this->extend(op.width - this->width); 352 | } 353 | 354 | 355 | 356 | bitVector append(const bitVector &op) const; 357 | 358 | // Inclusive of end points, thus if the same, extracts just one bit 359 | bitVector extract(bitWidthType upper, bitWidthType lower) const; 360 | 361 | // Only meaningful for executable implementations 362 | T contents (void) const { return this->value; } 363 | 364 | }; 365 | 366 | } 367 | 368 | 369 | #define SEITEDFN(T) template <> \ 370 | struct ite { \ 371 | static const T & iteOp (const simpleExecutable::traits::prop &cond, \ 372 | const T &l, \ 373 | const T &r) { \ 374 | if (cond) { \ 375 | return l; \ 376 | } else { \ 377 | return r; \ 378 | } \ 379 | } \ 380 | } 381 | 382 | SEITEDFN(simpleExecutable::traits::rm); 383 | SEITEDFN(simpleExecutable::traits::prop); 384 | 385 | #undef SEITEDFN 386 | 387 | #define SEITEDFNW(T) template <> \ 388 | struct ite { \ 389 | static const T & iteOp (const simpleExecutable::traits::prop &cond, \ 390 | const T &l, \ 391 | const T &r) { \ 392 | assert(l.getWidth() == r.getWidth()); \ 393 | \ 394 | if (cond) { \ 395 | return l; \ 396 | } else { \ 397 | return r; \ 398 | } \ 399 | } \ 400 | } 401 | 402 | SEITEDFNW(simpleExecutable::traits::sbv); 403 | SEITEDFNW(simpleExecutable::traits::ubv); 404 | 405 | #undef SEITEDFNW 406 | 407 | } 408 | 409 | 410 | // For testing only; bitwise implementation is way slower for software 411 | #if 0 412 | #include "../core/operations.h" 413 | 414 | namespace symfpu { 415 | 416 | template <> 417 | simpleExecutable::traits::ubv orderEncode (const simpleExecutable::traits::ubv &b); 418 | 419 | } 420 | #endif 421 | 422 | 423 | #endif 424 | -------------------------------------------------------------------------------- /core/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags 2 | CXXFLAGS+=-I../ 3 | ALL= 4 | .PHONY : all 5 | 6 | all : $(ALL) 7 | 8 | %.o : %.cpp 9 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 10 | 11 | -------------------------------------------------------------------------------- /core/classify.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** classify.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 21/08/14 24 | ** 25 | ** The classification functions for different classes of float. 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | 31 | #ifndef SYMFPU_CLASSIFY 32 | #define SYMFPU_CLASSIFY 33 | 34 | namespace symfpu { 35 | 36 | template 37 | typename t::prop isNormal (const typename t::fpt &format, const unpackedFloat &uf) { 38 | PRECONDITION(uf.valid(format)); 39 | 40 | return !uf.getNaN() && !uf.getInf() && !uf.getZero() && uf.inNormalRange(format, typename t::prop(true)); 41 | } 42 | 43 | 44 | template 45 | typename t::prop isSubnormal (const typename t::fpt &format, const unpackedFloat &uf) { 46 | PRECONDITION(uf.valid(format)); 47 | 48 | return !uf.getNaN() && !uf.getInf() && !uf.getZero() && uf.inSubnormalRange(format, typename t::prop(true)); 49 | } 50 | 51 | 52 | template 53 | typename t::prop isZero (const typename t::fpt &format, const unpackedFloat &uf) { 54 | PRECONDITION(uf.valid(format)); 55 | 56 | return uf.getZero(); 57 | } 58 | 59 | 60 | template 61 | typename t::prop isInfinite (const typename t::fpt &format, const unpackedFloat &uf) { 62 | PRECONDITION(uf.valid(format)); 63 | 64 | return uf.getInf(); 65 | } 66 | 67 | 68 | template 69 | typename t::prop isNaN (const typename t::fpt &format, const unpackedFloat &uf) { 70 | PRECONDITION(uf.valid(format)); 71 | 72 | return uf.getNaN(); 73 | } 74 | 75 | 76 | // Note these are the SMT-LIB semantics, NaN is neither positive or negative 77 | 78 | template 79 | typename t::prop isPositive (const typename t::fpt &format, const unpackedFloat &uf) { 80 | PRECONDITION(uf.valid(format)); 81 | 82 | return !uf.getNaN() && !uf.getSign(); 83 | } 84 | 85 | template 86 | typename t::prop isNegative (const typename t::fpt &format, const unpackedFloat &uf) { 87 | PRECONDITION(uf.valid(format)); 88 | 89 | return !uf.getNaN() && uf.getSign(); 90 | } 91 | 92 | 93 | // C semantics 94 | 95 | template 96 | typename t::prop isFinite (const typename t::fpt &format, const unpackedFloat &uf) { 97 | PRECONDITION(uf.valid(format)); 98 | 99 | return !uf.getNaN() && !uf.getInf(); 100 | } 101 | 102 | 103 | } 104 | 105 | #endif 106 | 107 | -------------------------------------------------------------------------------- /core/compare.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** compare.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 25/08/14 24 | ** 25 | ** Comparison between floating-point numbers 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | #include "symfpu/core/ite.h" 31 | 32 | #ifndef SYMFPU_COMPARE 33 | #define SYMFPU_COMPARE 34 | 35 | namespace symfpu { 36 | 37 | // SMT-LIB equality 38 | template 39 | typename t::prop smtlibEqual (const typename t::fpt &format, 40 | const unpackedFloat &left, 41 | const unpackedFloat &right) { 42 | typedef typename t::prop prop; 43 | 44 | PRECONDITION(left.valid(format)); 45 | PRECONDITION(right.valid(format)); 46 | 47 | // Relies on a number of properties of the unpacked format 48 | // particularly the use of default exponents, significands and signs 49 | 50 | prop flagsEqual((left.getNaN() == right.getNaN()) && 51 | (left.getInf() == right.getInf()) && 52 | (left.getZero() == right.getZero()) && 53 | (left.getSign() == right.getSign())); 54 | 55 | prop flagsAndExponent(flagsEqual && left.getExponent() == right.getExponent()); 56 | 57 | // Avoid comparing (and thus instantiating) the significand unless necessary 58 | probabilityAnnotation(flagsAndExponent, UNLIKELY); 59 | 60 | prop res(ITE(flagsAndExponent, 61 | left.getSignificand() == right.getSignificand(), 62 | prop(false))); 63 | 64 | return res; 65 | } 66 | 67 | // IEEE-754 Equality (not actually an equivalence relation but ...) 68 | template 69 | typename t::prop ieee754Equal (const typename t::fpt &format, 70 | const unpackedFloat &left, 71 | const unpackedFloat &right) { 72 | 73 | typedef typename t::prop prop; 74 | 75 | PRECONDITION(left.valid(format)); 76 | PRECONDITION(right.valid(format)); 77 | 78 | prop neitherNan(!left.getNaN() && !right.getNaN()); // All comparison with NaN are false 79 | prop bothZero(left.getZero() && right.getZero()); // Both zeros are equal 80 | prop neitherZero(!left.getZero() && !right.getZero()); 81 | 82 | prop flagsAndExponent(neitherNan && 83 | (bothZero || (neitherZero && 84 | (left.getInf() == right.getInf() && 85 | left.getSign() == right.getSign() && 86 | left.getExponent() == right.getExponent())))); 87 | 88 | // Avoid comparing (and thus instantiating) the significand unless necessary 89 | probabilityAnnotation(flagsAndExponent, UNLIKELY); 90 | 91 | prop res(ITE(flagsAndExponent, left.getSignificand() == right.getSignificand(), prop(false))); 92 | 93 | return res; 94 | } 95 | 96 | 97 | // Share the common comparison code between functions 98 | // equality == true if the equal case returns true 99 | // IEEE-754 semantics for ordering with NaN 100 | // (i.e. unordered with everything, not even equal to itself) 101 | template 102 | typename t::prop ordering (const typename t::fpt &format, 103 | const unpackedFloat &left, 104 | const unpackedFloat &right, 105 | const typename t::prop equality) { 106 | 107 | typedef typename t::prop prop; 108 | 109 | PRECONDITION(left.valid(format)); 110 | PRECONDITION(right.valid(format)); 111 | 112 | // All comparison with NaN are false 113 | prop neitherNaN(!left.getNaN() && !right.getNaN()); 114 | 115 | // Either is an infinity (wrong in the case of NaN but will be corrected) 116 | prop infCase( (left.isNegativeInf() && ITE(equality, prop(true), !right.isNegativeInf()) ) || 117 | (right.isPositiveInf() && ITE(equality, prop(true), !left.isPositiveInf()) ) || 118 | (ITE(equality, left.getInf() && right.getInf() && left.getSign() == right.getSign(), prop(false))) ); 119 | 120 | 121 | // Either is a zero (wrong in the case of NaN but will be corrected) 122 | prop zeroCase( ( left.getZero() && !right.getZero() && !right.getSign()) || 123 | (right.getZero() && !left.getZero() && left.getSign()) || 124 | (ITE(equality, left.getZero() && right.getZero(), prop(false))) ); 125 | 126 | 127 | // Normal and subnormal case 128 | prop normalOrSubnormal(!left.getNaN() && !right.getNaN() && 129 | !left.getInf() && !right.getInf() && 130 | !left.getZero() && !right.getZero()); 131 | 132 | prop negativeLessThanPositive(normalOrSubnormal && left.getSign() && !right.getSign()); 133 | 134 | prop exponentNeeded(normalOrSubnormal && left.getSign() == right.getSign()); 135 | probabilityAnnotation(exponentNeeded, UNLIKELY); 136 | 137 | prop positiveCase(!left.getSign() && !right.getSign() && 138 | left.getExponent() < right.getExponent()); 139 | prop negativeCase( left.getSign() && right.getSign() && 140 | left.getExponent() > right.getExponent()); 141 | 142 | 143 | prop exponentEqual(left.getExponent() == right.getExponent()); 144 | 145 | prop significandNeeded(exponentNeeded && exponentEqual); 146 | probabilityAnnotation(significandNeeded, VERYUNLIKELY); 147 | 148 | prop positiveExEqCase(!left.getSign() && !right.getSign() && 149 | left.getSignificand() < right.getSignificand()); 150 | prop negativeExEqCase( left.getSign() && right.getSign() && 151 | left.getSignificand() > right.getSignificand()); 152 | 153 | prop positiveExEqCaseEq(!left.getSign() && !right.getSign() && 154 | left.getSignificand() <= right.getSignificand()); 155 | prop negativeExEqCaseEq( left.getSign() && right.getSign() && 156 | left.getSignificand() >= right.getSignificand()); 157 | 158 | return ITE(!normalOrSubnormal, 159 | neitherNaN && (infCase || zeroCase), 160 | ITE(!exponentNeeded, 161 | negativeLessThanPositive, 162 | ITE(!significandNeeded, 163 | positiveCase || negativeCase, 164 | ITE(equality, 165 | positiveExEqCaseEq || negativeExEqCaseEq, 166 | positiveExEqCase || negativeExEqCase)))); 167 | } 168 | 169 | 170 | template 171 | typename t::prop lessThan (const typename t::fpt &format, 172 | const unpackedFloat &left, 173 | const unpackedFloat &right) { 174 | PRECONDITION(left.valid(format)); 175 | PRECONDITION(right.valid(format)); 176 | 177 | typedef typename t::prop prop; 178 | 179 | return ordering(format, left, right, prop(false)); 180 | } 181 | 182 | 183 | template 184 | typename t::prop lessThanOrEqual (const typename t::fpt &format, 185 | const unpackedFloat &left, 186 | const unpackedFloat &right) { 187 | PRECONDITION(left.valid(format)); 188 | PRECONDITION(right.valid(format)); 189 | 190 | typedef typename t::prop prop; 191 | 192 | return ordering(format, left, right, prop(true)); 193 | } 194 | 195 | 196 | // Note that IEEE-754 says that max(+0,-0) = +/-0 and max(-0,+0) = +/- 0 197 | template 198 | unpackedFloat max (const typename t::fpt &format, 199 | const unpackedFloat &left, 200 | const unpackedFloat &right, 201 | const typename t::prop &zeroCase) { 202 | return ITE(left.getNaN() || ordering(format, left, right, zeroCase), 203 | right, 204 | left); 205 | } 206 | 207 | // Note that IEEE-754 says that min(+0,-0) = +/-0 and min(-0,+0) = +/- 0 208 | // this will always return the left one. 209 | template 210 | unpackedFloat min (const typename t::fpt &format, 211 | const unpackedFloat &left, 212 | const unpackedFloat &right, 213 | const typename t::prop &zeroCase) { 214 | return ITE(right.getNaN() || ordering(format, left, right, zeroCase), 215 | left, 216 | right); 217 | } 218 | 219 | 220 | 221 | template 222 | typename t::prop originalLessThan (const typename t::fpt &format, 223 | const unpackedFloat &left, 224 | const unpackedFloat &right) { 225 | 226 | typedef typename t::prop prop; 227 | 228 | PRECONDITION(left.valid(format)); 229 | PRECONDITION(right.valid(format)); 230 | 231 | // Optimisation : merge < and == 232 | 233 | 234 | // All comparison with NaN are false 235 | prop neitherNan(!left.getNaN() && !right.getNaN()); 236 | 237 | // Infinities are bigger than everything but themself 238 | prop eitherInf(left.getInf() || right.getInf()); 239 | prop infCase(( left.isNegativeInf() && !right.isNegativeInf()) || 240 | (!left.isPositiveInf() && right.isPositiveInf())); 241 | 242 | 243 | // Both zero are equal 244 | prop eitherZero(left.getZero() || right.getZero()); 245 | prop zeroCase(( left.getZero() && !right.getZero() && !right.getSign()) || 246 | (!left.getZero() && left.getSign() && right.getZero())); 247 | 248 | 249 | // Normal and subnormal 250 | 251 | prop negativeLessThanPositive(left.getSign() && !right.getSign()); // - < + 252 | prop positiveCase(!left.getSign() && !right.getSign() && 253 | ((left.getExponent() < right.getExponent()) || 254 | (left.getExponent() == right.getExponent() && 255 | left.getSignificand() < right.getSignificand()))); 256 | 257 | prop negativeCase(left.getSign() && right.getSign() && 258 | ((left.getExponent() > right.getExponent()) || 259 | (left.getExponent() == right.getExponent() && 260 | left.getSignificand() > right.getSignificand()))); 261 | 262 | 263 | return neitherNan && 264 | ITE(eitherInf, 265 | infCase, 266 | ITE(eitherZero, 267 | zeroCase, 268 | negativeLessThanPositive || positiveCase || negativeCase)); 269 | } 270 | 271 | // Optimised combination of the two 272 | template 273 | typename t::prop originalLessThanOrEqual (const typename t::fpt &format, 274 | const unpackedFloat &left, 275 | const unpackedFloat &right) { 276 | 277 | typedef typename t::prop prop; 278 | 279 | PRECONDITION(left.valid(format)); 280 | PRECONDITION(right.valid(format)); 281 | 282 | // Optimisation : merge < and == 283 | 284 | 285 | // All comparison with NaN are false 286 | prop neitherNan(!left.getNaN() && !right.getNaN()); 287 | 288 | // Infinities are bigger than everything but themself 289 | prop eitherInf(left.getInf() || right.getInf()); 290 | prop infCase( (left.getInf() && right.getInf() && left.getSign() == right.getSign()) || 291 | left.isNegativeInf() || 292 | right.isPositiveInf()); 293 | 294 | 295 | // Both zero are equal 296 | prop eitherZero(left.getZero() || right.getZero()); 297 | prop zeroCase((left.getZero() && right.getZero()) || 298 | ( left.getZero() && !right.getSign()) || 299 | ( left.getSign() && right.getZero())); 300 | 301 | 302 | // Normal and subnormal 303 | 304 | prop negativeLessThanPositive(left.getSign() && !right.getSign()); // - < + 305 | prop positiveCase(!left.getSign() && !right.getSign() && 306 | ((left.getExponent() < right.getExponent()) || 307 | (left.getExponent() == right.getExponent() && 308 | left.getSignificand() <= right.getSignificand()))); 309 | 310 | prop negativeCase(left.getSign() && right.getSign() && 311 | ((left.getExponent() > right.getExponent()) || 312 | (left.getExponent() == right.getExponent() && 313 | left.getSignificand() >= right.getSignificand()))); 314 | 315 | 316 | return neitherNan && 317 | ITE(eitherInf, 318 | infCase, 319 | ITE(eitherZero, 320 | zeroCase, 321 | negativeLessThanPositive || positiveCase || negativeCase)); 322 | } 323 | 324 | } 325 | 326 | #endif 327 | -------------------------------------------------------------------------------- /core/convert.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** convert.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 03/02/14 24 | ** 25 | ** Conversion from unpacked floats in one format to another. 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | #include "symfpu/core/rounder.h" 31 | 32 | #ifndef SYMFPU_CONVERT 33 | #define SYMFPU_CONVERT 34 | 35 | namespace symfpu { 36 | 37 | template 38 | unpackedFloat convertFloatToFloat (const typename t::fpt &sourceFormat, 39 | const typename t::fpt &targetFormat, 40 | const typename t::rm &roundingMode, 41 | const unpackedFloat &input) { 42 | 43 | PRECONDITION(input.valid(sourceFormat)); 44 | 45 | typedef typename t::bwt bwt; 46 | //typedef typename t::prop prop; 47 | //typedef typename t::ubv ubv; 48 | //typedef typename t::sbv sbv; 49 | 50 | // increased includes equality 51 | bool exponentIncreased = unpackedFloat::exponentWidth(sourceFormat) <= unpackedFloat::exponentWidth(targetFormat); 52 | bool significandIncreased = unpackedFloat::significandWidth(sourceFormat) <= unpackedFloat::significandWidth(targetFormat); 53 | 54 | bwt expExtension = (exponentIncreased) ? unpackedFloat::exponentWidth(targetFormat) - unpackedFloat::exponentWidth(sourceFormat) : 0; 55 | bwt sigExtension = (significandIncreased) ? unpackedFloat::significandWidth(targetFormat) - unpackedFloat::significandWidth(sourceFormat) : 0; 56 | 57 | unpackedFloat extended(input.extend(expExtension, sigExtension)); 58 | 59 | // Format sizes are literal so it is safe to branch on them 60 | if (exponentIncreased && significandIncreased) { 61 | // Fast path strict promotions 62 | 63 | POSTCONDITION(extended.valid(targetFormat)); 64 | 65 | return extended; 66 | 67 | } else { 68 | 69 | unpackedFloat rounded(rounder(targetFormat, roundingMode, extended)); 70 | 71 | unpackedFloat result(ITE(input.getNaN(), 72 | unpackedFloat::makeNaN(targetFormat), 73 | ITE(input.getInf(), 74 | unpackedFloat::makeInf(targetFormat, input.getSign()), 75 | ITE(input.getZero(), 76 | unpackedFloat::makeZero(targetFormat, input.getSign()), 77 | rounded)))); 78 | 79 | POSTCONDITION(result.valid(targetFormat)); 80 | 81 | return result; 82 | } 83 | } 84 | 85 | 86 | template 87 | unpackedFloat roundToIntegral (const typename t::fpt &format, 88 | const typename t::rm &roundingMode, 89 | const unpackedFloat &input) { 90 | 91 | PRECONDITION(input.valid(format)); 92 | 93 | typedef typename t::bwt bwt; 94 | typedef typename t::prop prop; 95 | typedef typename t::ubv ubv; 96 | typedef typename t::sbv sbv; 97 | 98 | sbv exponent(input.getExponent()); 99 | bwt exponentWidth(exponent.getWidth()); 100 | 101 | sbv packedSigWidth(exponentWidth, format.packedSignificandWidth()); 102 | sbv unpackedSigWidth(exponentWidth, format.significandWidth()); 103 | 104 | // Fast path for things that must be integral 105 | prop isIntegral(exponent >= packedSigWidth); 106 | prop isSpecial(input.getNaN() || input.getInf() || input.getZero()); 107 | prop isID(isIntegral || isSpecial); 108 | probabilityAnnotation(isID, LIKELY); 109 | // TODO : fast path the cases that don't round up 110 | 111 | 112 | // Otherwise, compute rounding location 113 | sbv initialRoundingPoint(expandingSubtract(packedSigWidth,exponent)); // Expansion only needed in obscure formats 114 | sbv roundingPoint(collar(initialRoundingPoint, 115 | sbv::zero(exponentWidth + 1), 116 | unpackedSigWidth.extend(1).increment())); 117 | 118 | // Round 119 | ubv significand(input.getSignificand()); 120 | significandRounderResult roundedResult(variablePositionRound(roundingMode, input.getSign(), significand, 121 | roundingPoint.toUnsigned().matchWidth(significand), 122 | prop(false), // TODO : Could actually be exponent >= 0 123 | isID)); // The fast-path case so just deactives some code 124 | 125 | // Reconstruct 126 | // Note this is not in a valid form if significand is all zeros 127 | // The max is necessary to catch cases when we round up to one from very small numbers 128 | // The rounder ensures these are zero if they don't round up 129 | unpackedFloat reconstructed(input.getSign(), 130 | max(conditionalIncrement(roundedResult.incrementExponent, exponent), 131 | sbv::zero(exponentWidth)), 132 | roundedResult.significand); 133 | 134 | 135 | unpackedFloat result(ITE(isID, 136 | input, 137 | ITE(roundedResult.significand.isAllZeros(), 138 | unpackedFloat::makeZero(format, input.getSign()), 139 | reconstructed))); 140 | 141 | POSTCONDITION(result.valid(format)); 142 | 143 | return result; 144 | 145 | 146 | #if 0 147 | // increased includes equality 148 | bool exponentIncreased = unpackedFloat::exponentWidth(sourceFormat) <= unpackedFloat::exponentWidth(targetFormat); 149 | bool significandIncreased = unpackedFloat::significandWidth(sourceFormat) <= unpackedFloat::significandWidth(targetFormat); 150 | 151 | bwt expExtension = (exponentIncreased) ? unpackedFloat::exponentWidth(targetFormat) - unpackedFloat::exponentWidth(sourceFormat) : 0; 152 | bwt sigExtension = (significandIncreased) ? unpackedFloat::significandWidth(targetFormat) - unpackedFloat::significandWidth(sourceFormat) : 0; 153 | 154 | unpackedFloat extended(input.extend(expExtension, sigExtension)); 155 | 156 | // Format sizes are literal so it is safe to branch on them 157 | if (exponentIncreased && significandIncreased) { 158 | // Fast path strict promotions 159 | 160 | POSTCONDITION(extended.valid(targetFormat)); 161 | 162 | return extended; 163 | 164 | } else { 165 | 166 | unpackedFloat rounded(rounder(targetFormat, roundingMode, extended)); 167 | 168 | unpackedFloat result(ITE(input.getNaN(), 169 | unpackedFloat::makeNaN(targetFormat), 170 | ITE(input.getInf(), 171 | unpackedFloat::makeInf(targetFormat, input.getSign()), 172 | ITE(input.getZero(), 173 | unpackedFloat::makeZero(targetFormat, input.getSign()), 174 | rounded)))); 175 | 176 | POSTCONDITION(result.valid(targetFormat)); 177 | 178 | return result; 179 | } 180 | #endif 181 | 182 | } 183 | 184 | 185 | template 186 | unpackedFloat convertUBVToFloat (const typename t::fpt &targetFormat, 187 | const typename t::rm &roundingMode, 188 | const typename t::ubv &input, 189 | const typename t::bwt &decimalPointPosition = 0) { 190 | 191 | typedef typename t::bwt bwt; 192 | typedef typename t::prop prop; 193 | typedef typename t::sbv sbv; 194 | typedef typename t::fpt fpt; 195 | 196 | bwt inputWidth(input.getWidth()); 197 | 198 | PRECONDITION(decimalPointPosition <= inputWidth); 199 | 200 | // Devise an appropriate format 201 | bwt initialExponentWidth(bitsToRepresent(inputWidth) + 1); // +1 as unsigned -> signed 202 | fpt initialFormat(initialExponentWidth, inputWidth); 203 | bwt actualExponentWidth(unpackedFloat::exponentWidth(initialFormat)); 204 | 205 | // Build 206 | unpackedFloat initial(prop(false), sbv(actualExponentWidth, (inputWidth - 1) - decimalPointPosition), input); // inputWidth - 1 as we want one bit above the decimal point 207 | 208 | // Normalise 209 | unpackedFloat normalised(initial.normaliseUpDetectZero(initialFormat)); 210 | 211 | // Round (the conversion will catch the cases where no rounding is needed) 212 | return convertFloatToFloat(initialFormat, targetFormat, roundingMode, normalised); 213 | } 214 | 215 | 216 | template 217 | unpackedFloat convertSBVToFloat (const typename t::fpt &targetFormat, 218 | const typename t::rm &roundingMode, 219 | const typename t::sbv &input, 220 | const typename t::bwt &decimalPointPosition = 0) { 221 | typedef typename t::bwt bwt; 222 | typedef typename t::prop prop; 223 | typedef typename t::sbv sbv; 224 | typedef typename t::fpt fpt; 225 | 226 | bwt inputWidth(input.getWidth()); 227 | 228 | PRECONDITION(decimalPointPosition <= inputWidth); 229 | 230 | // Devise an appropriate format 231 | bwt initialExponentWidth(bitsToRepresent(inputWidth) + 1); // +1 as unsigned -> signed 232 | fpt initialFormat(initialExponentWidth, inputWidth + 1); // +1 as signed -> unsigned 233 | bwt actualExponentWidth(unpackedFloat::exponentWidth(initialFormat)); 234 | 235 | // Work out the sign 236 | prop negative(input < sbv::zero(inputWidth)); 237 | 238 | // Build 239 | unpackedFloat initial(negative, sbv(actualExponentWidth, inputWidth - decimalPointPosition), (abs(input.extend(1))).toUnsigned()); 240 | 241 | // Normalise 242 | unpackedFloat normalised(initial.normaliseUpDetectZero(initialFormat)); 243 | 244 | // Round (the conversion will catch the cases where no rounding is needed) 245 | return convertFloatToFloat(initialFormat, targetFormat, roundingMode, normalised); 246 | } 247 | 248 | 249 | // Common conversion code for both convert to sgined and to unsigned. 250 | // Note that the results will be junk if it is not in bounds, etc. 251 | // convertFloatToUBV and convertFloatToSBV handle all of that logic. 252 | template 253 | significandRounderResult convertFloatToBV (const typename t::fpt &format, 254 | const typename t::rm &roundingMode, 255 | const unpackedFloat &input, 256 | const typename t::bwt &targetWidth, 257 | const typename t::bwt &decimalPointPosition) { 258 | 259 | typedef typename t::bwt bwt; 260 | typedef typename t::prop prop; 261 | typedef typename t::ubv ubv; 262 | typedef typename t::sbv sbv; 263 | 264 | 265 | PRECONDITION(decimalPointPosition < targetWidth); 266 | 267 | 268 | // TODO : fast path the RTZ / don't need to round case 269 | 270 | bwt maxShift(targetWidth + 1); // + 1 as we have to shift over the guard bit 271 | bwt maxShiftBits(bitsToRepresent(maxShift) + 1); // +1 as we want it to be signed 272 | 273 | bwt exponentWidth(input.getExponent().getWidth()); 274 | bwt workingExponentWidth((exponentWidth >= maxShiftBits) ? 275 | exponentWidth : maxShiftBits); 276 | 277 | sbv maxShiftAmount(workingExponentWidth, maxShift); 278 | sbv exponent(input.getExponent().matchWidth(maxShiftAmount)); 279 | 280 | 281 | // Optimisation : compact the significand in the case targetWidth < significantWidth 282 | ubv inputSignificand(input.getSignificand()); 283 | bwt inputSignificandWidth(inputSignificand.getWidth()); 284 | ubv *working = NULL; 285 | if (targetWidth + 2 < inputSignificandWidth) { 286 | 287 | ubv dataAndGuard(inputSignificand.extract(inputSignificandWidth - 1, (inputSignificandWidth - targetWidth) - 1)); 288 | prop sticky(!inputSignificand.extract((inputSignificandWidth - targetWidth) - 2, 0).isAllZeros()); 289 | 290 | working = new ubv(dataAndGuard.append(ubv(sticky))); 291 | } else { 292 | working = new ubv(inputSignificand); 293 | } 294 | ubv significand(*working); 295 | delete working; 296 | bwt significandWidth(significand.getWidth()); 297 | 298 | // Handle zero 299 | ubv zerodSignificand(significand & 300 | ITE(input.getZero(), ubv::zero(significandWidth), ubv::allOnes(significandWidth))); 301 | ubv expandedSignificand(zerodSignificand.extend(maxShift)); // Start with the significand in the sticky position. 302 | // targetWidth +1 is for the guard bit 303 | 304 | // Align 305 | sbv shiftAmount(collar(expandingAdd(exponent, 306 | sbv(workingExponentWidth, decimalPointPosition + 2)), // +1 to guard, +1 to LSB 307 | sbv::zero(workingExponentWidth + 1), 308 | maxShiftAmount.extend(1))); 309 | ubv convertedShiftAmount(shiftAmount.resize(bitsToRepresent(maxShift) + 1 /* +1 for sign bit, safe due to collar */ 310 | ).toUnsigned().matchWidth(expandedSignificand)); 311 | ubv aligned(expandedSignificand << convertedShiftAmount); // Safe by collar 312 | 313 | 314 | // Fixed position round 315 | significandRounderResult rounded(fixedPositionRound(roundingMode, input.getSign(), 316 | aligned, targetWidth, 317 | prop(false), prop(false))); 318 | 319 | return rounded; 320 | } 321 | 322 | // A more compact version for round to zero 323 | // Only handles normal, subnormal and zero cases, overflow of targetWidth will give junk. 324 | // Inf, NaN, and overflow must be handled by the caller. 325 | template 326 | significandRounderResult convertFloatToBVRTZ (const typename t::fpt &format, 327 | const unpackedFloat &input, 328 | const typename t::bwt &targetWidth, 329 | const typename t::bwt &decimalPointPosition) { 330 | typedef typename t::bwt bwt; 331 | typedef typename t::prop prop; 332 | typedef typename t::ubv ubv; 333 | typedef typename t::sbv sbv; 334 | 335 | PRECONDITION(targetWidth > 0); 336 | PRECONDITION(decimalPointPosition < targetWidth); 337 | 338 | // A working significand of the right length 339 | ubv significand(input.getSignificand()); 340 | bwt significandWidth(significand.getWidth()); 341 | 342 | ubv significantSignificand(significand.extract(significandWidth - 1, 343 | ((targetWidth < significandWidth) ? significandWidth - targetWidth : 0))); 344 | bwt ssWidth(significantSignificand.getWidth()); 345 | 346 | 347 | // Handle zero and fractional cases 348 | sbv exponent(input.getExponent()); 349 | bwt exponentWidth(exponent.getWidth()); 350 | 351 | prop fraction(input.getExponent() < sbv::zero(exponentWidth)); 352 | ubv zerodSignificand(significantSignificand & 353 | ITE(input.getZero() || fraction, ubv::zero(ssWidth), ubv::allOnes(ssWidth))); 354 | 355 | ubv expandedSignificand(zerodSignificand.extend(targetWidth - 1)); // Start with the significand in the LSB of output 356 | 357 | 358 | // Prepare exponent 359 | bwt maxShift(targetWidth - 1); // - 1 as we are already at LSB 360 | bwt maxShiftBits(bitsToRepresent(maxShift)); // Don't care about it being signed 361 | 362 | ubv convertedExponent(exponent.toUnsigned()); 363 | bwt topExtractedBit(((maxShiftBits > (exponentWidth - 1)) ? exponentWidth : maxShiftBits) - 1); 364 | 365 | ubv shiftBits(convertedExponent.extract(topExtractedBit, 0)); 366 | ubv shiftOperand(shiftBits.matchWidth(expandedSignificand)); 367 | 368 | // Align 369 | ubv shifted(expandedSignificand.modularLeftShift(shiftOperand)); 370 | bwt shiftedWidth(shifted.getWidth()); 371 | 372 | // Extract 373 | ubv result(shifted.extract(shiftedWidth - 1, shiftedWidth - targetWidth)); 374 | 375 | return significandRounderResult(result, prop(false)); 376 | } 377 | 378 | 379 | 380 | // Decimal point position in the bit in the output on the left hand side of the decimal point 381 | // I.E. if it is positive then it is converting to a fix-point number 382 | template 383 | typename t::ubv convertFloatToUBV (const typename t::fpt &format, 384 | const typename t::rm &roundingMode, 385 | const unpackedFloat &input, 386 | const typename t::bwt &targetWidth, 387 | const typename t::ubv &undefValue, 388 | const typename t::bwt &decimalPointPosition = 0) { 389 | 390 | typedef typename t::bwt bwt; 391 | typedef typename t::prop prop; 392 | typedef typename t::ubv ubv; 393 | typedef typename t::sbv sbv; 394 | 395 | 396 | PRECONDITION(decimalPointPosition < targetWidth); 397 | 398 | 399 | // Invalid cases 400 | prop specialValue(input.getInf() || input.getNaN()); 401 | 402 | bwt maxExponentValue(targetWidth); 403 | bwt maxExponentBits(bitsToRepresent(maxExponentValue) + 1); 404 | 405 | bwt exponentWidth(input.getExponent().getWidth()); 406 | bwt workingExponentWidth((exponentWidth >= maxExponentBits) ? 407 | exponentWidth : maxExponentBits); 408 | 409 | sbv maxExponent(workingExponentWidth, maxExponentValue); 410 | sbv exponent(input.getExponent().matchWidth(maxExponent)); 411 | 412 | prop tooLarge(exponent >= maxExponent); 413 | 414 | prop tooNegative(input.getSign() && 415 | !input.getZero() && // Zero is handled elsewhere 416 | sbv::zero(workingExponentWidth) <= exponent); // Can't round to 0 417 | 418 | prop earlyUndefinedResult(specialValue || tooLarge || tooNegative); 419 | probabilityAnnotation(earlyUndefinedResult, LIKELY); // Convertable values are rare 420 | 421 | 422 | // Fixed position round 423 | significandRounderResult rounded(convertFloatToBV(format, roundingMode, input, 424 | targetWidth, decimalPointPosition)); 425 | 426 | // TODO : fast path negative by converting exp==0 into guard and exp < 0 into sticky 427 | 428 | // Put the result together 429 | prop undefinedResult(earlyUndefinedResult || 430 | rounded.incrementExponent || // Overflow 431 | (input.getSign() && !rounded.significand.isAllZeros())); // Negative case 432 | 433 | ubv result(ITE(undefinedResult, 434 | undefValue, 435 | rounded.significand)); 436 | 437 | return result; 438 | } 439 | 440 | // Decimal point position in the bit in the output on the left hand side of the decimal point 441 | // I.E. if it is positive then it is converting to a fix-point number 442 | template 443 | typename t::sbv convertFloatToSBV (const typename t::fpt &format, 444 | const typename t::rm &roundingMode, 445 | const unpackedFloat &input, 446 | const typename t::bwt &targetWidth, 447 | const typename t::sbv &undefValue, 448 | const typename t::bwt &decimalPointPosition = 0) { 449 | 450 | typedef typename t::bwt bwt; 451 | typedef typename t::prop prop; 452 | //typedef typename t::ubv ubv; 453 | typedef typename t::sbv sbv; 454 | 455 | 456 | PRECONDITION(decimalPointPosition < targetWidth); 457 | 458 | 459 | // Invalid cases 460 | prop specialValue(input.getInf() || input.getNaN()); 461 | 462 | bwt maxExponentValue(targetWidth); 463 | bwt maxExponentBits(bitsToRepresent(maxExponentValue) + 1); 464 | 465 | bwt exponentWidth(input.getExponent().getWidth()); 466 | bwt workingExponentWidth((exponentWidth >= maxExponentBits) ? 467 | exponentWidth : maxExponentBits); 468 | 469 | sbv maxExponent(workingExponentWidth, maxExponentValue); 470 | sbv exponent(input.getExponent().matchWidth(maxExponent)); 471 | 472 | prop tooLarge(exponent >= maxExponent); 473 | 474 | prop earlyUndefinedResult(specialValue || tooLarge); 475 | probabilityAnnotation(earlyUndefinedResult, LIKELY); // Convertable values are rare 476 | 477 | 478 | // Fixed position round 479 | // (It is tempting to think that this could be done with targetWidth - 1 bits but that 480 | // missed the case of things like -128.05 -> int8_t) 481 | significandRounderResult rounded(convertFloatToBV(format, roundingMode, input, 482 | targetWidth, decimalPointPosition)); 483 | 484 | // Put the result together 485 | bwt roundSigWidth(rounded.significand.getWidth()); 486 | prop undefinedResult(earlyUndefinedResult || 487 | rounded.incrementExponent || // Definite Overflow 488 | (rounded.significand.extract(roundSigWidth - 1, 489 | roundSigWidth - 1).isAllOnes() && 490 | !(input.getSign() && rounded.significand.extract(roundSigWidth - 2, 0).isAllZeros()))); // -2^{n-1} is the only safe "overflow" case 491 | 492 | 493 | sbv result(ITE(undefinedResult, 494 | undefValue, 495 | conditionalNegate(input.getSign(), rounded.significand.toSigned()))); 496 | 497 | return result; 498 | } 499 | 500 | } 501 | 502 | #endif 503 | -------------------------------------------------------------------------------- /core/divide.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** divide.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 04/02/16 24 | ** 25 | ** Division of arbitrary precision floats 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | #include "symfpu/core/ite.h" 31 | #include "symfpu/core/rounder.h" 32 | #include "symfpu/core/operations.h" 33 | 34 | #ifndef SYMFPU_DIVIDE 35 | #define SYMFPU_DIVIDE 36 | 37 | namespace symfpu { 38 | 39 | template 40 | unpackedFloat addDivideSpecialCases (const typename t::fpt &format, 41 | const unpackedFloat &left, 42 | const unpackedFloat &right, 43 | const typename t::prop &sign, 44 | const unpackedFloat ÷Result) { 45 | typedef typename t::prop prop; 46 | 47 | prop eitherArgumentNaN(left.getNaN() || right.getNaN()); 48 | prop generateNaN((left.getInf() && right.getInf()) || 49 | (left.getZero() && right.getZero())); 50 | 51 | prop isNaN(eitherArgumentNaN || generateNaN); 52 | 53 | prop isInf((!left.getZero() && right.getZero()) || 54 | (left.getInf() && !right.getInf())); 55 | 56 | prop isZero((!left.getInf() && right.getInf()) || 57 | (left.getZero() && !right.getZero())); 58 | 59 | return ITE(isNaN, 60 | unpackedFloat::makeNaN(format), 61 | ITE(isInf, 62 | unpackedFloat::makeInf(format, sign), 63 | ITE(isZero, 64 | unpackedFloat::makeZero(format, sign), 65 | divideResult))); 66 | } 67 | 68 | 69 | template 70 | unpackedFloat arithmeticDivide (const typename t::fpt &format, 71 | const unpackedFloat &left, 72 | const unpackedFloat &right) { 73 | typedef typename t::bwt bwt; 74 | typedef typename t::prop prop; 75 | typedef typename t::ubv ubv; 76 | typedef typename t::sbv sbv; 77 | typedef typename t::fpt fpt; 78 | 79 | PRECONDITION(left.valid(format)); 80 | PRECONDITION(right.valid(format)); 81 | 82 | // Compute sign 83 | prop divideSign(left.getSign() ^ right.getSign()); 84 | 85 | // Subtract up exponents 86 | sbv exponentDiff(expandingSubtract(left.getExponent(),right.getExponent())); 87 | // Optimisation : do this late and use the increment as a carry in 88 | 89 | sbv min(unpackedFloat::minSubnormalExponent(format)); 90 | sbv max(unpackedFloat::maxNormalExponent(format)); 91 | INVARIANT(expandingSubtract(min,max) <= exponentDiff); 92 | INVARIANT(exponentDiff <= expandingSubtract(max, min)); 93 | // Optimisation : use the if-then-lazy-else to avoid dividing for underflow and overflow 94 | // subnormal / greater-than-2^sigwidth does not need to be evaluated 95 | 96 | 97 | // Divide the significands 98 | // We need significandWidth() + 1 bits in the result but the top one may cancel, so add two bits 99 | ubv extendedNumerator(left.getSignificand().append(ubv::zero(2))); 100 | ubv extendedDenominator(right.getSignificand().append(ubv::zero(2))); 101 | 102 | resultWithRemainderBit divided(fixedPointDivide(extendedNumerator, extendedDenominator)); 103 | 104 | 105 | bwt resWidth(divided.result.getWidth()); 106 | ubv topBit(divided.result.extract(resWidth - 1, resWidth - 1)); 107 | ubv nextBit(divided.result.extract(resWidth - 2, resWidth - 2)); 108 | 109 | // Alignment of inputs means at least one of the two MSB is 1 110 | // i.e. [1,2) / [1,2) = [0.5,2) 111 | // Top bit is set by the first round of the divide and thus is 50/50 1 or 0 112 | prop topBitSet(topBit.isAllOnes()); 113 | INVARIANT(topBitSet || nextBit.isAllOnes()); 114 | INVARIANT(topBitSet == (left.getSignificand() >= right.getSignificand())); 115 | 116 | 117 | // Re-align 118 | sbv alignedExponent(conditionalDecrement(!topBitSet, exponentDiff)); // Will not overflow as previously expanded 119 | ubv alignedSignificand(conditionalLeftShiftOne(!topBitSet, divided.result)); // Will not loose information 120 | 121 | // Create the sticky bit, it is important that this is after alignment 122 | ubv finishedSignificand(alignedSignificand | ubv(divided.remainderBit).extend(resWidth - 1)); 123 | 124 | // Put back together 125 | unpackedFloat divideResult(divideSign, alignedExponent.extend(1), finishedSignificand); 126 | 127 | // A brief word about formats. 128 | // You might think that the extend above is unnecessary : it is from a overflow point of view. 129 | // It's needed so that it is a valid number with exponentWidth() + 2. 130 | // +1 is sufficient in almost all cases. However: 131 | // very large normal / very small subnormal 132 | // can have an exponent greater than very large normal * 2 ( + 1) 133 | // because the exponent range is asymmetric with more subnormal than normal. 134 | 135 | fpt extendedFormat(format.exponentWidth() + 2, format.significandWidth() + 2); 136 | POSTCONDITION(divideResult.valid(extendedFormat)); 137 | 138 | return divideResult; 139 | } 140 | 141 | 142 | // Put it all together... 143 | template 144 | unpackedFloat divide (const typename t::fpt &format, 145 | const typename t::rm &roundingMode, 146 | const unpackedFloat &left, 147 | const unpackedFloat &right) { 148 | //typedef typename t::bwt bwt; 149 | //typedef typename t::prop prop; 150 | //typedef typename t::ubv ubv; 151 | //typedef typename t::sbv sbv; 152 | 153 | PRECONDITION(left.valid(format)); 154 | PRECONDITION(right.valid(format)); 155 | 156 | unpackedFloat divideResult(arithmeticDivide(format, left, right)); 157 | 158 | unpackedFloat roundedDivideResult(rounder(format, roundingMode, divideResult)); 159 | 160 | unpackedFloat result(addDivideSpecialCases(format, left, right, roundedDivideResult.getSign(), roundedDivideResult)); 161 | 162 | POSTCONDITION(result.valid(format)); 163 | 164 | return result; 165 | } 166 | 167 | 168 | } 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /core/fma.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** fma.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 20/05/15 24 | ** 25 | ** Fused multiply and add : 26 | ** fma(R,A,B,C) = round(R, A * B + C) 27 | ** 28 | */ 29 | 30 | 31 | #include "symfpu/core/unpackedFloat.h" 32 | #include "symfpu/core/ite.h" 33 | #include "symfpu/core/rounder.h" 34 | #include "symfpu/core/multiply.h" 35 | #include "symfpu/core/convert.h" 36 | #include "symfpu/core/add.h" 37 | 38 | 39 | #ifndef SYMFPU_FMA 40 | #define SYMFPU_FMA 41 | 42 | namespace symfpu { 43 | 44 | template 45 | unpackedFloat fma (const typename t::fpt &format, 46 | const typename t::rm &roundingMode, 47 | const unpackedFloat &leftMultiply, 48 | const unpackedFloat &rightMultiply, 49 | const unpackedFloat &addArgument) { 50 | 51 | // typedef typename t::bwt bwt; 52 | typedef typename t::prop prop; 53 | //typedef typename t::ubv ubv; 54 | //typedef typename t::sbv sbv; 55 | typedef typename t::fpt fpt; 56 | 57 | PRECONDITION(leftMultiply.valid(format)); 58 | PRECONDITION(rightMultiply.valid(format)); 59 | PRECONDITION(addArgument.valid(format)); 60 | 61 | /* First multiply */ 62 | unpackedFloat arithmeticMultiplyResult(arithmeticMultiply(format, leftMultiply, rightMultiply)); 63 | 64 | fpt extendedFormat(format.exponentWidth() + 1, format.significandWidth() * 2); 65 | INVARIANT(arithmeticMultiplyResult.valid(extendedFormat)); 66 | 67 | 68 | 69 | /* Then add */ 70 | 71 | // Rounding mode doesn't matter as this is a strict extension 72 | unpackedFloat extendedAddArgument(convertFloatToFloat(format, extendedFormat, t::RTZ(), addArgument)); 73 | 74 | prop knownInCorrectOrder(false); 75 | exponentCompareInfo ec(addExponentCompare(arithmeticMultiplyResult.getExponent().getWidth() + 1, 76 | arithmeticMultiplyResult.getSignificand().getWidth(), 77 | arithmeticMultiplyResult.getExponent(), 78 | extendedAddArgument.getExponent(), 79 | knownInCorrectOrder)); 80 | 81 | unpackedFloat additionResult(arithmeticAdd(extendedFormat, roundingMode, arithmeticMultiplyResult, extendedAddArgument, prop(true), knownInCorrectOrder, ec).uf); 82 | // Custom rounder flags are ignored as they are not applicable in this case 83 | 84 | fpt evenMoreExtendedFormat(extendedFormat.exponentWidth() + 1, extendedFormat.significandWidth() + 2); 85 | INVARIANT(additionResult.valid(evenMoreExtendedFormat)); 86 | 87 | 88 | /* Then round */ 89 | 90 | unpackedFloat roundedResult(rounder(format, roundingMode, additionResult)); 91 | INVARIANT(roundedResult.valid(format)); 92 | 93 | // This result is correct as long as neither of multiplyResult or extendedAddArgument is 94 | // 0, Inf or NaN. Note that roundedResult may be zero from cancelation or underflow 95 | // or infinity due to rounding. If it is, it has the correct sign. 96 | 97 | 98 | 99 | /* Finally, the special cases */ 100 | 101 | // One disadvantage to having a flag for zero and default exponents and significands for zero 102 | // that are not (min, 0) is that the x + (+/-)0 case has to be handled by the addition special cases. 103 | // This means that you need the value of x, rounded to the correct format. 104 | // arithmeticMultiplyResult is in extended format, thus we have to use a second rounder just for this case. 105 | // It is not zero, inf or NaN so it only matters when addArgument is zero when it would be returned. 106 | unpackedFloat roundedMultiplyResult(rounder(format, roundingMode, arithmeticMultiplyResult)); 107 | 108 | unpackedFloat fullMultiplyResult(addMultiplySpecialCases(format, leftMultiply, rightMultiply, roundedMultiplyResult.getSign(), roundedMultiplyResult)); 109 | 110 | 111 | // We need the flags from the multiply special cases, determined on the arithemtic result, 112 | // i.e. handling special values and not the underflow / overflow of the result. 113 | // But we will use roundedMultiplyResult instead of the value so ... 114 | unpackedFloat dummyZero(unpackedFloat::makeZero(format, prop(false))); 115 | unpackedFloat dummyValue(dummyZero.getSign(), dummyZero.getExponent(), dummyZero.getSignificand()); 116 | 117 | unpackedFloat multiplyResultWithSpecialCases(addMultiplySpecialCases(format, leftMultiply, rightMultiply, arithmeticMultiplyResult.getSign(), dummyValue)); 118 | 119 | 120 | unpackedFloat result(addAdditionSpecialCasesWithID(format, 121 | roundingMode, 122 | multiplyResultWithSpecialCases, 123 | fullMultiplyResult, // for the identity case 124 | addArgument, 125 | roundedResult, 126 | prop(true))); 127 | 128 | POSTCONDITION(result.valid(format)); 129 | 130 | return result; 131 | } 132 | 133 | /* 134 | * BUGS : 135 | * 1. sign of zero different for exact 0 and underflow 136 | * 2. large * -large + inf = inf not NaN 137 | * 3. rounder decision bugs : one looks like an issue with too-eager overflow, 138 | * one looks like a misplaced decision on highest subnormal exponent 139 | */ 140 | 141 | template 142 | unpackedFloat fmaBroken (const typename t::fpt &format, 143 | const typename t::rm &roundingMode, 144 | const unpackedFloat &leftMultiply, 145 | const unpackedFloat &rightMultiply, 146 | const unpackedFloat &addArgument) { 147 | 148 | // typedef typename t::bwt bwt; 149 | typedef typename t::prop prop; 150 | //typedef typename t::ubv ubv; 151 | //typedef typename t::sbv sbv; 152 | typedef typename t::fpt fpt; 153 | 154 | PRECONDITION(leftMultiply.valid(format)); 155 | PRECONDITION(rightMultiply.valid(format)); 156 | PRECONDITION(addArgument.valid(format)); 157 | 158 | unpackedFloat multiplyResult(arithmeticMultiply(format, leftMultiply, rightMultiply)); 159 | 160 | fpt extendedFormat(format.exponentWidth() + 1, format.significandWidth() * 2); 161 | INVARIANT(multiplyResult.valid(extendedFormat)); 162 | 163 | // Rounding mode doesn't matter as this is a strict extension 164 | unpackedFloat extendedAddArgument(convertFloatToFloat(format, extendedFormat, t::RTZ(), addArgument)); 165 | 166 | unpackedFloat additionResult(arithmeticAdd(extendedFormat, roundingMode, multiplyResult, extendedAddArgument, prop(true), prop(false)).uf); 167 | // Custom rounder flags are ignored as they are not applicable in this case 168 | 169 | unpackedFloat roundedResult(rounder(format, roundingMode, additionResult)); 170 | 171 | // Note that multiplyResult.getSign() != roundedResult.getSign() in rare cases 172 | // the multiply special cases use the sign for zeros and infinities, thus the sign of the 173 | // result of the multiplication is needed (i.e. the xor of the sign of left and right multiply) 174 | // (-small, +inf, large) should trigger this as the desired result is -inf 175 | // but roundedResult.getSign() is positive. 176 | unpackedFloat roundedResultWithMultiplyCases(addMultiplySpecialCases(format, 177 | leftMultiply, 178 | rightMultiply, 179 | multiplyResult.getSign(), 180 | roundedResult)); 181 | 182 | 183 | // One disadvantage to having a flag for zero and default exponents and significands for zero 184 | // that are not (min, 0) is that the x + 0 case has to be handled by the addition special cases. 185 | // This means that you need the value of x, rounded to the correct format. 186 | // multiplyResult is in extended format, thus we have to use a second rounder just for this case. 187 | // It is not zero, inf or NaN so it only matters when addArgument is zero when it would be returned. 188 | 189 | unpackedFloat roundedMultiplyResult(rounder(format, roundingMode, multiplyResult)); 190 | // Optimisation : Try ITE before rounding so that only one rounder is needed 191 | 192 | 193 | // To make matters more awkward, we also need to apply the multiplicative special cases so that 194 | // (x*0) + y is correctly handled by the addition special cases. Without applying the 195 | // multiplicative ones, (x*0) would not be correctly flagged as 0. 196 | unpackedFloat roundedMultiplyResultWithMultiplyCases(addMultiplySpecialCases(format, 197 | leftMultiply, 198 | rightMultiply, 199 | multiplyResult.getSign(), 200 | roundedMultiplyResult)); 201 | // Optimisation : consolidate the special cases and verify against this 202 | 203 | unpackedFloat result(addAdditionSpecialCases(format, 204 | roundingMode, 205 | roundedMultiplyResultWithMultiplyCases, 206 | addArgument, 207 | roundedResultWithMultiplyCases, 208 | prop(true))); 209 | 210 | POSTCONDITION(result.valid(format)); 211 | 212 | return result; 213 | } 214 | 215 | 216 | } 217 | 218 | #endif 219 | -------------------------------------------------------------------------------- /core/ite.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** ite.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 03/12/14 24 | ** 25 | ** The handling of if-then-else depends on the type of both the condition 26 | ** (i.e. is it concrete or is it symbolic) and the type of the data 27 | ** (i.e. is it a symbolic class that wraps a tree node, is it a structure 28 | ** containing them, etc.). Some of the handling will work for any condition, 29 | ** any of the data, etc. So far not difficult in a language with multiple 30 | ** dispatch including type variables. 31 | ** 32 | ** However, we are using C++, so there are a few extra hoops to jump 33 | ** through. We declare ITEs as a struct containing a static function 34 | ** as then we can partially specialise templates of them. 35 | ** Specialisations of these are then given when appropriate types are 36 | ** introduced. Care must be taken with these to ensure that we don't 37 | ** get ambigious template instantiations. 38 | ** 39 | */ 40 | 41 | #ifndef SYMFPU_ITE 42 | #define SYMFPU_ITE 43 | 44 | namespace symfpu { 45 | 46 | template 47 | struct ite; 48 | 49 | // To avoid the need for putting the types *everywhere* we use a 50 | // helper function as C++ can perform type inference for functions 51 | // but not classes. 52 | template 53 | const data ITE (const prop &c, const data &l, const data &r) { 54 | return ite::iteOp(c, l, r); 55 | } 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /core/multiply.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** multiply.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 25/08/14 24 | ** 25 | ** Multiplication of arbitrary precision floats 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | #include "symfpu/core/ite.h" 31 | #include "symfpu/core/rounder.h" 32 | #include "symfpu/core/operations.h" 33 | 34 | #ifndef SYMFPU_MULTIPLY 35 | #define SYMFPU_MULTIPLY 36 | 37 | namespace symfpu { 38 | 39 | // sign == multiplyResult.getSign() normally but not for FMA, thus an argument is needed 40 | template 41 | unpackedFloat addMultiplySpecialCases (const typename t::fpt &format, 42 | const unpackedFloat &left, 43 | const unpackedFloat &right, 44 | const typename t::prop &sign, 45 | const unpackedFloat &multiplyResult) { 46 | typedef typename t::prop prop; 47 | 48 | prop eitherArgumentNan(left.getNaN() || right.getNaN()); 49 | prop generateNan((left.getInf() && right.getZero()) || 50 | (left.getZero() && right.getInf())); 51 | prop isNan(eitherArgumentNan || generateNan); 52 | 53 | prop isInf(left.getInf() || right.getInf()); 54 | 55 | prop isZero(left.getZero() || right.getZero()); 56 | 57 | return ITE(isNan, 58 | unpackedFloat::makeNaN(format), 59 | ITE(isInf, 60 | unpackedFloat::makeInf(format, sign), 61 | ITE(isZero, 62 | unpackedFloat::makeZero(format, sign), 63 | multiplyResult))); 64 | } 65 | 66 | template 67 | unpackedFloat arithmeticMultiply (const typename t::fpt &format, 68 | const unpackedFloat &left, 69 | const unpackedFloat &right) { 70 | typedef typename t::bwt bwt; 71 | typedef typename t::prop prop; 72 | typedef typename t::ubv ubv; 73 | typedef typename t::sbv sbv; 74 | typedef typename t::fpt fpt; 75 | 76 | PRECONDITION(left.valid(format)); 77 | PRECONDITION(right.valid(format)); 78 | 79 | // Compute sign 80 | prop multiplySign(left.getSign() ^ right.getSign()); 81 | 82 | // Multiply the significands 83 | ubv significandProduct(expandingMultiply(left.getSignificand(), right.getSignificand())); 84 | // Optimisation : low bits are not needed apart from the guard and sticky bits 85 | // Optimisation : top bits accurately predict whether re-alignment is needed 86 | 87 | bwt spWidth(significandProduct.getWidth()); 88 | ubv topBit(significandProduct.extract(spWidth - 1, spWidth - 1)); 89 | ubv nextBit(significandProduct.extract(spWidth - 2, spWidth - 2)); 90 | 91 | // Alignment of inputs means at least one of the two MSB is 1 92 | // i.e. [1,2) * [1,2) = [1,4) 93 | // topBitSet is the likely case 94 | prop topBitSet(topBit.isAllOnes()); 95 | INVARIANT(topBitSet || nextBit.isAllOnes()); 96 | probabilityAnnotation(topBitSet, LIKELY); 97 | 98 | // Re-align 99 | ubv alignedSignificand(conditionalLeftShiftOne(!topBitSet, significandProduct)); // Will not loose information 100 | 101 | // Add up exponents 102 | #if 0 103 | sbv exponentSum(expandingAdd(left.getExponent(),right.getExponent())); 104 | sbv min(unpackedFloat::minSubnormalExponent(format)); 105 | sbv max(unpackedFloat::maxNormalExponent(format)); 106 | INVARIANT(expandingAdd(min,min) <= exponentSum); 107 | INVARIANT(exponentSum <= expandingAdd(max, max)); 108 | // Optimisation : use the if-then-lazy-else to avoid multiplying for underflow and overflow 109 | // subnormal * subnormal does not need to be evaluated 110 | // may be best done in the rounder along with underflow 111 | #endif 112 | 113 | sbv alignedExponent(expandingAddWithCarryIn(left.getExponent(),right.getExponent(), topBitSet)); 114 | 115 | 116 | // Put back together 117 | unpackedFloat multiplyResult(multiplySign, alignedExponent, alignedSignificand); 118 | 119 | 120 | fpt extendedFormat(format.exponentWidth() + 1, format.significandWidth() * 2); 121 | POSTCONDITION(multiplyResult.valid(extendedFormat)); 122 | 123 | return multiplyResult; 124 | } 125 | 126 | 127 | // Put it all together... 128 | template 129 | unpackedFloat multiply (const typename t::fpt &format, 130 | const typename t::rm &roundingMode, 131 | const unpackedFloat &left, 132 | const unpackedFloat &right) { 133 | //typedef typename t::bwt bwt; 134 | //typedef typename t::prop prop; 135 | //typedef typename t::ubv ubv; 136 | //typedef typename t::sbv sbv; 137 | 138 | PRECONDITION(left.valid(format)); 139 | PRECONDITION(right.valid(format)); 140 | 141 | unpackedFloat multiplyResult(arithmeticMultiply(format, left, right)); 142 | 143 | unpackedFloat roundedMultiplyResult(rounder(format, roundingMode, multiplyResult)); 144 | 145 | unpackedFloat result(addMultiplySpecialCases(format, left, right, roundedMultiplyResult.getSign(), roundedMultiplyResult)); 146 | 147 | POSTCONDITION(result.valid(format)); 148 | 149 | return result; 150 | } 151 | 152 | 153 | } 154 | 155 | #endif 156 | 157 | -------------------------------------------------------------------------------- /core/operations.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** operations.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 15/11/14 24 | ** 25 | ** A number of compound operations on bit-vectors. These are default 26 | ** implementations to reduce the amount of code that is needed for a 27 | ** back-end (and the risk of making a mistake). Back-ends can provide 28 | ** their own implementations of these if they can handle them in a 29 | ** smarter way than the default. 30 | ** 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | #include "../utils/common.h" 37 | 38 | 39 | #ifndef SYMFPU_OPERATIONS 40 | #define SYMFPU_OPERATIONS 41 | 42 | namespace symfpu { 43 | 44 | /*** Expanding operations ***/ 45 | template 46 | bv expandingAdd (const bv &op1, const bv &op2) { 47 | PRECONDITION(op1.getWidth() == op2.getWidth()); 48 | 49 | bv x(op1.extend(1)); 50 | bv y(op2.extend(1)); 51 | 52 | return x + y; 53 | } 54 | 55 | template 56 | bv expandingAddWithCarryIn (const bv &op1, const bv &op2, const prop &cin) { 57 | PRECONDITION(op1.getWidth() == op2.getWidth()); 58 | 59 | bv x(op1.extend(1)); 60 | bv y(op2.extend(1)); 61 | 62 | bv sum(x + y); 63 | 64 | typename t::bwt w(sum.getWidth()); 65 | bv carry(ITE(cin, bv::one(w), bv::zero(w))); 66 | bv res(sum.modularAdd(carry)); // Modular is safe due to the extension 67 | // (2^n - 1) + (2^n - 1) + 1 == 2^(n+1) - 1 68 | // -(2^n) + -(2^n) + 1 > 2^(n+1) 69 | return res; 70 | } 71 | 72 | template 73 | bv expandingSubtract (const bv &op1, const bv &op2) { 74 | PRECONDITION(op1.getWidth() == op2.getWidth()); 75 | 76 | bv x(op1.extend(1)); 77 | bv y(op2.extend(1)); 78 | 79 | return x - y; 80 | } 81 | 82 | template 83 | bv expandingMultiply (const bv &op1, const bv &op2) { 84 | typename t::bwt width = op1.getWidth(); 85 | PRECONDITION(width == op2.getWidth()); 86 | 87 | bv x(op1.extend(width)); 88 | bv y(op2.extend(width)); 89 | 90 | return x * y; 91 | } 92 | 93 | 94 | /*** Conditional Operations ***/ 95 | template 96 | bv conditionalIncrement (const prop &p, const bv &b) { 97 | PRECONDITION(IMPLIES(p, b < bv::maxValue(b.getWidth()))); 98 | 99 | typename t::bwt w(b.getWidth()); 100 | bv inc(ITE(p, bv::one(w), bv::zero(w))); 101 | 102 | return b + inc; 103 | } 104 | 105 | template 106 | bv conditionalDecrement (const prop &p, const bv &b) { 107 | PRECONDITION(IMPLIES(p, bv::minValue(b.getWidth()) < b)); 108 | 109 | typename t::bwt w(b.getWidth()); 110 | bv inc(ITE(p, bv::one(w), bv::zero(w))); 111 | 112 | return b - inc; 113 | } 114 | 115 | template 116 | bv conditionalLeftShiftOne (const prop &p, const bv &b) { 117 | typename t::bwt w(b.getWidth()); 118 | PRECONDITION(IMPLIES(p, (b.extract(w - 1, w - 1).isAllZeros()))); 119 | 120 | bv shifted(b.modularLeftShift(bv::one(w))); 121 | return bv(ITE(p, shifted, b)); 122 | } 123 | 124 | template 125 | bv conditionalRightShiftOne (const prop &p, const bv &b) { 126 | typename t::bwt w(b.getWidth()); 127 | // PRECONDITION(IMPLIES(p, (b.extract(0, 0).isAllZeros()))); // Adder uses and compensates for this case. 128 | 129 | bv shifted(b.modularRightShift(bv::one(w))); 130 | return bv(ITE(p, shifted, b)); 131 | } 132 | 133 | template 134 | bv conditionalNegate (const prop &p, const bv &b) { 135 | typename t::bwt w(b.getWidth()); 136 | PRECONDITION(w >= 2); 137 | PRECONDITION(IMPLIES(p, !(b.extract(w - 1, w - 1).isAllOnes() && 138 | b.extract(w - 2, 0).isAllZeros()))); 139 | 140 | return bv(ITE(p, -b, b)); 141 | } 142 | 143 | template 144 | bv abs(const bv &b) { 145 | return conditionalNegate(b < bv::zero(b.getWidth()), b); 146 | } 147 | 148 | 149 | 150 | /*** Probability Annotations ***/ 151 | enum probability { 152 | VERYLIKELY = 100, 153 | LIKELY = 50, 154 | NEUTRAL = 0, 155 | UNLIKELY = -50, 156 | VERYUNLIKELY = -100 157 | }; 158 | 159 | template 160 | void probabilityAnnotation (const prop &, const probability &) { 161 | // Back-ends can make use of this information if they want 162 | return; 163 | } 164 | 165 | 166 | /*** Max and min ***/ 167 | template 168 | bv max (const bv &op1, const bv &op2) { 169 | return ITE(op1 <= op2, op2, op1); 170 | } 171 | 172 | template 173 | bv min (const bv &op1, const bv &op2) { 174 | return ITE(op1 <= op2, op1, op2); 175 | } 176 | 177 | template 178 | bv collar(const bv &op, const bv &lower, const bv &upper) { 179 | return ITE(op < lower, 180 | lower, 181 | ITE(upper < op, 182 | upper, 183 | op)); 184 | } 185 | 186 | 187 | /*** Unary/Binary operations ***/ 188 | template 189 | bv countLeadingZerosRec (const bv &op, const bwt position, const prop &allPreceedingZeros) { 190 | typename t::bwt w(op.getWidth()); 191 | 192 | PRECONDITION(0 <= position && position < w); 193 | 194 | bv bit(op.extract(position, position)); 195 | 196 | prop isLeadingOne(allPreceedingZeros && (bit.isAllOnes())); 197 | prop continuingZero(allPreceedingZeros && (bit.isAllZeros())); 198 | 199 | if (position == 0) { 200 | return ITE(isLeadingOne, bv(w, w - 1), bv(w, w)); 201 | } else { 202 | return ITE(isLeadingOne, 203 | bv(w, w - (position + 1)), 204 | countLeadingZerosRec(op, position - 1, continuingZero)); 205 | } 206 | } 207 | 208 | template 209 | bv countLeadingZeros (const bv &op) { 210 | typedef typename t::bwt bwt; 211 | typedef typename t::prop prop; 212 | bwt w(op.getWidth()); 213 | 214 | return countLeadingZerosRec(op, w - 1, prop(true)); 215 | } 216 | 217 | // This is sort of the opposite of count trailing 1's (a.k.a. clz(reverse(not(x))) ) 218 | template 219 | bv orderEncode (const bv &op) { 220 | typename t::bwt w(op.getWidth()); 221 | 222 | //PRECONDITION(bv::zero(w) <= op && op <= bv(w, w)); // Not needed as using modular shift 223 | 224 | bv tmp((bv::one(w + 1).modularLeftShift(op.resize(w + 1))).modularDecrement().extract(w-1,0)); 225 | return tmp; 226 | } 227 | 228 | 229 | // The comparison we need to do is 230 | // op.extract(relevantBits - 1, 0) == bv(relevantBits, position + 1) 231 | // bits can be shared between instances of this. 232 | // The following is a dynamic programming style solution. 233 | // HOWEVER : it may not actually give a net saving depending on your application 234 | template 235 | struct fragmentMap { 236 | typedef typename t::bwt bwt; 237 | typedef typename t::prop prop; 238 | 239 | typedef std::pair fragment; 240 | typedef std::map map; 241 | 242 | protected : 243 | const bv &op; 244 | map m; 245 | 246 | prop getComparitorRec(bwt length, bwt value) 247 | { 248 | PRECONDITION(length > 0); 249 | PRECONDITION(bitsToRepresent(value) <= length); 250 | typename map::const_iterator it = m.find(std::make_pair(length, value)); 251 | 252 | if (it != m.end()) { 253 | return it->second; 254 | } else { 255 | bwt leadingBit = bwt(1) << (length - 1); 256 | prop leadingBitIsOne(op.extract(length - 1, length - 1).isAllOnes()); 257 | prop correctComparison((value & leadingBit) ? 258 | leadingBitIsOne : !leadingBitIsOne); 259 | prop *step = NULL; 260 | 261 | if (length == 1) { 262 | step = new prop(correctComparison); 263 | } else { 264 | prop rec(getComparitorRec(length - 1, value & (~leadingBit))); 265 | step = new prop(correctComparison && rec); 266 | } 267 | 268 | prop res(*step); 269 | delete step; 270 | 271 | m.insert(std::make_pair(std::make_pair(length, value), res)); 272 | return res; 273 | } 274 | } 275 | 276 | public : 277 | fragmentMap(const bv &_op) : op(_op) {} 278 | 279 | prop getComparitor(bwt length, bwt value) 280 | { 281 | PRECONDITION(length > 0); 282 | PRECONDITION(bitsToRepresent(value) <= length); 283 | 284 | prop res(getComparitorRec(length, value)); 285 | 286 | POSTCONDITION(bv(res) == (op.extract(length - 1, 0) == bv(length, value))); 287 | return res; 288 | } 289 | }; 290 | 291 | 292 | // A more compact, bitwise implementation of orderEncode for SAT encoding 293 | // Intended to be used in specialisation of orderEncode 294 | template 295 | bv orderEncodeBitwise (const bv &op) { 296 | typedef typename t::bwt bwt; 297 | bwt w(op.getWidth()); 298 | 299 | fragmentMap m(op); 300 | 301 | // If op is too large, then set everything to 1 302 | bv outOfRange(op >= bv(w, w)); 303 | 304 | // SAND to fill in the remaining bits 305 | bv * working = new bv(outOfRange); 306 | for (bwt i = w; i > 0; --i) { 307 | bwt position = i - 1; // Position in the output bitvectors 308 | bwt relevantBits = bitsToRepresent(position + 1); 309 | INVARIANT(relevantBits > 0); 310 | 311 | //bv activateBit(m.getComparitor(relevantBits, position + 1)); // No more compact and slower 312 | bv activateBit(op.extract(relevantBits - 1, 0) == bv(relevantBits, position + 1)); 313 | bv nextBit(working->extract(0,0) | activateBit); 314 | 315 | bv * tmp = working; 316 | working = new bv(working->append(nextBit)); 317 | delete tmp; 318 | } 319 | 320 | bv output(working->extract(w - 1,0)); 321 | delete working; 322 | 323 | POSTCONDITION(output == (bv::one(w + 1).modularLeftShift(op.resize(w + 1))).modularDecrement().extract(w-1,0)); 324 | 325 | return output; 326 | } 327 | 328 | 329 | /*** Custom shifts ***/ 330 | // 1 if and only if the right shift moves at least one 1 out of the word 331 | template 332 | bv rightShiftStickyBit (const bv &op, const bv &shift) { 333 | bv stickyBit(ITE((orderEncode(shift) & op).isAllZeros(), 334 | bv::zero(op.getWidth()), 335 | bv::one(op.getWidth()))); 336 | 337 | return stickyBit; 338 | } 339 | 340 | 341 | // It is easier to compute along with the shift 342 | template 343 | struct stickyRightShiftResult { 344 | typedef typename t::ubv ubv; 345 | 346 | ubv signExtendedResult; 347 | ubv stickyBit; 348 | 349 | stickyRightShiftResult(const ubv &ser, const ubv &sb) : signExtendedResult(ser), stickyBit(sb) {} 350 | stickyRightShiftResult(const stickyRightShiftResult &old) : signExtendedResult(old.signExtendedResult), stickyBit(old.stickyBit) {} 351 | }; 352 | 353 | 354 | template 355 | stickyRightShiftResult stickyRightShift (const typename t::ubv &input, const typename t::ubv &shiftAmount) { 356 | stickyRightShiftResult res(input.signExtendRightShift(shiftAmount), rightShiftStickyBit(input, shiftAmount)); 357 | 358 | return res; 359 | } 360 | 361 | 362 | template 363 | stickyRightShiftResult stickyRightShiftBitwise (const typename t::ubv &input, const typename t::ubv &shiftAmount) { 364 | typedef typename t::bwt bwt; 365 | typedef typename t::prop prop; 366 | typedef typename t::ubv ubv; 367 | 368 | bwt width(input.getWidth()); 369 | bwt startingPosition(positionOfLeadingOne(width)); 370 | INVARIANT(0 < startingPosition && startingPosition < width); 371 | 372 | // Catch the out of bounds case 373 | PRECONDITION(shiftAmount.getWidth() == width); 374 | prop fullShift(shiftAmount >= ubv(width, width)); 375 | // Note the shiftAmount is treated as unsigned... 376 | 377 | ubv *working = new ubv(input); 378 | prop *stickyBit = new prop(ITE(fullShift, !input.isAllZeros(), prop(false))); 379 | 380 | for (bwt i = startingPosition + 1; i > 0; --i) 381 | { 382 | bwt shiftAmountPosition = i - 1; 383 | 384 | prop shiftEnabled = fullShift || shiftAmount.extract(shiftAmountPosition, shiftAmountPosition).isAllOnes(); 385 | 386 | prop stickyAccumulate(shiftEnabled && !(working->extract((1ULL << shiftAmountPosition) - 1, 0).isAllZeros())); // Would this loose data? 387 | 388 | prop * tmp = stickyBit; 389 | stickyBit = new prop(*stickyBit || stickyAccumulate); 390 | delete tmp; 391 | 392 | 393 | // Note the slightly unexpected sign extension 394 | ubv shifted(working->signExtendRightShift(ubv::one(width) << ubv(width, shiftAmountPosition))); 395 | 396 | ubv * workingTmp = working; 397 | working = new ubv(ITE(shiftEnabled, shifted, *working)); 398 | delete workingTmp; 399 | } 400 | 401 | stickyRightShiftResult res(*working, ubv(*stickyBit).extend(width - 1)); 402 | 403 | delete working; 404 | delete stickyBit; 405 | 406 | POSTCONDITION(res.signExtendedResult == input.signExtendRightShift(shiftAmount)); 407 | POSTCONDITION(res.stickyBit == rightShiftStickyBit(input, shiftAmount)); 408 | 409 | return res; 410 | } 411 | 412 | 413 | 414 | template 415 | struct normaliseShiftResult { 416 | typedef typename t::ubv ubv; 417 | typedef typename t::prop prop; 418 | 419 | ubv normalised; 420 | ubv shiftAmount; 421 | prop isZero; 422 | 423 | normaliseShiftResult(const ubv &n, const ubv &s, const prop &z) : normalised(n), shiftAmount(s), isZero(z) {} 424 | normaliseShiftResult(const normaliseShiftResult &old) : normalised(old.normalised), shiftAmount(old.shiftAmount), isZero(old.isZero) {} 425 | }; 426 | 427 | template 428 | normaliseShiftResult normaliseShift (const typename t::ubv input) { 429 | typedef typename t::bwt bwt; 430 | typedef typename t::prop prop; 431 | typedef typename t::ubv ubv; 432 | 433 | bwt width(input.getWidth()); 434 | bwt startingMask(previousPowerOfTwo(width)); 435 | INVARIANT(startingMask < width); 436 | 437 | // Catch the zero case 438 | prop zeroCase(input.isAllZeros()); 439 | 440 | ubv *working = new ubv(input); 441 | ubv *shiftAmount = NULL; 442 | prop *deactivateShifts = new prop(zeroCase); 443 | 444 | for (bwt i = startingMask; i > 0; i >>= 1) { 445 | prop newDeactivateShifts = *deactivateShifts || working->extract(width-1,width-1).isAllOnes(); 446 | delete deactivateShifts; 447 | deactivateShifts = new prop(newDeactivateShifts); 448 | 449 | ubv mask(ubv::allOnes(i).append(ubv::zero(width - i))); 450 | prop shiftNeeded(!(*deactivateShifts) && (mask & *working).isAllZeros()); 451 | 452 | // Modular is safe because of the mask comparison 453 | ubv shifted(ITE(shiftNeeded, working->modularLeftShift(ubv(width, i)), *working)); 454 | delete working; 455 | working = new ubv(shifted); 456 | 457 | if (shiftAmount == NULL) { 458 | shiftAmount = new ubv(shiftNeeded); 459 | } else { 460 | ubv newShiftAmount = shiftAmount->append(ubv(shiftNeeded)); 461 | delete shiftAmount; 462 | shiftAmount = new ubv(newShiftAmount); 463 | } 464 | } 465 | 466 | normaliseShiftResult res(*working, *shiftAmount, zeroCase); 467 | 468 | delete deactivateShifts; 469 | delete working; 470 | delete shiftAmount; 471 | 472 | POSTCONDITION(res.normalised.extract(width-1,width-1).isAllZeros() == res.isZero); 473 | POSTCONDITION(IMPLIES(res.isZero, res.shiftAmount.isAllZeros())); 474 | 475 | bwt shiftAmountWidth(res.shiftAmount.getWidth()); 476 | bwt widthBits(bitsToRepresent(width)); 477 | POSTCONDITION(shiftAmountWidth == widthBits || 478 | shiftAmountWidth == widthBits - 1); // If width is an exact power of 2 479 | ubv widthBV(widthBits, width); 480 | POSTCONDITION(res.shiftAmount.matchWidth(widthBV) < widthBV); 481 | 482 | return res; 483 | } 484 | 485 | 486 | /*** Dividers ***/ 487 | template 488 | struct resultWithRemainderBit { 489 | typedef typename t::ubv ubv; 490 | typedef typename t::prop prop; 491 | 492 | ubv result; 493 | prop remainderBit; 494 | 495 | resultWithRemainderBit(const ubv &o, const prop &r) : result(o), remainderBit(r) {} 496 | resultWithRemainderBit(const resultWithRemainderBit &old) : result(old.result), remainderBit(old.remainderBit) {} 497 | }; 498 | 499 | // x and y are fixed-point numbers in the range [1,2) 500 | // Compute o \in [0.5,2), r \in [0,\delta) such that: x = o*y + r 501 | // Return (o, r != 0) 502 | template 503 | resultWithRemainderBit fixedPointDivide (const typename t::ubv &x, const typename t::ubv &y) { 504 | typename t::bwt w(x.getWidth()); 505 | 506 | // Same width and both have MSB ones 507 | PRECONDITION(y.getWidth() == w); 508 | PRECONDITION(x.extract(w - 1, w - 1).isAllOnes()); 509 | PRECONDITION(y.extract(w - 1, w - 1).isAllOnes()); 510 | 511 | typedef typename t::ubv ubv; 512 | 513 | // Not the best way of doing this but pretty universal 514 | ubv ex(x.append(ubv::zero(w - 1))); 515 | ubv ey(y.extend(w - 1)); 516 | 517 | ubv div(ex / ey); 518 | ubv rem(ex % ey); 519 | 520 | return resultWithRemainderBit(div.extract(w - 1, 0), !(rem.isAllZeros())); 521 | } 522 | 523 | 524 | // x is a fixed-point number in the range [1,4) with 2/p bits 525 | // Compute o \in [1,sqrt(2)), r \in [0,o*2 + 1) such that x = o*o + r with 1/p bits 526 | // Return (o, r != 0) 527 | template 528 | resultWithRemainderBit fixedPointSqrt (const typename t::ubv &x) { 529 | typedef typename t::bwt bwt; 530 | typedef typename t::ubv ubv; 531 | typedef typename t::prop prop; 532 | 533 | // The default algorithm given here isn't a great one 534 | // However it is simple and has a very simple termination criteria. 535 | // Plus most symbolic back ends will prefer 536 | // o = nondet(), r = nondet(), assert(r < o*2 + 1), assert(x = o*o + r) 537 | 538 | bwt inputWidth(x.getWidth()); 539 | bwt outputWidth(inputWidth - 1); 540 | 541 | // To compare against, we need to pad x to 2/2p 542 | ubv xcomp(x.append(ubv::zero(inputWidth - 2))); 543 | 544 | // Start at 1 545 | ubv working(ubv::one(outputWidth) << ubv(outputWidth, outputWidth - 1)); 546 | 547 | bwt location; 548 | for (location = outputWidth - 1; location > 0; --location) { // Offset by 1 for easy termination 549 | ubv shift(ubv(outputWidth, location - 1)); 550 | 551 | ubv candidate(working | (ubv::one(outputWidth) << shift)); 552 | 553 | prop addBit(expandingMultiply(candidate, candidate) <= xcomp); 554 | 555 | working = working | (ubv(addBit).extend(outputWidth - 1) << shift); 556 | } 557 | 558 | return resultWithRemainderBit(working, !(expandingMultiply(working, working) == xcomp)); 559 | } 560 | 561 | // One step of a divider 562 | // Here the "remainder bit" is actual the result bit and 563 | // The result is the remainder 564 | template 565 | resultWithRemainderBit divideStep (const typename t::ubv &x, const typename t::ubv &y) { 566 | typedef typename t::bwt bwt; 567 | typedef typename t::ubv ubv; 568 | typedef typename t::prop prop; 569 | 570 | bwt xWidth(x.getWidth()); 571 | bwt yWidth(y.getWidth()); 572 | 573 | PRECONDITION(xWidth == yWidth); 574 | PRECONDITION(yWidth >= 2); 575 | PRECONDITION(y.extract(yWidth - 2, yWidth - 2).isAllOnes()); // Assume y is aligned 576 | 577 | prop canSubtract(x >= y); 578 | ubv sub(x.modularAdd(y.modularNegate())); // TODO : modular subtract or better 579 | ubv step(ITE(canSubtract, sub, x)); 580 | 581 | return resultWithRemainderBit(step << ubv::one(xWidth), canSubtract); 582 | } 583 | } 584 | 585 | #endif 586 | -------------------------------------------------------------------------------- /core/packing.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** packing.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 03/06/14 24 | ** 25 | ** Algorithms for converting from a packed float (a bit vector) into 26 | ** the working, unpacked float format. Should be instantiated with a 27 | ** traits structure from one of the baseTypes/ implementations. 28 | ** 29 | */ 30 | 31 | #include "symfpu/core/unpackedFloat.h" 32 | 33 | #ifndef SYMFPU_PACKING 34 | #define SYMFPU_PACKING 35 | 36 | namespace symfpu { 37 | 38 | template 39 | unpackedFloat unpack (const typename t::fpt format, const typename t::ubv &packedFloat) { 40 | typedef typename t::bwt bwt; 41 | typedef typename t::prop prop; 42 | typedef typename t::ubv ubv; 43 | typedef typename t::sbv sbv; 44 | 45 | bwt pWidth = format.packedWidth(); 46 | bwt exWidth = format.packedExponentWidth(); 47 | bwt sigWidth = format.packedSignificandWidth(); 48 | 49 | PRECONDITION(packedFloat.getWidth() == pWidth); 50 | 51 | // Extract 52 | ubv packedSignificand(packedFloat.extract(sigWidth - 1, 0)); 53 | ubv packedExponent(packedFloat.extract(sigWidth + exWidth - 1, sigWidth)); 54 | prop sign(packedFloat.extract(pWidth - 1, sigWidth + exWidth).isAllOnes()); 55 | 56 | // Prepare the normal and subnormal cases 57 | bwt unpackedExWidth = unpackedFloat::exponentWidth(format); 58 | bwt unpackedSigWidth = unpackedFloat::significandWidth(format); 59 | 60 | INVARIANT(unpackedExWidth > exWidth); // To avoid overflow 61 | sbv biasedExponent(packedExponent.extend(unpackedExWidth - exWidth).toSigned() - unpackedFloat::bias(format)); 62 | // Optimisation : both the normal and subnormal paths subtract a constant 63 | // from the exponent as the last step (bias and minNormalExponent respectively) 64 | 65 | ubv significandWithLeadingZero(packedSignificand.extend(unpackedSigWidth - sigWidth)); 66 | ubv significandWithLeadingOne(unpackedFloat::leadingOne(unpackedFloat::significandWidth(format)) | significandWithLeadingZero); 67 | 68 | unpackedFloat ufNormal(sign, biasedExponent, significandWithLeadingOne); 69 | unpackedFloat ufSubnormalBase(sign, unpackedFloat::minNormalExponent(format), significandWithLeadingZero); 70 | 71 | // Optimisation : right shift the significand by one if subnormal 72 | // and then set the carry in when you add to the exponent. 73 | // May be sufficient to just assert that it has a leading zero 74 | 75 | 76 | // Analyse 77 | prop zeroExponent(packedExponent.isAllZeros()); 78 | prop onesExponent(packedExponent.isAllOnes()); 79 | prop zeroSignificand(significandWithLeadingZero.isAllZeros()); // Shared with normaliseUp 80 | 81 | // Identify the cases 82 | prop isZero(zeroExponent && zeroSignificand); 83 | prop isSubnormal(zeroExponent && !zeroSignificand); 84 | prop isNormal(!zeroExponent && !onesExponent); 85 | prop isInf(onesExponent && zeroSignificand); 86 | prop isNaN(onesExponent && !zeroSignificand); 87 | 88 | INVARIANT(isZero || isSubnormal || isNormal || isInf || isNaN); 89 | 90 | probabilityAnnotation(isSubnormal, UNLIKELY); 91 | 92 | // Splice together 93 | unpackedFloat uf(ITE(isNaN, 94 | unpackedFloat::makeNaN(format), 95 | ITE(isInf, 96 | unpackedFloat::makeInf(format, sign), 97 | ITE(isZero, 98 | unpackedFloat::makeZero(format, sign), 99 | ITE(!isSubnormal, 100 | ufNormal, 101 | ufSubnormalBase.normaliseUp(format) ))))); 102 | 103 | POSTCONDITION(uf.valid(format)); 104 | 105 | return uf; 106 | } 107 | 108 | 109 | template 110 | typename t::ubv pack (const typename t::fpt &format, const unpackedFloat &uf) { 111 | typedef typename t::bwt bwt; 112 | typedef typename t::prop prop; 113 | typedef typename t::ubv ubv; 114 | typedef typename t::sbv sbv; 115 | 116 | PRECONDITION(uf.valid(format)); 117 | 118 | // Sign 119 | ubv packedSign(uf.getSign()); 120 | 121 | // Exponent 122 | bwt packedExWidth = format.packedExponentWidth(); 123 | 124 | prop inNormalRange(uf.inNormalRange(format, prop(true))); 125 | INVARIANT(inNormalRange || uf.inSubnormalRange(format, prop(true))); // Default values ensure this. 126 | //prop inSubnormalRange(uf.inSubnormalRange(format)); // Allowing this optimisation 127 | prop inSubnormalRange(!inNormalRange); 128 | 129 | probabilityAnnotation(inNormalRange, LIKELY); 130 | probabilityAnnotation(inSubnormalRange, UNLIKELY); 131 | 132 | sbv biasedExp(uf.getExponent() + unpackedFloat::bias(format)); 133 | // Will be correct for normal values only, subnormals may still be negative. 134 | ubv packedBiasedExp(biasedExp.toUnsigned().extract(packedExWidth - 1,0)); 135 | 136 | ubv maxExp(ubv::allOnes(packedExWidth)); 137 | ubv minExp(ubv::zero(packedExWidth)); 138 | 139 | prop hasMaxExp(uf.getNaN() || uf.getInf()); 140 | prop hasMinExp(uf.getZero() || inSubnormalRange); 141 | prop hasFixedExp(hasMaxExp || hasMinExp); 142 | 143 | ubv packedExp(ITE(hasFixedExp, 144 | ITE(hasMaxExp, maxExp, minExp), 145 | packedBiasedExp)); 146 | 147 | 148 | // Significand 149 | bwt packedSigWidth = format.packedSignificandWidth(); 150 | ubv unpackedSignificand(uf.getSignificand()); 151 | 152 | INVARIANT(packedSigWidth == unpackedSignificand.getWidth() - 1); 153 | ubv dropLeadingOne(unpackedSignificand.extract(packedSigWidth - 1,0)); 154 | ubv correctedSubnormal((unpackedSignificand >> (uf.getSubnormalAmount(format).toUnsigned().matchWidth(unpackedSignificand))).extract(packedSigWidth - 1,0)); 155 | 156 | prop hasFixedSignificand(uf.getNaN() || uf.getInf() || uf.getZero()); 157 | 158 | ubv packedSig(ITE(hasFixedSignificand, 159 | ITE(uf.getNaN(), 160 | unpackedFloat::nanPattern(packedSigWidth), 161 | ubv::zero(packedSigWidth)), 162 | ITE(inNormalRange, 163 | dropLeadingOne, 164 | correctedSubnormal))); 165 | 166 | 167 | // Finish up 168 | ubv packed(packedSign.append(packedExp).append(packedSig)); 169 | 170 | POSTCONDITION(packed.getWidth() == format.packedWidth()); 171 | 172 | return packed; 173 | } 174 | 175 | } 176 | 177 | #endif 178 | -------------------------------------------------------------------------------- /core/remainder.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** remainder.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 14/12/16 24 | ** 25 | ** Computing the IEEE-754 remainder of arbitrary precision floats 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | #include "symfpu/core/ite.h" 31 | #include "symfpu/core/rounder.h" 32 | #include "symfpu/core/operations.h" 33 | #include "symfpu/core/add.h" 34 | #include "symfpu/core/sign.h" 35 | 36 | 37 | #ifndef SYMFPU_REMAINDER 38 | #define SYMFPU_REMAINDER 39 | 40 | namespace symfpu { 41 | 42 | template 43 | unpackedFloat addRemainderSpecialCases (const typename t::fpt &format, 44 | const unpackedFloat &left, 45 | const unpackedFloat &right, 46 | const unpackedFloat &remainderResult) { 47 | typedef typename t::prop prop; 48 | 49 | prop eitherArgumentNan(left.getNaN() || right.getNaN()); 50 | prop generateNan(left.getInf() || right.getZero()); 51 | prop isNan(eitherArgumentNan || generateNan); 52 | 53 | prop passThrough((!(left.getInf() || left.getNaN()) && right.getInf()) || 54 | left.getZero()); 55 | 56 | return ITE(isNan, 57 | unpackedFloat::makeNaN(format), 58 | ITE(passThrough, 59 | left, 60 | remainderResult)); 61 | } 62 | 63 | /* Let left = x*2^e, right = y*2^f, x \in [1,2), y \in [1,2) 64 | * x/y \in (0.5,2) x > y x/y \in (1,2) x < y (0.5,1) 65 | * 66 | * rem = x*2^e - (y*2^f * int((x*2^e) / (y*2^f))) 67 | * = x*2^e - (y*2^f * int((x/y) * 2^{e-f})) 68 | * = (x*2^{e-f} - (y * int((x/y) * 2^{e-f}))) * 2^f 69 | * 70 | * 71 | * If e - f > 0 72 | * = (x*2^{e-f} - (y * int((x*2^{e-f})/y)) * 2^f 73 | * 74 | * 75 | * If e - f == 0 76 | * = (x - (y * int((x/y) ))) * 2^f 77 | * = ITTE(x ?= y, 78 | * (x - (y * int[guard=1,sticky=1])) * 2^f 79 | * (x - y) * 2^f, 80 | * ...) 81 | * = ITTE(x ?= y, 82 | * (x - (y * int[guard=1,sticky=1])) * 2^f 83 | * left - right, 84 | * ...) 85 | * 86 | * 87 | * If e - f == -1 88 | * = (x*2^{-1} - (y * int((x/y) * 2^{-1 }))) * 2^f 89 | * = ITTE(x ?= y, 90 | * (x*2^{-1} - (y * int[guard=0,sticky=1])) * 2^f 91 | * (x*2^{-1} - (y * int[guard=1,sticky=0])) * 2^f 92 | * (x*2^{-1} - (y * int[guard=1,sticky=1])) * 2^f 93 | * 94 | * If e - f <= -2 95 | * = (x*2^{e-f} - (y * int[guard=0,sticky=1])) * 2^f 96 | * = ITE(int[guard=0,sticky=1], 97 | * x*2^e - y*2^f, 98 | * left) 99 | * = ITE(int[guard=0,sticky=1], 100 | * left - right, 101 | * left) 102 | * 103 | */ 104 | 105 | // Divide for max(e - f, 0) cycles 106 | // The equal case, if you divide you use to extract the even bit of n, also save the rem. 107 | // Then one more cycle for the guard bit 108 | // Use that remainder to work out the sticky bit 109 | // Round and either subtract or not from saved rem 110 | // Output at 2^f 111 | 112 | template 113 | unpackedFloat arithmeticRemainder (const typename t::fpt &format, 114 | const typename t::rm &roundingMode, 115 | const unpackedFloat &left, 116 | const unpackedFloat &right) { 117 | typedef typename t::bwt bwt; 118 | typedef typename t::prop prop; 119 | typedef typename t::ubv ubv; 120 | typedef typename t::sbv sbv; 121 | //typedef typename t::fpt fpt; 122 | 123 | PRECONDITION(left.valid(format)); 124 | PRECONDITION(right.valid(format)); 125 | 126 | // Compute sign 127 | prop remainderSign(left.getSign()); 128 | 129 | 130 | // Compute exponent difference 131 | sbv exponentDifference(expandingSubtract(left.getExponent(), right.getExponent())); 132 | bwt edWidth(exponentDifference.getWidth()); 133 | 134 | // Extend for divide steps 135 | ubv lsig(left.getSignificand().extend(1)); 136 | ubv rsig(right.getSignificand().extend(1)); 137 | 138 | 139 | ubv first(divideStep(lsig,rsig).result); 140 | ubv *running = new ubv(first); // To avoid running out of stack space loop with a pointer 141 | 142 | bwt maxDifference = unpackedFloat::maximumExponentDifference(format); 143 | for (bwt i = maxDifference - 1; i > 0; i--) { 144 | prop needPrevious(exponentDifference > sbv(edWidth, i)); 145 | probabilityAnnotation(needPrevious, (i > (maxDifference / 2)) ? VERYUNLIKELY : UNLIKELY); 146 | 147 | ubv r(ITE(needPrevious, *running, lsig)); 148 | delete running; // We assume the value / reference has been transfered to ITE 149 | running = new ubv(divideStep(r, rsig).result); 150 | } 151 | 152 | // The zero exponent difference case is a little different 153 | // as we need the result bit for the even flag 154 | // and the actual result for the final 155 | prop lsbRoundActive(exponentDifference > -sbv::one(edWidth)); // i.e. >= 0 156 | 157 | prop needPrevious(exponentDifference > sbv::zero(edWidth)); 158 | probabilityAnnotation(needPrevious, UNLIKELY); 159 | 160 | ubv r0(ITE(needPrevious, *running, lsig)); 161 | delete running; 162 | resultWithRemainderBit dsr(divideStep(r0, rsig)); 163 | 164 | prop integerEven(!lsbRoundActive || !dsr.remainderBit); // Note negation of guardBit 165 | 166 | 167 | // The same to get the guard flag 168 | prop guardRoundActive(exponentDifference > -sbv(edWidth,2)); // i.e. >= -1 169 | 170 | ubv rm1(ITE(lsbRoundActive, dsr.result, lsig)); 171 | resultWithRemainderBit dsrg(divideStep(rm1, rsig)); 172 | 173 | prop guardBit(guardRoundActive && dsrg.remainderBit); 174 | 175 | prop stickyBit(!ITE(guardRoundActive, 176 | dsrg.result, 177 | lsig).isAllZeros()); 178 | 179 | 180 | // The base result if lsbRoundActive 181 | unpackedFloat reconstruct(remainderSign, 182 | right.getExponent(), 183 | dsr.result.extract(lsig.getWidth() - 1,1)); // dsr shifts right as last action so is safe 184 | 185 | 186 | probabilityAnnotation(needPrevious, UNLIKELY); // Perhaps stretching it a bit but good for approximation 187 | unpackedFloat candidateResult(ITE(lsbRoundActive, 188 | reconstruct.normaliseUpDetectZero(format), 189 | left)); 190 | 191 | // The final subtract is a little different as previous ones were 192 | // guaranteed to be positive 193 | // TODO : This could be improved as these don't need special cases, etc. 194 | 195 | // From the rounding of the big integer multiple 196 | prop bonusSubtract(roundingDecision(roundingMode, 197 | remainderSign, 198 | integerEven, 199 | guardBit, 200 | stickyBit, 201 | prop(false))); 202 | probabilityAnnotation(bonusSubtract, UNLIKELY); // Again, more like 50/50 203 | 204 | // The big integer has sign left.getSign() ^ right.getSign() so we subtract something of left.getSign(). 205 | // For the integer part we handle this by working with absolutes (ignoring the sign) and 206 | // adding it back in at the end. 207 | // However for the correction for the rounded part we need to take it into account 208 | unpackedFloat signCorrectedRight(right, left.getSign()); 209 | unpackedFloat remainderResult(ITE(bonusSubtract, 210 | add(format, 211 | roundingMode, 212 | candidateResult, 213 | signCorrectedRight, 214 | false), 215 | candidateResult)); 216 | 217 | // TODO : fast path if first.isAllZeros() 218 | 219 | POSTCONDITION(remainderResult.valid(format)); 220 | 221 | return remainderResult; 222 | } 223 | 224 | 225 | // Put it all together... 226 | template 227 | unpackedFloat remainderWithRounding (const typename t::fpt &format, 228 | const typename t::rm &roundingMode, 229 | const unpackedFloat &left, 230 | const unpackedFloat &right) { 231 | //typedef typename t::bwt bwt; 232 | //typedef typename t::prop prop; 233 | //typedef typename t::ubv ubv; 234 | //typedef typename t::sbv sbv; 235 | 236 | PRECONDITION(left.valid(format)); 237 | PRECONDITION(right.valid(format)); 238 | 239 | unpackedFloat remainderResult(arithmeticRemainder(format, roundingMode, left, right)); 240 | 241 | //unpackedFloat result(addRemainderSpecialCases(format, left, right, roundedRemainderResult)); 242 | unpackedFloat result(addRemainderSpecialCases(format, left, right, remainderResult)); 243 | 244 | POSTCONDITION(result.valid(format)); 245 | 246 | return result; 247 | } 248 | 249 | // IEEE-754 remainder always uses round to nearest, ties to even 250 | template 251 | unpackedFloat remainder (const typename t::fpt &format, 252 | const unpackedFloat &left, 253 | const unpackedFloat &right) { 254 | 255 | return remainderWithRounding(format, t::RNE(), left, right); 256 | } 257 | 258 | 259 | } 260 | 261 | #endif 262 | 263 | -------------------------------------------------------------------------------- /core/sign.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** sign.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 21/08/14 24 | ** 25 | ** The sign manipulating operations. 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | 31 | #ifndef SYMFPU_SIGN 32 | #define SYMFPU_SIGN 33 | 34 | namespace symfpu { 35 | 36 | template 37 | unpackedFloat negate (const typename t::fpt &format, const unpackedFloat &uf) { 38 | 39 | PRECONDITION(uf.valid(format)); 40 | 41 | unpackedFloat result(uf, !uf.getSign()); 42 | 43 | POSTCONDITION(result.valid(format)); 44 | 45 | return result; 46 | } 47 | 48 | template 49 | unpackedFloat absolute (const typename t::fpt &format, const unpackedFloat &uf) { 50 | 51 | PRECONDITION(uf.valid(format)); 52 | 53 | unpackedFloat result(uf, typename t::prop(false)); 54 | 55 | POSTCONDITION(result.valid(format)); 56 | 57 | return result; 58 | } 59 | 60 | 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /core/sqrt.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** sqrt.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 05/02/16 24 | ** 25 | ** Square root of arbitrary precision floats 26 | ** 27 | */ 28 | 29 | #include "symfpu/core/unpackedFloat.h" 30 | #include "symfpu/core/ite.h" 31 | #include "symfpu/core/rounder.h" 32 | #include "symfpu/core/operations.h" 33 | 34 | #ifndef SYMFPU_SQRT 35 | #define SYMFPU_SQRT 36 | 37 | namespace symfpu { 38 | 39 | template 40 | unpackedFloat addSqrtSpecialCases (const typename t::fpt &format, 41 | const unpackedFloat &uf, 42 | const typename t::prop &sign, 43 | const unpackedFloat &sqrtResult) { 44 | typedef typename t::prop prop; 45 | 46 | prop generateNaN(uf.getSign() && !uf.getZero()); 47 | prop isNaN(uf.getNaN() || generateNaN); 48 | 49 | prop isInf(uf.getInf() && !uf.getSign()); 50 | 51 | prop isZero(uf.getZero()); 52 | 53 | return ITE(isNaN, 54 | unpackedFloat::makeNaN(format), 55 | ITE(isInf, 56 | unpackedFloat::makeInf(format, prop(false)), 57 | ITE(isZero, 58 | unpackedFloat::makeZero(format, sign), 59 | sqrtResult))); 60 | } 61 | 62 | 63 | template 64 | unpackedFloat arithmeticSqrt (const typename t::fpt &format, 65 | const unpackedFloat &uf) { 66 | typedef typename t::bwt bwt; 67 | typedef typename t::prop prop; 68 | typedef typename t::ubv ubv; 69 | typedef typename t::sbv sbv; 70 | typedef typename t::fpt fpt; 71 | 72 | PRECONDITION(uf.valid(format)); 73 | 74 | // Compute sign 75 | prop sqrtSign(uf.getSign()); 76 | 77 | // Divide the exponent by 2 78 | sbv exponent(uf.getExponent()); 79 | bwt exponentWidth(exponent.getWidth()); 80 | prop exponentEven((exponent & sbv::one(exponentWidth)).isAllZeros()); 81 | #if 0 82 | sbv exponentHalved(conditionalDecrement((exponent < sbv::zero(exponentWidth)) && !exponentEven, 83 | exponent.signExtendRightShift(sbv::one(exponentWidth)))); 84 | #endif 85 | sbv exponentHalved(exponent.signExtendRightShift(sbv::one(exponentWidth))); 86 | // Right shift rounds down for positive, and away for negative (-5 >>> 1 == -3) 87 | // sqrt(1.s * 2^{-(2n + 1)}) = sqrt(1.s * 2^{-2n - 2 + 1)}) 88 | // = sqrt(1.s * 2^{-2(n + 1)} * 2) 89 | // = sqrt(1.s * 2) * 2^{-(n + 1)} 90 | // Optimisation : improve the encoding of this operation 91 | 92 | // Sqrt the significands 93 | // extend to allow alignment, pad so result has a guard bit 94 | ubv alignedSignificand(conditionalLeftShiftOne(!exponentEven, uf.getSignificand().extend(1).append(ubv::zero(1)))); 95 | 96 | resultWithRemainderBit sqrtd(fixedPointSqrt(alignedSignificand)); 97 | 98 | 99 | bwt resWidth(sqrtd.result.getWidth()); 100 | ubv topBit(sqrtd.result.extract(resWidth - 1, resWidth - 1)); 101 | ubv guardBit(sqrtd.result.extract(0,0)); 102 | 103 | // Alignment of inputs means it is the range [1,4) so the result is in [1,2) 104 | // Also, the square root cannot be exactly between two numbers 105 | INVARIANT(topBit.isAllOnes()); 106 | INVARIANT(IMPLIES(guardBit.isAllOnes(), sqrtd.remainderBit)); 107 | // This also implies that no alignment of the exponent is needed 108 | 109 | ubv finishedSignificand(sqrtd.result.append(ubv(sqrtd.remainderBit))); 110 | 111 | unpackedFloat sqrtResult(sqrtSign, exponentHalved, finishedSignificand); 112 | 113 | 114 | fpt extendedFormat(format.exponentWidth(), format.significandWidth() + 2); 115 | // format.exponentWidth() - 1 should also be true but requires shrinking the exponent and 116 | // then increasing it in the rounder 117 | POSTCONDITION(sqrtResult.valid(extendedFormat)); 118 | 119 | return sqrtResult; 120 | } 121 | 122 | 123 | // Put it all together... 124 | template 125 | unpackedFloat sqrt (const typename t::fpt &format, 126 | const typename t::rm &roundingMode, 127 | const unpackedFloat &uf) { 128 | //typedef typename t::bwt bwt; 129 | typedef typename t::prop prop; 130 | //typedef typename t::ubv ubv; 131 | //typedef typename t::sbv sbv; 132 | 133 | PRECONDITION(uf.valid(format)); 134 | 135 | unpackedFloat sqrtResult(arithmeticSqrt(format, uf)); 136 | 137 | // Exponent is divided by two, thus it can't overflow, underflow or generate a subnormal number. 138 | // The last one is quite subtle but you can show that the largest number generatable 139 | // by arithmeticSqrt is 111...111:0:1 with the last two as the guard and sticky bits. 140 | // Round up (when the sign is positive) and round down (when the sign is negative -- 141 | // the result will be computed but then discarded) are the only cases when this can increment the significand. 142 | customRounderInfo cri(prop(true), prop(true), prop(false), prop(true), 143 | !((roundingMode == t::RTP() && !sqrtResult.getSign()) || 144 | (roundingMode == t::RTN() && sqrtResult.getSign()))); 145 | unpackedFloat roundedSqrtResult(customRounder(format, roundingMode, sqrtResult, cri)); 146 | 147 | unpackedFloat result(addSqrtSpecialCases(format, uf, roundedSqrtResult.getSign(), roundedSqrtResult)); 148 | 149 | POSTCONDITION(result.valid(format)); 150 | 151 | return result; 152 | } 153 | 154 | 155 | } 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /flags: -------------------------------------------------------------------------------- 1 | CXXFLAGS+=-std=gnu++11 -Wall -W -frounding-math -fsignaling-nans -ffp-contract=off -msse2 -mfpmath=sse -pedantic -mfma -mno-fma4 2 | -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags 2 | CXXFLAGS+=-I../../ 3 | ALL= 4 | .PHONY : all 5 | 6 | all : $(ALL) 7 | 8 | %.o : %.cpp 9 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 10 | 11 | -------------------------------------------------------------------------------- /utils/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** common.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 05/08/14 24 | ** 25 | ** Commonly used utility functions. 26 | ** 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #include "symfpu/utils/properties.h" 33 | 34 | #ifndef SYMFPU_COMMON 35 | #define SYMFPU_COMMON 36 | 37 | namespace symfpu { 38 | template 39 | T previousPowerOfTwo (T x) { 40 | assert(x > 1); 41 | //PRECONDITION(x > 1); 42 | 43 | T current = 1; 44 | T next = current << 1; 45 | 46 | while (next < x) { 47 | current = next; 48 | next <<= 1; 49 | } 50 | 51 | return current; 52 | } 53 | 54 | template 55 | T leftmostBit (T x) { 56 | assert(x > 1); 57 | //PRECONDITION(x > 1); 58 | 59 | T current = 1; 60 | T next = current << 1; 61 | 62 | while (next <= x) { 63 | current = next; 64 | next <<= 1; 65 | } 66 | 67 | return current; 68 | } 69 | 70 | 71 | // The number of bits required to represent a number 72 | // == the position of the leading 0 + 1 73 | // == ceil(log_2(value + 1)) 74 | template 75 | T bitsToRepresent (const T value) { 76 | T i = 0; 77 | //unsigned T working = *((unsigned T)&value); // Implementation defined for signed types 78 | T working = value; 79 | 80 | while (working != 0) { 81 | ++i; 82 | working >>= 1; 83 | } 84 | 85 | return i; 86 | } 87 | 88 | template 89 | T positionOfLeadingOne (const T value) { 90 | //PRECONDITION(value != 0); 91 | assert(value != 0); 92 | 93 | T i = 0; 94 | //unsigned T working = *((unsigned T)&value); // Implementation defined for signed types 95 | T working = value; 96 | 97 | while (working != 0) { 98 | ++i; 99 | working >>= 1; 100 | } 101 | 102 | return i - 1; 103 | } 104 | } 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /utils/numberOfRoundingModes.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** numberOfRoundingModes.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 20/05/15 24 | ** 25 | ** We need a better solution... 26 | ** 27 | */ 28 | 29 | #ifndef SYMFPU_NUMBEROFROUNDINGMODES 30 | #define SYMFPU_NUMBEROFROUNDINGMODES 31 | 32 | namespace symfpu { 33 | 34 | 35 | // Currently support 5 rounding modes 36 | // TODO : This shouldn't be a preprocessor constant 37 | 38 | #define SYMFPU_NUMBER_OF_ROUNDING_MODES 5 39 | 40 | } 41 | 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /utils/properties.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018 Martin Brain 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | ** properties.h 20 | ** 21 | ** Martin Brain 22 | ** martin.brain@cs.ox.ac.uk 23 | ** 07/08/14 24 | ** 25 | ** Macros for specifying invariants in a back-end specific way. 26 | ** 27 | ** Note that there are two kinds of assertions. 28 | ** - Implementation assertions : should be statically or dynamically 29 | ** resolvable to bools. Intended to catch cases where the code is 30 | ** buggy or being used incorrectly. 31 | ** - Algorithm assertions : should be trait::prop and are used 32 | ** to document and record properties and assumptions about the 33 | ** floating-point computation. Depending on the back-end these may 34 | ** be concrete or symbolic and thus handled in different ways. 35 | ** 36 | */ 37 | 38 | #ifndef SYMFPU_PROPERTIES 39 | #define SYMFPU_PROPERTIES 40 | 41 | #define IMPLIES(X,Y) (!(X) || (Y)) 42 | 43 | #ifndef PRECONDITION 44 | #define PRECONDITION(X) t::precondition(X) 45 | #endif 46 | 47 | #ifndef POSTCONDITION 48 | #define POSTCONDITION(X) t::postcondition(X) 49 | #endif 50 | 51 | #ifndef INVARIANT 52 | #define INVARIANT(X) t::invariant(X) 53 | #endif 54 | 55 | #endif 56 | 57 | 58 | 59 | --------------------------------------------------------------------------------