text: //llrem.cpp
  
  // Copyright Querysoft Limited 2013
  //
  // Permission is hereby granted, free of charge, to any person or organization
  // obtaining a copy of the software and accompanying documentation covered by
  // this license (the "Software") to use, reproduce, display, distribute,
  // execute, and transmit the Software, and to prepare derivative works of the
  // Software, and to permit third-parties to whom the Software is furnished to
  // do so, all subject to the following:
  // 
  // The copyright notices in the Software and this entire statement, including
  // the above license grant, this restriction and the following disclaimer,
  // must be included in all copies of the Software, in whole or in part, and
  // all derivative works of the Software, unless such copies or derivative
  // works are solely in the form of machine-executable object code generated by
  // a source language processor.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  // DEALINGS IN THE SOFTWARE.
  
  #include "CompilerQOR.h"
  #include "CodeQOR/Macros/CodingMacros.h"
  #include "ArchQOR/Common/Machine.h"
  #include "ArchQOR/Common/HLAssembler/JITFunctor.h"
  
  //To generate assembler function for llrem
  
  //------------------------------------------------------------------------------
  class CJITallrem : public nsArch::CJITFunctor0< int >
  {
  public:
  
  	//------------------------------------------------------------------------------
  	CJITallrem( nsArch::CHighLevelAssemblerBase* pHLA, byte* pLaunchPad = 0 ) : CJITFunctor0( pHLA, pLaunchPad )
  	{
  		if( m_pLaunchPad != 0 )
  		{
  			Generate();
  		}
  	}
  
  protected:
  
  	//------------------------------------------------------------------------------
  	virtual FP Generate()
  	{
  		nsArch::nsx86::Cx86HLAIntrinsics& HLA( *( dynamic_cast< nsArch::nsx86::Cx86HLAIntrinsics* >( m_pHLA ) ) );
  		nsArch::nsx86::CCPU& CPU = dynamic_cast< nsArch::nsx86::CCPU& >( TheMachine()->Logic().CPU() );
  
  		//static const Cmp_unsigned__int32 PAGESIZE = 4096;
  
  		CPU.clear();
  
  		nsArch::nsx86::CLabel L1( CPU.newLabel() );
  		nsArch::nsx86::CLabel L2( CPU.newLabel() );
  		nsArch::nsx86::CLabel L3( CPU.newLabel() );
  		nsArch::nsx86::CLabel L4( CPU.newLabel() );
  		nsArch::nsx86::CLabel L5( CPU.newLabel() );
  		nsArch::nsx86::CLabel L6( CPU.newLabel() );
  		nsArch::nsx86::CLabel L7( CPU.newLabel() );
  		nsArch::nsx86::CLabel L8( CPU.newLabel() );
  		
  		//CPU.int3();
  
  		CPU.push( CPU.reg_ebx() );
  		CPU.push( CPU.reg_edi() );
  
  		CPU.xor_( CPU.reg_edi(), CPU.reg_edi() );									//result sign assumed positive
  		CPU.mov( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 16 ) );			//Hi Word of dividend
  		CPU.or_( CPU.reg_eax(), CPU.reg_eax() );									//test to see if signed
  		CPU.jge( L1 );																//skip rest if a is already positive
  
  		CPU.inc( CPU.reg_edi() );													//complement result sign flag bit
  		CPU.mov( CPU.reg_edx(), nsArch::nsx86::CMem( CPU.reg_esp(), 12 ) );			//Lo Word of dividend
  		CPU.neg( CPU.reg_eax() );													//make a positive
  		CPU.neg( CPU.reg_edx() );
  		CPU.sbb( CPU.reg_eax(), 0 );
  		CPU.mov( nsArch::nsx86::CMem( CPU.reg_esp(), 16 ), CPU.reg_eax() );			//save positive value
  		CPU.mov( nsArch::nsx86::CMem( CPU.reg_esp(), 12 ), CPU.reg_edx() );
  
  	CPU.bind( L1 );
  
  		CPU.mov( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 24 ) );			//hi word of b
  		CPU.or_( CPU.reg_eax(), CPU.reg_eax() );									//test to see if signed
  		CPU.jge( L2 );																//skip rest if b is already positive
  		CPU.mov( CPU.reg_edx(), nsArch::nsx86::CMem( CPU.reg_esp(), 20 ) );			//lo word of b
  		CPU.neg( CPU.reg_eax() );													//make b positive
  		CPU.neg( CPU.reg_edx() );
  		CPU.sbb( CPU.reg_eax(), 0 );
  		CPU.mov( nsArch::nsx86::CMem( CPU.reg_esp(), 24 ), CPU.reg_eax() );
  		CPU.mov( nsArch::nsx86::CMem( CPU.reg_esp(), 20 ), CPU.reg_edx() );			//save positive value
  
  	CPU.bind( L2 );
  
  		CPU.or_( CPU.reg_eax(), CPU.reg_eax() );									//check to see if divisor < 4194304K
  		CPU.jnz( L3 );																//nope, gotta do this the hard way
  
  		CPU.mov( CPU.reg_ecx(), nsArch::nsx86::CMem( CPU.reg_esp(), 20 ) );			//load divisor
  		CPU.mov( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 16 ) );			//load high word of dividend
  
  		CPU.xor_( CPU.reg_edx(), CPU.reg_edx() );
  		CPU.div( CPU.reg_ecx() );													//edx <- remainder
  
  		CPU.mov( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 12 ) );			//edx:eax <- remainder:lo word of dividend
  		CPU.div( CPU.reg_ecx() );													//edx <- final remainder
  		CPU.mov( CPU.reg_eax(), CPU.reg_edx() );									//edx:eax <- remainder
  		CPU.xor_( CPU.reg_edx(), CPU.reg_edx() );									
  		CPU.dec( CPU.reg_edi() );													//check result sign flag
  		CPU.jns( L4 );																//negate result, restore stack and return
  		CPU.jmp( L8 );																//result sign ok, restore stack and return
  
  	CPU.bind( L3 );
  
  		CPU.mov( CPU.reg_ebx(), CPU.reg_eax() );									//ebx:ecx <- divisor
  		CPU.mov( CPU.reg_ecx(), nsArch::nsx86::CMem( CPU.reg_esp(), 20 ) );			//load low word of divisor
  		CPU.mov( CPU.reg_edx(), nsArch::nsx86::CMem( CPU.reg_esp(), 16 ) );			//load high word of dividend
  		CPU.mov( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 12 ) );			//load low word of dividend
  
  	CPU.bind( L5 );
  
  		CPU.shr( CPU.reg_ebx(), 1 );												//shift divisor right one bit
  		CPU.rcr( CPU.reg_ecx(), 1 );
  		CPU.shr( CPU.reg_edx(), 1 );												//shift dividend right one bit
  		CPU.rcr( CPU.reg_eax(), 1 );
  		CPU.or_( CPU.reg_ebx(), CPU.reg_ebx() );
  		CPU.jnz( L5 );																//loop until divisor < 4194304K
  
  		CPU.div( CPU.reg_ecx() );													//now divide, ignore remainder
  
  		CPU.mov( CPU.reg_ecx(), CPU.reg_eax() );									//save a copy of quotient in ECX
  
  		CPU.mul( nsArch::nsx86::dword_ptr( CPU.reg_esp(), 24 ) );
  		CPU.xchg( CPU.reg_ecx(), CPU.reg_eax() );									//save product, get quotient in EAX
  		CPU.mul( nsArch::nsx86::dword_ptr( CPU.reg_esp(), 20 ) );
  		CPU.add( CPU.reg_edx(), CPU.reg_ecx() );									//EDX:EAX = QUOT * DVSR
  		CPU.jc( L6 );																//carry means Quotient is off by 1
  
  		CPU.cmp( CPU.reg_edx(), nsArch::nsx86::CMem( CPU.reg_esp(), 16 ) );			//compare hi words of result and original
  		CPU.ja( L6 );																//if result > original, do subtract
  		CPU.jb( L7 );																//if result < original, we are ok
  		CPU.cmp( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 12 ) );			// hi words are equal, compare lo words
  		CPU.jbe( L7 );																//if less or equal we are ok, else subtract
  
  	CPU.bind( L6 );
  
  		CPU.sub( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 20 ) );			//subtract divisor from result
  		CPU.sbb( CPU.reg_edx(), nsArch::nsx86::CMem( CPU.reg_esp(), 24 ) );
  
  	CPU.bind( L7 );
  
  		CPU.sub( CPU.reg_eax(), nsArch::nsx86::CMem( CPU.reg_esp(), 12 ) );			//subtract dividend from result
  		CPU.sbb( CPU.reg_edx(), nsArch::nsx86::CMem( CPU.reg_esp(), 16 ) );
  
  		CPU.dec( CPU.reg_edi() );													//check result sign flag
  		CPU.jns( L8 );																//result is ok, restore stack and return
  
  	CPU.bind( L4 );
  
  		CPU.neg( CPU.reg_edx() );													//otherwise, negate the result
  		CPU.neg( CPU.reg_eax() );
  		CPU.sbb( CPU.reg_edx(), 0 );
  
  	CPU.bind( L8 );
  
  		CPU.pop( CPU.reg_edi() );
  		CPU.pop( CPU.reg_ebx() );
  
  		CPU.ret( nsArch::nsx86::CImm( 16 ) );
  
  		// Make JIT function.
  		FP fn = reinterpret_cast< FP >( CPU.make() );
  
  		// Ensure that everything is ok and write the launchpad
  		if( fn )
  		{
  			m_bGenerated = true;
  			if( m_pLaunchPad )
  			{
  				HLA.WriteLaunchPad( (byte*)fn, m_pLaunchPad );
  			}
  		}
  
  		return fn;
  	}
  
  };
  
  __QCMP_STARTLINKAGE_C
  
  #pragma section( ".jit", execute )
  
  __declspec( allocate( ".jit" ) ) byte _allrem[ 16 ];
  
  #pragma comment( linker, "/SECTION:.jit,ERW" )
  
  __QCMP_ENDLINKAGE_C
  
  CJITallrem allremJIT( &TheMachine()->HLAssembler(), _allrem );
  