module utils use ISO_C_BINDING implicit none private public utils_init, ldmxcsr, stmxcsr, fstsw, fstcw, fldcw, & fclex, rdtsc, CPUID_type, cpuid integer(C_INT8_T) BAD_STUFF(224) data BAD_STUFF / & Z'31', Z'C0', Z'40', Z'75', Z'0A', Z'89', Z'4C', Z'24', & Z'08', Z'0F', Z'AE', Z'54', Z'24', Z'08', Z'C3', Z'0F', & Z'AE', Z'54', Z'24', Z'04', Z'C3', Z'90', Z'90', Z'90', & Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', & Z'31', Z'C0', Z'40', Z'75', Z'0A', Z'0F', Z'AE', Z'5C', & Z'24', Z'08', Z'8B', Z'44', Z'24', Z'08', Z'C3', Z'50', & Z'0F', Z'AE', Z'1C', Z'24', Z'58', Z'C3', Z'90', Z'90', & Z'31', Z'C0', Z'DF', Z'E0', Z'C3', Z'90', Z'90', Z'90', & Z'31', Z'C0', Z'40', Z'75', Z'0A', Z'D9', Z'7C', Z'24', & Z'08', Z'66', Z'8B', Z'44', Z'24', Z'08', Z'C3', Z'50', & Z'D9', Z'3C', Z'24', Z'58', Z'C3', Z'90', Z'90', Z'90', & Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', & Z'31', Z'C0', Z'40', Z'75', Z'0A', Z'66', Z'89', Z'4C', & Z'24', Z'08', Z'D9', Z'6C', Z'24', Z'08', Z'C3', Z'D9', & Z'6C', Z'24', Z'04', Z'C3', Z'90', Z'90', Z'90', Z'90', & Z'DB', Z'E2', Z'C3', Z'90', Z'90', Z'90', Z'90', Z'90', & Z'31', Z'C0', Z'40', Z'75', Z'0A', Z'0F', Z'31', Z'48', & Z'C1', Z'E2', Z'20', Z'48', Z'09', Z'D0', Z'C3', Z'0F', & Z'31', Z'C3', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', & Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', Z'90', & Z'31', Z'C0', Z'40', Z'75', Z'18', Z'53', Z'89', Z'D0', & Z'49', Z'87', Z'C8', Z'0F', Z'A2', Z'49', Z'90', Z'44', & Z'89', Z'00', Z'89', Z'58', Z'04', Z'89', Z'50', Z'08', & Z'89', Z'48', Z'0C', Z'5B', Z'C3', Z'53', Z'56', Z'8B', & Z'44', Z'24', Z'10', Z'8B', Z'4C', Z'24', Z'14', Z'0F', & Z'A2', Z'8B', Z'74', Z'24', Z'0C', Z'89', Z'06', Z'89', & Z'5E', Z'04', Z'89', Z'56', Z'08', Z'89', Z'4E', Z'0C', & Z'5E', Z'5B', Z'C3', Z'90', Z'90', Z'90', Z'90', Z'90' / type, bind(C) :: CPUID_type integer(C_INT32_T) eax integer(C_INT32_T) ebx integer(C_INT32_T) edx integer(C_INT32_T) ecx end type CPUID_type abstract interface subroutine ldmxcsr_template(source) bind(C) use ISO_C_BINDING implicit none integer(C_INT32_T), value :: source end subroutine ldmxcsr_template function stmxcsr_template() bind(C) use ISO_C_BINDING implicit none integer(C_INT32_T) :: stmxcsr_template end function stmxcsr_template function fstsw_template() bind(C) use ISO_C_BINDING implicit none integer(C_INT16_T) :: fstsw_template end function fstsw_template function fstcw_template() bind(C) use ISO_C_BINDING implicit none integer(C_INT16_T) :: fstcw_template end function fstcw_template subroutine fldcw_template(source) bind(C) use ISO_C_BINDING implicit none integer(C_INT16_T), value :: source end subroutine fldcw_template subroutine fclex_template() bind(C) use ISO_C_BINDING implicit none end subroutine fclex_template function rdtsc_template() bind(C) use ISO_C_BINDING implicit none integer(C_INT64_T) :: rdtsc_template end function rdtsc_template subroutine cpuid_template(result,eax,ecx) bind(C) use ISO_C_BINDING import CPUID_type implicit none type(CPUID_type) :: result integer(C_INT32_T), value :: eax integer(C_INT32_T), value :: ecx end subroutine cpuid_template end interface procedure(ldmxcsr_template), pointer :: ldmxcsr => NULL() procedure(stmxcsr_template), pointer :: stmxcsr => NULL() procedure(fstsw_template), pointer :: fstsw => NULL() procedure(fstcw_template), pointer :: fstcw => NULL() procedure(fldcw_template), pointer :: fldcw => NULL() procedure(fclex_template), pointer :: fclex => NULL() procedure(rdtsc_template), pointer :: rdtsc => NULL() procedure(cpuid_template), pointer :: cpuid => NULL() interface function VirtualAlloc(lpAddress, dwSize, flAllocationType, & flProtect) bind(C, name = 'VirtualAlloc') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: VirtualAlloc type(C_PTR) VirtualAlloc type(C_PTR), value :: lpAddress integer(C_SIZE_T), value :: dwSize integer(C_LONG), value :: flAllocationType integer(C_LONG), value :: flProtect end function VirtualAlloc function GetLastError() bind(C,name='GetLastError') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: GetLastError integer(C_LONG) GetLastError end function GetLastError end interface contains subroutine utils_init() type(C_PTR) address integer(C_INTPTR_T) temp integer(C_LONG) error integer(C_INT8_T), pointer :: temp_ptr(:) type(C_FUNPTR) fun_address logical :: first = .TRUE. if(.NOT.first) return first = .FALSE. address = VirtualAlloc(C_NULL_PTR, & size(BAD_STUFF,kind=C_SIZE_T),int(Z'1000',C_LONG), & int(Z'40',C_LONG)) if(.NOT.C_ASSOCIATED(address)) then error = GetLastError() write(*,'(a,z0,a)') "Error Z'",error,"' allocating memory" stop end if call C_F_POINTER(address, temp_ptr, shape(BAD_STUFF)) temp_ptr = BAD_STUFF temp = transfer(address, temp) fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, ldmxcsr) temp = temp+32 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, stmxcsr) temp = temp+24 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, fstsw) temp = temp+8 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, fstcw) temp = temp+32 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, fldcw) temp = temp+24 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, fclex) temp = temp+8 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, rdtsc) temp = temp+32 fun_address = transfer(temp, fun_address) call C_F_PROCPOINTER(fun_address, cpuid) end subroutine utils_init end module utils module nudge_FSW implicit none integer, parameter :: dp = kind(1.0d0) integer, parameter :: ep_preferred = selected_real_kind(18,4931) integer, parameter :: ep = & (1+sign(1,ep_preferred))/2*ep_preferred+ & (1-sign(1,ep_preferred))/2*dp private public ep, set_inexact contains subroutine set_inexact(x,y,z) real(ep) x, y, z x = y*z end subroutine set_inexact end module nudge_FSW program mxcsr_test use ISO_C_BINDING use utils use nudge_FSW implicit none integer(C_INT32_T) reg integer(C_INT64_T) ts1, ts2 integer(C_INT16_T) sw, cw integer(C_INT32_T) eax, ecx type(CPUID_type) result ! character(C_SIZEOF(result)) string ! character(C_SIZEOF(CPUID_type(0,0,0,0))) string character(16) string real(ep) alpha real(ep) :: beta = 4*atan(1.0_ep) real(ep) :: gamma = sqrt(2.0_ep) write(*,'(a,i0,a)') 'This is a ', & bit_size(1_C_INTPTR_T),'-bit processor' call utils_init ts1 = rdtsc() reg = stmxcsr() ts2 = rdtsc() write(*,'(a,i0)') 'Time read from TSC: ',ts2-ts1 write(*,'(a,z0.8)') 'Initial value of MXCSR: ',reg reg = ibclr(reg,9) write(*,'(a,z0.8)') 'Value to be stored in MXCSR: ',reg call ldmxcsr(reg) reg = stmxcsr() write(*,'(a,z0.8)') 'Value read from MXCSR: ',reg cw = fstcw() write(*,'(a,z0.4)') 'Initial value of FCW: ',cw cw = ibclr(cw, 2) write(*,'(a,z0.4)') 'Value to be stored in FCW: ',cw call fldcw(cw) cw = fstcw() write(*,'(a,z0.4)') 'Value read from FCW: ',cw sw = fstsw() write(*,'(a,z0.4)') 'Initial value of FSW: ',sw call set_inexact(alpha, beta, gamma) sw = fstsw() write(*,'(a,z0.4)') 'Value of FSW after inexact: ',sw call fclex sw = fstsw() write(*,'(a,z0.4)') 'Value of FSW after FCLEX: ',sw eax = 0 ecx = 0 call cpuid(result, eax, ecx) write(*,'(a,i0)') 'Max input value for basic CPUID: ', result%eax string = transfer(result,string) write(*,'(a,a)') 'Brand name: ',string(5:16) !write(*,*) len(string) write(*,'(4(z8.8:1x))') result ! Get ep parameters write(*,'(a,g14.6)') 'epsilon = ', epsilon(alpha) ! write(*,'(a,g14.6)') 'huge = ', huge(alpha) write(*,*) 'huge = ', huge(alpha) write(*,'(a,i0)') 'precision = ', precision(alpha) write(*,'(a,i0)') 'range = ', range(alpha) write(*,'(a,i0)') 'sizeof = ', sizeof(alpha) ! write(*,'(a,e15.6)') 'tiny = ', tiny(alpha) write(*,*) 'tiny = ', tiny(alpha) end program mxcsr_test