Skip to content

Instantly share code, notes, and snippets.

@jakubtomsu
Created June 24, 2025 15:40
Show Gist options
  • Select an option

  • Save jakubtomsu/361f9319f73ed0ae9c0e36df887226b9 to your computer and use it in GitHub Desktop.

Select an option

Save jakubtomsu/361f9319f73ed0ae9c0e36df887226b9 to your computer and use it in GitHub Desktop.
package fp_exceptions
import "core:log"
when ODIN_OS == .Windows {
foreign import libcmt "system:libcmt.lib"
}
@(default_calling_convention = "system")
foreign libcmt {
_controlfp_s :: proc(currentControl: ^u32, newControl: u32,mask: u32) -> i32 ---
}
// Set parameters of exceptions you want to enable to true
fp_exceptions_set :: proc(
invalid := false,
zero_div := false,
) {
cw: u32
_controlfp_s(&cw, 0, 0)
// Note: setting the bit to 0 enables the exception
if invalid {
cw &= ~u32(_EM_INVALID)
} else {
cw |= u32(_EM_INVALID)
}
if zero_div {
cw &= ~u32(_EM_ZERODIVIDE)
} else {
cw |= u32(_EM_ZERODIVIDE)
}
_controlfp_s(nil, cw, _MCW_EM)
}
fp_exceptions_log :: proc() {
cw: u32
_controlfp_s(&cw, 0, 0)
if 0 == cw & _EM_INEXACT do log.info("FP except: EM_INEXACT: inexact (precision)")
if 0 == cw & _EM_UNDERFLOW do log.info("FP except: EM_UNDERFLOW: underflow")
if 0 == cw & _EM_OVERFLOW do log.info("FP except: EM_OVERFLOW: overflow")
if 0 == cw & _EM_ZERODIVIDE do log.info("FP except: EM_ZERODIVIDE: zero divide")
if 0 == cw & _EM_INVALID do log.info("FP except: EM_INVALID: invalid")
if 0 != cw & _RC_NEAR do log.info("FP except: RC_NEAR: near")
if 0 != cw & _RC_DOWN do log.info("FP except: RC_DOWN: down")
if 0 != cw & _RC_UP do log.info("FP except: RC_UP: up")
if 0 != cw & _RC_CHOP do log.info("FP except: RC_CHOP: chop")
if 0 != cw & _IC_AFFINE do log.info("FP except: IC_AFFINE: affine")
if 0 != cw & _IC_PROJECTIVE do log.info("FP except: IC_PROJECTIVE: projective")
if 0 != cw & _DN_SAVE do log.info("FP except: DN_SAVE: save denormal results and operands")
if 0 != cw & _DN_FLUSH do log.info("FP except: DN_FLUSH: flush denormal results and operands to zero")
}
// New Control Bit that specifies the ambiguity in control word.
_EM_AMBIGUIOUS :: 0x80000000 // For backwards compatibility
_EM_AMBIGUOUS :: 0x80000000
// Abstract User Control Word Mask and bit definitions
_MCW_EM :: 0x0008001f // Interrupt Exception Masks
_EM_INEXACT :: 0x00000001 // inexact (precision)
_EM_UNDERFLOW :: 0x00000002 // underflow
_EM_OVERFLOW :: 0x00000004 // overflow
_EM_ZERODIVIDE :: 0x00000008 // zero divide
_EM_INVALID :: 0x00000010 // invalid
_EM_DENORMAL :: 0x00080000 // Denormal exception mask (_control87 only)
_MCW_RC :: 0x00000300 // Rounding Control
_RC_NEAR :: 0x00000000 // near
_RC_DOWN :: 0x00000100 // down
_RC_UP :: 0x00000200 // up
_RC_CHOP :: 0x00000300 // chop
// i386 specific definitions
_MCW_PC :: 0x00030000 // Precision Control
_PC_64 :: 0x00000000 // 64 bits
_PC_53 :: 0x00010000 // 53 bits
_PC_24 :: 0x00020000 // 24 bits
_MCW_IC :: 0x00040000 // Infinity Control
_IC_AFFINE :: 0x00040000 // affine
_IC_PROJECTIVE :: 0x00000000 // projective
// RISC specific definitions
_MCW_DN :: 0x03000000 // Denormal Control
_DN_SAVE :: 0x00000000 // save denormal results and operands
_DN_FLUSH :: 0x01000000 // flush denormal results and operands to zero
_DN_FLUSH_OPERANDS_SAVE_RESULTS :: 0x02000000 // flush operands to zero and save results
_DN_SAVE_OPERANDS_FLUSH_RESULTS :: 0x03000000 // save operands and flush results to zero
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment