📄 arrays.hhf
字号:
#else // Verify the shapes of the two arrays. // The dest must have one less dimension than the // source (that was checked above) and except for // the dimension in src specified by _theDim_, each // src dimension must match the corresponding // dest dimension. // // Note: If either, or both, of the arrays are dynamic, // the check must be done at run-time. If both arrays // are static, then the check can be done at compile time. #if ( !array.isItDynamic( _theSrc_ ) & !array.isItDynamic( _theDest_ ) ) // Both arrays are static, do the check at compile-time. ?_dimSrc_ := @dim( _theSrc_ ); ?_dimDest_ := @dim( _theDest_ ); ?_dimIndex_ := 0; ?_NumIterations_ := 1; ?_goodShape_ := true; #while( _dimIndex_ < _arityDest_ ) #if( _dimSrc_[ _dimIndex_ ] <> _dimDest_[ _dimIndex_ ] ) #error( "reduce: illegal destination shape" ) ?_goodShape_ := false; #endif ?_NumIterations_ := _NumIterations_ * _dimSrc_[ _dimIndex_ ]; ?_dimIndex_ := _dimIndex_ + 1; #endwhile #elseif ( array.isItDynamic( _theSrc_ ) & !array.isItDynamic( _theDest_ ) ) // The source array is dynamic, must check the // dimensions at run-time. ?_dimDest_ := @dim( _theDest_ ); ?_goodShape_ := true; ?_NumIterations_ := 1; ?_dimIndex_ := 0; #if( _arityDest_ <> 0 ) #while( _dimIndex_ < _arityDest_ - 1 ) cmp ( _theSrc_.dopeVector[ _dimIndex_*4 ], _dimDest_[ _dimIndex_ ] ); jne _BadArity_; ?_NumIterations_ := _NumIterations_ * _dimDest_[ _dimIndex_ ]; ?_dimIndex_ := _dimIndex_ + 1; #endwhile cmp ( _theSrc_.dopeVector[ (_arityDest_ - 1)*4 ], _dimDest_[ _arityDest_ - 1 ] ); je _GoodArity_; _BadArity_: raise( ex.ArrayShapeViolation ); _GoodArity_: ?_NumIterations_ := _NumIterations_ * _dimDest_[ _arityDest_ - 1 ]; #endif #elseif ( !array.isItDynamic( _theSrc_ ) & array.isItDynamic( _theDest_ ) ) // The destination array is dynamic, must check the // dimensions at run-time. ?_dimSrc_ := @dim( _theSrc_ ); ?_goodShape_ := true; ?_NumIterations_ := 1; ?_dimIndex_ := 0; #if( _aritySrc_ - 1 <> 0 ) #while( _dimIndex_ < _aritySrc_ - 2 ) cmp ( _theDest_.dopeVector[ _dimIndex_*4 ], _dimSrc_[ _dimIndex_ ] ); jne _BadArity_; ?_dimIndex_ := _dimIndex_ + 1; ?_NumIterations_ := _NumIterations_ * _dimSrc_[ _dimIndex_ ]; #endwhile cmp ( _theDest_.dopeVector[ (_aritySrc_ - 2)*4 ], _dimSrc_[ _aritySrc_ - 2 ] ); je _GoodArity_; _BadArity_: raise( ex.ArrayShapeViolation ); _GoodArity_: ?_NumIterations_ := _NumIterations_ * _dimSrc_[ _aritySrc_ - 2 ]; #else #error( "Source array must have at least one dimension" ) ?_goodShape_ := false; #endif #else // Both arrays are dynamic, so we must check the // dimensions at run-time. push( eax ); mov( 1, eax ); mov( @elements( _theDest_.dopeVector ), ecx ); while( ecx > 0 ) do mov( _theSrc_.dopeVector[ ecx*4-4 ], esi ); cmp( esi, _theDest_.dopeVector[ ecx*4-4 ] ); je _GoodArity_; raise( ex.ArrayShapeViolation ); _GoodArity_: intmul( esi, eax ); dec( ecx ); endwhile; ?_goodShape_ := true; intmul( _ElementSize_, eax ); xchg( eax, [esp] ); #endif #endif #keyword beforeRow; #if( _goodShape_ & !_DidBeforeRow_ ) #if ( !array.isItDynamic( _theSrc_ ) | !array.isItDynamic( _theDest_ ) ) // Construct the for loop that will generate // the reduction. Note that at least one // of the arrays is a static array, so we // can use the _NumIterations_ constant. xor( esi, esi ); for ( xor( edi, edi ); edi < _NumIterations_ * _ElementSize_; add( _ElementSize_, edi) ) do #else // As above, but both arrays are dynamic. // The number of loop iterations can be // found on the top of the stack. xor( esi, esi ); for ( xor( edi, edi ); edi < [esp]; add( _ElementSize_, edi) ) do #endif #endif ?_DidBeforeRow_ := true; #keyword reduction:_srcDims_; #if( !_DidBeforeRow_ ) #error ( "'beforeRow' section must precede the 'reduction' section" ) ?_DidEachRow_ := true; // So we don't get two messages. #endif #if( _goodShape_ & !_DidReduce_ ) // Emit the for loop that indexes through the // array elements we are reducing: #if( !array.isItDynamic( _theSrc_ )) ?_srcDims_ := @dim( _theSrc_ ); for ( xor( ecx, ecx ); ecx < _srcDims_[ @elements( _srcDims_ ) - 1 ]; inc( ecx ) ) do #else push ( _theSrc_.dopeVector [ ( @elements( _theSrc_.dopeVector ) - 1 ) * 4 ] ); for ( xor( ecx, ecx ); ecx < [esp]; inc( ecx ) ) do #endif #endif ?_DidReduce_ := true; #keyword afterRow; #if( !_DidBeforeRow_ ) #error( "Missing 'beforeRow' and 'reduction' sections" ) ?_DidBeforeRow_ := true; #elseif( !_DidReduce_ ) #error( "Missing 'reduction' section" ) ?_DidReduce_ := true; #else // Bump up the index into the array by the size of // a single array element: add( _ElementSize_, esi ); // Endfor that matches the innermost loop: endfor; // If the source array is a dynamic array, remove // the ending loop index from the stack: #if( array.isItDynamic( _theSrc_ )) add( 4, esp ); #endif #endif ?_DidAfterRow_ := true; #terminator endreduce; #if( _goodShape_ ) #if( !_DidBeforeRow_ ) #error ( "Missing 'beforeRow', 'reduction', " "and 'afterRow' sections" ) #elseif( !_DidReduce_ ) #error( "Missing 'reduction' and 'afterRow' sections" ) #elseif( !_DidAfterRow_ ) #error( "Missing 'afterRow' section" ) #else // Emit the endfor for the enclosing loop. endfor; // If both arrays were dynamic, we need to remove // the ending loop index from the stack: #if ( array.isItDynamic( _theSrc_ ) & array.isItDynamic( _theDest_ ) ) add( 4, esp ); #endif #endif #endif pop( edi ); pop( esi ); pop( ecx ); #endmacro/*************************************************************************/ #macro mulbyConst( src1, dest ); #if( src1 = 1 ) mov( src2, dest ); #elseif( src1 = 2 ) shl( 1, dest ); #elseif( src1 = 4 ) shl( 2, dest ); #elseif( src1 = 8 ) shl( 3, dest ); #elseif( src1 = 16 ) shl( 4, dest ); #else intmul( src1, dest ); #endif #endmacro #macro transpose( _srcArray_, _destArray_, _xposDim_[] ): _xpos_, _offset_, _srcd_, _dstd_, _dSize_, _sSize_; // See if the third parameter is present. // If so, verify that it is an integer constant // falling in the range 0..arity( _srcArray_ ) - 1 #if( @Elements( _xposDim_ ) = 0 ) // If third parameter is not present, default the // transpose dimension to one. ?_xpos_ := 1; #elseif( @Elements( _xposDim_ ) = 1 ) // If we've got a third parameter, verify that // it is a constant. #if( !@IsConst( @text( _xposDim_[0] ))) #error ( "array.transpose:" nl "Expected a constant for the transpose dimension" ); #else // If the third parameter is a constant, verify that // it is a numeric constant. ?_xpos_ := @text( _xposDim_[0] ); #if( !hla.isNumber( _xpos_ )) #error ( "array.transpose:" nl "Transpose dimension parameter must be an integer" ) ?_xpos_ := 1; #endif #endif #else #error ( "array.transpose:" nl "Too many parameters" ); ?_xpos_ := 1; #endif // It is illegal to transpose dimension zero since that's // the other dimension we're working with. Also, negative // dimensions don't make sense, so check that here as well. #if( _xpos_ <= 0 ) #error ( "array.transpose:" nl "Transpose dimension must be one or greater" ); ?_xpos_ := 1; #endif // Handle the case where both arrays are dynamic: #if ( array.isItDynamic( _srcArray_ ) & array.isItDynamic( _destArray_ ) ) // Check the element sizes statically to ensure // they are reasonable and are the same size. ?_sSize_ := @Size( _srcArray_.elementType ); ?_dSize_ := @Size( _destArray_.elementType ); #if ( _sSize_ <> 1 & _sSize_ <> 2 & _sSize_ <> 4 & _sSize_ <> 8 & _sSize_ <> _dSize_ ) #error ( "array.transpose: " nl "Can only handle arrays with 1, 2, 4, or 8 byte elements" ); #else // We must check for proper array shapes at run-time // since we don't know the dest array dimensions // until then. push( eax ); if (#{ ?_i_ := 1; #while( _i_ < @Elements( _srcArray_.dopeVector )) #if( _i_ <> _xpos_ ) mov( _srcArray_.dopeVector[_i_*4], eax ); cmp ( eax, _destArray_.dopeVector[_i_*4] ); jne true; #endif ?_i_ := _i_ + 1; #endwhile mov( _srcArray_.dopeVector[0], eax ); cmp( eax, _destArray_.dopeVector[0] ); jne true; mov( _srcArray_.dopeVector[_xpos_*4], eax ); cmp( eax, _destArray_.dopeVector[_xpos_*4] ); je false; }#) then raise( ex.ArrayShapeViolation ); endif; // Optimize the most common case (transposing // a two-dim array or the last two dimensions // of an array). #if( _xpos_ = 1 ) push( ebx ); push( ecx ); push( edx ); push( esi ); push( edi ); // Note: assume that the src and dest array // sizes are the same. // // Begin by computing the size of the // matrix composed of the lower two dimensions. // The loop below uses this value. mov( _srcArray_.dopeVector[0], ecx ); intmul( _srcArray_.dopeVector[4], ecx ); #if( _sSize_ = 2 ) shl( 1, ecx ); #elseif( _sSize_ = 4 ) shl( 2, ecx ); #elseif( _sSize_ = 8 ) shl( 3, ecx ); #endif push( ecx ); // Save matrix size at [esp+4]. // Compute the size of the entire matrix and // the compute the address of the last element // of the source array so we can use this as // a loop termination value. ?_i_ := 2; #while( _i_ < @Elements( _srcArray_.dopeVector ) ) intmul( _srcArray_.dopeVector[_i_*4], ecx ); ?_i_ := _i_ + 1; #endwhile mov( _srcArray_.dataPtr, ebx ); add( ebx, ecx ); push( ecx ); // Save ptr to last src element at [esp]. // Compute the starting address of the first element // of the destination array, noting that will will // adjust the block size on the first iteration of // the loop, below. mov( _destArray_.dataPtr, ecx ); sub( [esp+4], ecx ); while( ebx < [esp] ) do add( [esp+4], ecx ); for ( mov(0, esi ); esi < _srcArray_.dopeVector[0]; inc( esi ) ) do for ( mov( 0, edi ); edi < _srcArray_.dopeVector[4]; inc( edi ) ) do #if( _sSize_ = 1 ) mov( edi, edx ); intmul( _destArray_.dopeVector[0], edx ); add( esi, edx ); mov( [ebx], al ); mov( al, [ecx+edx] ); inc( ebx ); #elseif( _sSize_ = 2 ) mov( edi, edx ); intmul( _destArray_.dopeVector[0], edx ); add( esi, edx ); mov( [ebx], ax ); mov( ax, [ecx+edx*2] ); add( 2, ebx ); #elseif( _sSize_ = 4 ) mov( edi, edx ); intmul( _destArray_.dopeVector[0], edx ); add( esi, edx ); mov( [ebx], eax ); mov( eax, [ecx+edx*4] ); add( 4, ebx ); #else mov( edi, edx ); intmul( _destArray_.dopeVector[0], edx ); add( esi, edx ); mov( [ebx], eax ); mov( eax, [ecx+edx*8] ); mov( [ebx+4], eax ); mov( eax, [ecx+edx*8+4] ); add( 8, ebx ); #endif endfor; endfor; endwhile; add( 8, esp ); pop( edi ); pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax ); // Okay, handle the case where we are not transposing // the last two dimensions of the array. This one is // ugly and less efficient (hence the special case // above). #else push( ebx ); push( esi ); push( edi ); // Make room for a set of loop control variables // on the stack: sub( @arity( _srcArray_ ) * 4, esp ); // Initialize array base pointers. mov( _destArray_.dataPtr, ebx ); mov( _srcArray_.dataPtr, esi ); // Emit the for loops that will do the // transposition. ?_i_ := @Elements( _srcArray_.dopeVector ); #while( _i_ > 0 ) ?_offset_ := ( _i_ - 1 ) * 4; mov(0, (type dword [esp+_offset_])); while({ mov( (type dword [esp+_offset_]), eax ); cmp( eax, _srcArray_.dopeVector[ _i_*4 - 4 ] ); jae false; }) do
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -